前端工程化学习笔记
前端工程化学习笔记
拉勾教育《前端工程化精讲》课程
开发效率
- 脚手架(Scaffold)工具
- 快速生成
- 基础代码和目录
- package.json, *.lock 文件
- 项目技术栈
- webpack 配置文件
- 检查工具、单元测试工具
- 最佳实践
- 自定义模板
- 快速生成
- 云开发
- 无代码工具
脚手架工具
- Yeoman 通用的,用于一些开发流程里特定片段代码的生成
- Create-React-App(CRA)
- react-rewired
- customize-cra
- react-scripts 开发流程集成工具
- Vue CLI 有交互定制化选项
- @vue/cli 全局命令
- @vue/cli-service 项目内集成工具
- @vue/cli-plugin- 功能插件系统
webpack
- loaders
- bable-loader
- plugins
- optimize
- TerserPlugin 压缩 js
- splitChunks 自动分包
- resolve
- PnpWebpackPlugin 加速使用 Yarn 模块安装和解析
定制化脚手架模板
- 团队内部定制,统一风格,减少重复事务
- Yeoman 生成器(Generator)
- writing()
- copyTpl()
- install()
- writing()
- CRA 自定义模板
- README.md
- package.json
- template.json
- template 目录
- public/index.html
- src/index.js
- Vue CLI
- meta.js/json
vue init [template-name] [app-name]
浏览器的热更新
- webpack-dev-server
类似的技术:
- Auto Compile 自动编译
- Live Reload 自动刷新
- HMR(Hot Module Replacement) 模块热替换
webpack 配置
- watch 自动编译:
npm run build:watch
- reload 自动刷新:
npm run dev:reload
, /sockjs-node websocket 连接,刷新后一些操作或数据会消失。 - hmr 模块热替换:
npm run dev:hmr
,hot:true
,新增style-loader
和css-loader
webpack 术语
- module 代码模块
- chunk 包含多个 module
- chunk group 通过配置入口点(entry point)区分的块组
- bundling
- asset/bundle
构建效率
打包提效
- 提升当前环节任务的工作效率
- 提升优化效果,减少传递给下一环节任务的数据量,从而提升后续环节的工作效率
面向 js 的压缩工具
- Terser整体上比UglifyJS好些
- Webpack 4 中内置了 TerserWebpackPlugin
面向 css 的压缩工具
- CSSMinimizerWebpackPlugin 支持缓存和多进程
- 三个插件都默认基于 cssnano
- 设置为
chunks:'all'
可以将所有信赖都进行分包处理,从而减少了重复引入相同模块代码的情况。
Tree Shaking
- 使用 ES6 类型的模块才能进行 Tree Shaking, commonjs 不支持。
- 以 default 方式引入的模块,无法被 Tree Shaking,这也是为什么说不要用
export default
的原因之一。 - 只有 sideEffects 为 false 的信赖包(或不在 sideEffects 对应数组中的文件),才可以被 Tree Shaking
- 如 lodash 替换为
lodash-es
,就可以 Tree Shaking,因为lodash-es
的 package.json 中描述:sideEffects: false
- 如 lodash 替换为
- 在 Babel 7 之前 modules 默认为
commonjs
,不能被 Tree Shaking,而在 Babel 7以后,@babel/preset-env
中默认为auto
,则可以使 ES6 的模块被 Tree Shaking
缓存优化
- Webpack4 内置压缩插件 TerserWebpackPlugin,默认开启了缓存参数。
- Babel-loader
- cacheDirectory: 默认为 false,改为 true 则默认目录,改为目录时,则为指定目录。
- cacheIdentifier: 计算缓存标识符,决定缓存是否被命中。
- cacheCompression: 默认为 true
- Cache-loader 存储的 Buffer 形式的数据处理效率更高
- 尽可能将不变的处理成本高的模块打入单独 Chunk,以便利用缓存。
- 使用 splitChunks 优化缓存利用率
- 注意在 CI/CD 中,要将缓存设置到公共缓存目录下保留,以免清除了缓存,反而低效。
增量构建:只编译打包所改动的文件
- 增量构建效果:watch 配置为 true,且 cache 配置为 true 就可以实现增量效果。
- Webpack 4 中, 一般情况下 cache 默认为 false,而在开发模式开启 watch配置时, cache 默认为 true
- 基于内存的缓存数据无法运用到生产环境中。
- Webpack 5 中支持基于文件系统的持久化缓存。
Webpack5 的优化细节
- Persistent Caching 持久化缓存
cache: {
type: 'filesystem',
cacheDirectory: '...',
name: '...', // name 可以保留之前的多套缓存,切换时缓存失效,恢复时则再次使用之前的缓存。
cacheLocation: path.resolve(), //覆盖 cacheDirectory 和 name
buildDependencies: {defaultWebpack: []}, // 当信赖项变化时,构建缓存失效。
version: process.env.NODE_ENV, // 不同环境切换时,缓存失效。
}
- Webpack 5 会忽略插件的缓存设置,由引擎自身提供构建各环节的缓存读写逻辑。
- Tree Shaking
- 增加了对嵌套模块的导出跟踪功能,能够找到内层未使用的模块属性。
- optimization.innerGraph 生产环境默认开启。
- 支持了一些 CommonJS 风格模块代码的静态分析功能。
- Logs 增加了许多内部处理过程日志
- stats: {logging: “verbose”}
Webpack 5 稳定版本,于 2020年10月10日发布。
无包构建(不打包的构建)
- 在构建时只需处理模块的编译而无须打包,把模块间的依赖关系完全交给浏览器来处理。
- 这种通过浏览器原生的模块进行解析的方式称: Native-ESM (Native ES Module)
- 支持 ES Module 的现代浏览器,会忽略 type=“nomodule” 属性的 script,这通常用于旧浏览器的降级方案。
- 带有
type="module"
属性的 script 在浏览器中通过 defer 的方式异步执行(异步下载,不阻塞 HTML,顺次执行) - 带有
type="module"
属性且带有async
属性的 script,在浏览器中通过 async 的方式异步执行,按下载完成顺序执行。 - 即使多次加载相同模块,也只会执行一次。
- 模块内信赖的引用,只能使用 import … from ‘…’ ES6风格模块导入。
- 模块内信赖的引用,只支持相对路径和 URL 方式,不支持直接包名开头的方式。
- 模块内信赖的引用,只支持MIME Type 为
text/javascript
方式的模块,不支持其他如 CSS 类型文件的加载。
无包构建的优点:
- 构建速度快,尤其是初次构建速度快很多。
- 按需编译,根据入口模块分析加载所需模块,编译过程按需处理。
- 增量构建速度快
无包构建的缺点:
- 浏览器网络请求数量剧增,对于稳定性和访问性能要求高的生产环境较难接受。 支持 HTTP/2 的服务器会好些。
- 浏览器的兼容性,对于需要兼容旧浏览器的项目生产环境下不能使用。
Vite
- 在开发环境下基于 Native-ESM 处理构建过程,只编译不打包
- 在生产环境下则基于 Rollup 打包。
- 支持在 React 和 Preact 项目中使用。
- 支持热更新(HMR)功能。
- 支持自定义配置文件:config.ts
- 支持使用 HTTPS 和 HTTP/2
- 支持配置代理服务,将部分请求代理到第三方服务。
- 支持模式 mode 和环境变量
.env.production.local
等 - 仅面向 ES6 的现代浏览器,最低支持 ES2015
- 仅限于 Vue3 以上版本,不兼容更低版本的 Vue。
- 内置了对 Vue 的大量构建优化,有更好的开发体验。
Snowpack
- 基本与 Vite 类似,主要差异:在生产环境下默认使用无包构建而非打包模式。
- 提供较完善的插件体系,支持用户和社区发布自定义插件,而 Vite 未提供自定义插件的相关文档。
- 如需打包功能,则可引入打包插件: @snowpack/plugin-webpack 和 @snowpack/pluin-parcel,暂未提供 Rollup 对应的插件。
部署效率
一般部署流程
- 获取代码
- 安装信赖
- 源码构建
- 产物打包
- 推送代码
- 重启服务
本地部署的问题
- 环境一致性问题:使用远程统一的部署系统,可以避免不同开发人员的本地环境差异性。同时,部署系统的工作环境也可以与线上服务环境保持一致,从而降低环境不一致的风险。
- 过程一致性问题:通过部署系统将完整处理过程写入代码,减少本地人工操作的风险,同时,系统可以记录每次部署操作的细节日志,方便跟踪问题。
- 可回溯性问题:日志可帮助定位问题,构建产物包也会被分别保存,方便问题排查和快速回滚发布。
- 人员分工问题:个别开发者会需要中断当前工作,无法快速响应多人的发布请求,如果多人都有权限发布,又会混乱。
流行的代码部署工具
Jenkins
- 完全免费的开源产品
- 有丰富的插件系统
- 有 API 调用功能
CircleCI
- 云端服务,免费仅一个 Job 及环境限制等。
- 收费版本支持更多构建数、环境,企业内部使用本地化搭建也是收费的。
Github Actions (GHA)
- 对公开仓库、自运维执行器的情况下免费。
- 对私有仓库超过额度的免费执行时间和存储空间后收费。
Gitlab CI
- 社区版本免费,商业版本收费
- 使用
.gitlab-ci.yml
配置 CI/CD 流程 - 需要单独安装执行器:
gitlab-runner
信赖安装效率优化
- npm
- Yarn
- Yarn with PnP
- Yarn v2
- pnpm
获取执行时间:
time npm i
time yarn
time pnpm i
总体执行时间: npm < pnpm < Yarn v1 PnP < Yarn v1 < Yarn v2
Lock 文件主要优化的是信赖解析阶段的时间。
优化思路
- 提升信赖下载速度
- 注册国内下载源
yarn/npm config set registry xxxx
- 二进制下载源,解决 node-sass, puppeteer 等的下载问题
- 注册国内下载源
npm config set sass-binary-site https://npm.taobao.org/mirrors/node-sass
npm config set puppeteer_download_host https://npm.taobao.org/mirrors
- 多项目共用信赖缓存
- 让使用相同信赖工具的项目共用相同服务器
- 让技术栈相同的项目共用相同的服务器
- 在 CI 系统中对项目的持久化缓存数据做单独的备份与还原。
- 打包阶段提升压缩效率的工具:
- Pigz 2xGzip ~ 4xGzip, 与 Gzip 兼容。
- Zstd 15xGzip ~ 16xGzip, 与 Gzip 不兼容。
- 原因主要是并行处理,CPU和内存的占用会比较高。
容器化方案
- node:14 镜像,包含 node14 和 Yarn 的 Linux 系统环境。
镜像阶段
- 构建镜像的具体内容写在 Dockerfile 文件中
FROM node:12-slim
RUN apt-get update
RUN apt-get install -y git
RUN apt-get install -y build-essential
RUN apt-get install -y curl
- 在 Dockerfile 所在目录执行构建命令:
docker build --network host --tag foo:bar .
容器阶段
- 基于项目的工作镜像创建执行部署过程的容器
- 操作容器执行相应的各部署环节:获取代码、安装信赖、执行构建、产物打包、推送产物等。
# 创建容器
docker run -dit --name container_1 foo:bar bash
# 容器内执行命令
docker exec -it container_1 xxxx
挑战及建议
- 缓存问题
- 信赖缓存:生成容器时挂载宿主环境信赖缓存目录,安装目录缓存。
- 构建缓存:在宿主环境中创建构建缓存目录并挂载到容器中,并在项目构建配置中将缓存目录设置为该目录。
- 性能问题
- 容器资源限制:在创建容器时,可以通过参数来限制容器使用的 CPU 核心数和内存大小。
- copy-to-write:在使用容器化部署时,需要尽量避免将可变数据写入镜像中。
搭建高效部署系统
-
产物部署分两种模式:
- Push 模式:通过 scp 等方式推送到目标服务器,并执行解压、重启等发布流程。
- Pull 模式:提供下载接口,由下游发布环节调用下载获取,然后执行解压、重启等发布流程。
-
部署服务器环境准备:全局信赖工具、系统配置文件、环境变量、目录规划、监控及清理策略。
-
Webhook:在部署系统中新增接收 Webhook 消息的路由,将此 Webhook 接口地址写入 CVS 系统的 Webhook 列表中,并配置相应参数,如:只监听特定分支或只监听 Tag Push 等。
-
任务队列:需限制同时执行任务数(Concurrency)避免过多任务同时执行,耗尽计算资源。
-
构建任务与插件系统
-
任务命令与子进程
-
状态、事件与 Socket
目前个人理解,使用类似 Gitlab CI 的功能,可以不用深入这么多细节,只需配置好
.gitlab-ci.yml
即可。