webpack4的splitChunks分包
自从webpack升级到4以来,号称零配置。代码会自动分割、压缩、优化,同时 webpack 也会自动帮你 Scope hoisting 和 Tree-shaking。
说到这里webpack4取消了UglifyjsWebpackPlugin,使用minimize进行压缩,取消了CommonsChunkPlugin,使用splitChunks进行分包。
在没配置任何东西的情况下,webpack 4 就智能的帮你做了代码分包。入口文件依赖的文件都被打包进了main.js,那些大于 30kb 的第三方包,如:echarts、xlsx、dropzone等都被单独打包成了一个个独立 bundle。
其它被我们设置了异步加载的页面或者组件变成了一个个chunk,也就是被打包成独立的bundle,比如我们的workbook页面,是以运用了懒加载路优酷加载的。
它内置的代码分割策略是这样的:
新的 chunk 是否被共享或者是来自 node_modules 的模块
新的 chunk 体积在压缩之前是否大于 30kb
按需加载 chunk 的并发请求数量小于等于 5 个
页面初始加载时的并发请求数量小于等于 3 个
这是我们项目没有做任何配置的分包图,全是webpack做的默认配置。观察这个分析图,发现main.js里面既有node_modules的包,还有src下的业务代码,并且除了main,几乎每个bundle都是这样包含node_modules和src下的代码,这样有什么不好的地方呢,每次业务代码的变动会导致bundle的hash变化,JS文件缓存失效,要重新下载,但是node_modules下的文件根本没有变动,也会一起重新打包。
因为webpack只做了入口文件的依赖代码打包,也就是main.js,并且只做了入口文件的公共代码分析,只有入口文件引用过的代码,并且其他chunk页面也引入了的话,webpack会依据自身默认分包规则将其分包,如下图
但是如果入口文件没有引入,那么其它chunk页面里面的公共代码并没有抽出,导致每个bundle都有重复打包代码的情况,导致整个项目文件较大,Gzip压缩后仍然有2.07Mb,如下图,很明显antd的table组件都被重复打包了,因为入口文件没有引入,也就没有被webpack分包
但凡配置了缓存组,这项目代码会按照webpack默认配置提取,这个配置提取了项目所有公共引用在2次以上的大于30KB公共代码块,不仅是node_modules中的也包括src中的业务代码
cacheGroups{ common: { name: "common", chunks: "all", minChunks: 2, priority: 10, } }
会用到如 echarts、xlsx、dropzone等各种第三方插件,同时又由于是管理后台,所以本身自己也会写很多共用组件,比如各种封装好的搜索查询组件,共用的业务模块等等,如果按照默认的拆包规则,结果就不怎么完美了。
在知道了以上这些规则的现象后我对项目进行了一个分包,基于的策略是:
- 基础类库:react,react-redux,react-router
- UI库:antd,antd-icons
- 公共组件库:自定义的公共组件
- 低频组件:echart
- 业务代码
基于以上规则做出来的拆包结果如下
拆分后的包变为1.24MB,有了较大的缩小
与未拆分的包对比:因为拆出了common公共库,这个库主要是node_modules中的公共库,更新频率低,其它页面chunk都可以公用这块库,因此其它页面都只包含自己业务代码,例如process缩小了75%,modal缩小了87%,workbook缩小了80%,
另外webpack机制下,把入口文件和其它chunk文件的公共代码进行抽取,并且在首页进行下载,这样导致首页的下载文件过多,阻塞了网络