摇树,顾名思义,就是将枯黄的落叶摇下来,只留下树上活的叶子。枯黄的落叶代表项目中未引用的无用代码,活的树叶代表项目中实际用到的源码。

3.1 JS

JS Tree Shaking 将 JavaScript 上下文中的未引用代码(Dead Code)移除,通过 package.json 的 “sideEffects” 属性作为标记,向 compiler 提供提示,表明项目中的哪些文件是 “pure(纯正 ES2015 模块)”,由此可以安全地删除文件中未使用的部分。

Dead Code 一般具有以下几个特征:

  • 代码不会被执行,不可到达;
  • 代码执行的结果不会被用到;
  • 代码只会影响死变量(只写不读)。

3.1.1 webpack5 sideEffects


通过 package.json 的 “sideEffects” 属性,来实现这种方式。

  1. {
  2. "name": "your-project",
  3. "sideEffects": false
  4. }

需注意的是,当代码有副作用时,需要将 sideEffects 改为提供一个数组,添加有副作用代码的文件路径:

  1. {
  2. "name": "your-project",
  3. "sideEffects": ["./src/some-side-effectful-file.js"]
  4. }

添加 TreeShaking 后,未引用的代码,将不会被打包,效果如下:

3.1.2 对组件库引用的优化


webpack5 sideEffects 只能清除无副作用的引用,而有副作用的引用则只能通过优化引用方式来进行 Tree Shaking。

  1. lodash
    类似 import { throttle } from 'lodash' 就属于有副作用的引用,会将整个 lodash 文件进行打包。
    优化方式是使用 import { throttle } from 'lodash-es' 代替 import { throttle } from 'lodash',lodash-es 将 Lodash 库导出为 ES 模块,支持基于 ES modules 的 tree shaking,实现按需引入。
  2. ant-design
    ant-design 默认支持基于 ES modules 的 tree shaking,对于 js 部分,直接引入import { Button } from 'antd'就会有按需加载的效果。
    假如项目中仅引入少部分组件,import { Button } from 'antd' 也属于有副作用,webpack不能把其他组件进行tree-shaking。这时可以缩小引用范围,将引入方式修改为 import { Button } from 'antd/lib/button'来进一步优化。

使用ES6引入的方式 import

3.2 CSS

上述对 JS 代码做了 Tree Shaking 操作,同样,CSS 代码也需要摇摇树,打包时把没有用的 CSS 代码摇走,可以大幅减少打包后的 CSS 文件大小。

使用 purgecss-webpack-plugin 对 CSS Tree Shaking。

安装

  1. npm i -D purgecss-webpack-plugin

因为打包时 CSS 默认放在 JS 文件内,因此要结合 webpack 分离 CSS 文件插件 mini-css-extract-plugin 一起使用,先将 CSS 文件分离,再进行 CSS Tree Shaking。

webpack.prod.js 配置方式如下:

  1. const glob = require('glob')
  2. const MiniCssExtractPlugin = require('mini-css-extract-plugin')
  3. const PurgeCSSPlugin = require('purgecss-webpack-plugin')
  4. const paths = require('paths')
  5. module.exports = {
  6. plugins: [
  7. // 打包体积分析
  8. new BundleAnalyzerPlugin(),
  9. // 提取 CSS
  10. new MiniCssExtractPlugin({
  11. filename: "[name].css",
  12. }),
  13. // CSS Tree Shaking
  14. new PurgeCSSPlugin({
  15. paths: glob.sync(`${paths.appSrc}/**/*`, { nodir: true }),
  16. }),
  17. ]
  18. }



上面为了测试 CSS 压缩效果,我引入了大量无效 CSS 代码,因此 Tree Shaking 效果也非常明显,效果如下:
image.png