一、首先要了解概念:​​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​​​中移除就可以了。​​链接​​​
​参考链接​



 

长风破浪会有时,直挂云帆济沧海