一、首先要了解概念:module
,chunk
和 bundle 到底是什么?
module
,chunk
和 bundle
其实就是同一份逻辑代码在不同转换场景下的取了三个名字:
我们直接写出来的是 module,webpack 处理时是 chunk,最后生成浏览器可以直接运行的 bundle。 参考链接
二、除了常见的项目优化(开启gzip压缩、external引入线上cdn减少打包体积...)还有什么?
1、优化拆包策略。默认webpack分包策略是:
- 新的 chunk 是否被共享或者是来自 node_modules 的模块
- 新的 chunk 体积在压缩之前是否大于 30kb
- 按需加载 chunk 的并发请求数量小于等于 5 个
- 页面初始加载时的并发请求数量小于等于 3 个
以上这些情况 都会单独打包成了一个个独立 bundle。 这就造成一些不合理的现象。例如:一个后台管理页面,它大部分的页面都是表单和 Table,我使用了一个第三方 table 组件,几乎后台每个页面都需要它,但它的体积也就 15kb,不具备单独拆包的标准,它就这样被打包到每个页面的 bundle 中了,这就很浪费资源了。这种情况下建议把大部分页面能共用的组件单独抽出来,策略是按照体积大小、共用率、更新频率重新划分我们的包,使其尽可能的利用浏览器缓存
2、持久化缓存
- 针对 html 文件:不开启缓存,把 html 放到自己的服务器上,关闭服务器的缓存
- 针对静态的 js,css,图片等文件:开启 cdn 和缓存,将静态资源上传到 cdn 服务商,我们可以对资源开启长期缓存,因为每个资源的路径都是独一无二的,所以不会导致资源被覆盖,保证线上用户访问的稳定性。
- 每次发布更新的时候,先将静态资源(js, css, img) 传到 cdn 服务上,然后再上传 html 文件,这样既保证了老用户能否正常访问,又能让新用户看到新的页面。
总结
拆包策略:
- 基础类库
chunk-libs
- UI 组件库
chunk-elementUI
- 自定义共用组件/函数
chunk-commons
- 低频组件
chunk-eachrts
/chunk-xlsx
等 - 业务代码 lazy-loading
xxxx.js
持久化缓存:
- 使用
runtimeChunk
提取manifest
,使用script-ext-html-webpack-plugin
等插件内联到index.html
减少请求 - 使用
HashedModuleIdsPlugin
固定moduleId
- 使用
NamedChunkPlugin
结合自定义 nameResolver 来固定chunkId
使用babel
的 plugins
babel-plugin-dynamic-import-node。它只做一件事就是将所有的import()
转化为require()
,这样就可以用这个插件将所有异步组件都用同步的方式引入,并结合 BABEL_ENV 这个babel
环境变量,让它只作用于开发环境下,在开发环境中将所有import()
转化为require()
,这种方案解决了之前重复打包的问题,同时对代码的侵入性也很小,你平时写路由的时候只需要按照官方文档路由懒加载的方式就可以了,其它的都交给babel
来处理,当你不想用这个方案的时候,也只要将它从babel
的 plugins
中移除就可以了。链接
参考链接
长风破浪会有时,直挂云帆济沧海