Better

Ethan的博客,欢迎访问交流

Angular 开启热更新和打包优化探索

前段时间寻思着开启 Angular 的热更新,同时公司项目打包耗时太长,于是就研究了 webpack 打包优化,不仅过程不是很顺利,而且结果也不是很美好,但还是小小的记录下吧。

开启热更新

Angular 默认未开启模块热更新,需要手动开启,大致有如下步骤

  • script 脚本添加 --hmr 参数
  • 安装 @angularclass/hmr 包
  • 环境配置添加 hmr 参数,后续代码中需要用到
  • 添加 hmr.ts 文件,具体内容直接 copy 官网即可
  • main.ts 中添加 hmr 相关代码
  • tsconfig.app.json 添加 "types": ["node"],避免编译报错
  • angular.json 下 server.options 添加 "hmrWarning": false,去掉启动 warning

打包原则和常见方式

常见优化原则

  • 缓存(cache)
  • 并行化(多线程)
  • 较少任务量(限定范围)

常见优化手段

  • 分开 vendor 和 app:DllPlugin & DllReferencePlugin
  • uglifyJsPlugin 非常耗时,开启并行配置
    • parallel
    • cache
  • HappyPack
    • 串行转并行
  • babel-loader 非常耗时
    • cacheDirectory 开启缓存
    • include & exclude

NG 内置命令打包

已有的打包情况

  • ng build:没有 hash 值,有 source map
    • vendor.js: @angular、three、rxjs、svg.js、svg.draw.js
    • polyfills.js es2015-polyfill.js runtime.js
    • style.js:处理样式
    • main.js 业务代码
  • ng build --aot:提前编译,没有 hash 值,有 source map
    • 代码相对不使用预先编译,体积要小一点,因为可以去除 JIT 编译相关的代码
    • 具体代码结构和不适用 aot 是差不多的
  • ng build --prod:有 hash 值,有 source map,默认开启 aot
    • 相比上两者时间构建时间变长了,主要是因为进行了代码压缩,体积小了很多,文件输出稍微有点变化
    • polyfills.js es2015-polyfill.js runtime.js 三个还是有
    • 少了 style.js,多了 styles.css
    • 少了 vendor.js,main.js 包含了之前的 vendor + main
  • ng build --prod --vendor-chunk
    • 熟悉的感觉 vendor.js 又回来了,出于业务代码与依赖分离的角度,同时高效利用客户端缓存,--vendor-chunk 参数的添加还是很有必要的
    • 不重复编译 vendor 是我考虑优化的主要方向

Angular-处理自带参数功能

  • --build-optimizer: 更小的 bundle,但更长的构建时间
  • --vendoor-chunk:将所有第三方库代码提取到单独的块中,也有利于持久化缓存

NG 限制

NG 7.x 之后并不支持弹出 webpack 配置,经查阅,如下方式可选

  • 放弃 CLI,自己书写构建脚本
  • 使用 ngx-build-plus 扩展 webpack 配置

放弃 CLI 似乎有点大胆,于是尝试使用 ngx-build-plus 方式,优化思路

  • ngx-build-plus 模块,使用 webpack-merge 合并配置
  • 开启:happypack、parallel、DllPlugin、DllReferencePlugin

修改 angular.json

"builder": "@angular-devkit/build-angular:browser", => 
"builder": "ngx-build-plus:build"

修改 package.json 指定额外的配置:--extra-webpack-config ./webpack.config.js

关于 angular/cli 是否支持 Dll?作者和成员回答是不支持。但有人写了个 loader,但是 star 并不高,但作者有在维护,提 issue 反馈很快。

如果将 angular 模块打包成 dll,会导致路由模块懒加载不打包,因此需要 webpack-dll-ng-module-loader

DllPlugin 和 DllReferencePlugin 原理

  • DllPlugin 预先生成 dll.js 和对应的 json 文件
  • 在每次编译过程中,DllReferencePlugin 使用 json 文件来判断用户请求的文件是否是一个 dllModule,如果是的,webpack 就不会打包进来
  • Dll 这个概念借鉴了 Windows 系统的 dll。一个 dll 包,就是一个纯纯的依赖库,它本身不能运行,是用来给你的 app 引用的。

dll 版本号,自动清理过期文件,自动加入 index.html

结果

不知道是项目体量的原因,还是 Angular 自身的原因,热更新表现不尽人意,更新很慢,还容易内存溢出,直接爆掉。

打包优化,最后实践是成功了,但我并没有运用到实际项目中了,因为测试结果,打包速度的并没有提升很大,表示很费解,明明就少打包了那么多文件。

后续

今日(20190926)尝试了一下 HardSourceWebpackPlugin 插件,也是利用缓存的原理,但结果令人失望,你没有听过,结果慢了 23 秒,真扎心。

关于 dllPlugin 的使用,应该会有这样一种感觉,就是配置太繁琐了,社区有一个 AutoDllPlugin 可以解放你的配置负担。你需要知道的是 vue-cli 和 create-react-app 已经抛弃了 dll 的使用,因为 webpack 4 有着比 dll 更好的打包性能。

思考

至于为什么如今使用 dll 等一下插件,优化效果并不明显呢?我想可能是 webpack 发展到现在,内置了很多的优化,比如缓存等,从而导致效果不是很明显。

之前自己的关于缓存的思考局限了,简单了认为我项目下并没有新增文件,怎么可能开启的缓存呢。殊不知缓存可能会在 node_modules 文件夹下,比如 .cache 文件夹。同时 Node 具有文件访问权限,可以写入到你磁盘中几乎任意地方,比如你用户目录下。

资料



留言