摇树,顾名思义,就是将枯黄的落叶摇下来,只留下树上活的叶子。枯黄的落叶代表项目中未引用的无用代码,活的树叶代表项目中实际用到的源码。
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” 属性,来实现这种方式。
{"name": "your-project","sideEffects": false}
需注意的是,当代码有副作用时,需要将 sideEffects 改为提供一个数组,添加有副作用代码的文件路径:
{"name": "your-project","sideEffects": ["./src/some-side-effectful-file.js"]}
添加 TreeShaking 后,未引用的代码,将不会被打包,效果如下:
3.1.2 对组件库引用的优化
webpack5 sideEffects 只能清除无副作用的引用,而有副作用的引用则只能通过优化引用方式来进行 Tree Shaking。
- lodash
类似import { throttle } from 'lodash'就属于有副作用的引用,会将整个 lodash 文件进行打包。
优化方式是使用import { throttle } from 'lodash-es'代替import { throttle } from 'lodash',lodash-es 将 Lodash 库导出为 ES 模块,支持基于 ES modules 的 tree shaking,实现按需引入。 - 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。
安装
npm i -D purgecss-webpack-plugin
因为打包时 CSS 默认放在 JS 文件内,因此要结合 webpack 分离 CSS 文件插件 mini-css-extract-plugin 一起使用,先将 CSS 文件分离,再进行 CSS Tree Shaking。
webpack.prod.js 配置方式如下:
const glob = require('glob')const MiniCssExtractPlugin = require('mini-css-extract-plugin')const PurgeCSSPlugin = require('purgecss-webpack-plugin')const paths = require('paths')module.exports = {plugins: [// 打包体积分析new BundleAnalyzerPlugin(),// 提取 CSSnew MiniCssExtractPlugin({filename: "[name].css",}),// CSS Tree Shakingnew PurgeCSSPlugin({paths: glob.sync(`${paths.appSrc}/**/*`, { nodir: true }),}),]}
上面为了测试 CSS 压缩效果,我引入了大量无效 CSS 代码,因此 Tree Shaking 效果也非常明显,效果如下:
