Tree Shaking 为什么没生效?按需引入 lodash 还是打包了整个库?
我用的是 webpack5 + babel,想按需引入 lodash 的 debounce 方法,但打包后发现整个 lodash 库都被打进去了,体积一点没减。
我试过直接 import { debounce } from 'lodash',也试过装 babel-plugin-lodash 插件,但都没效果。是不是我配置哪里错了?
这是我的 webpack 配置相关部分:
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false
},
// ...其他配置
}
你的 webpack 配置里 optimization.sideEffects: false 这个设置有问题。这个配置会让 Webpack 认为所有文件都没有副作用,但 lodash 是 CommonJS 模块,直接这样设置反而会把整个库打包进去。建议把这个选项删掉或者设为 true。
另外,光用 babel-plugin-lodash 不够,你还需要安装 lodash-es 和 babel-plugin-import 插件。具体操作步骤:
1. 安装依赖
npm install lodash-es babel-plugin-lodash --save
npm install babel-plugin-import --save-dev
2. 修改 babel 配置
{
"plugins": [
["import", {
"libraryName": "lodash-es",
"style": false
}],
"lodash"
]
}
3. 修改 import 语句
不要用 import { debounce } from 'lodash',改成 import debounce from 'lodash-es/debounce'
最后调试看看效果。记得清空缓存重新打包,webpack 缓存有时候会让人抓狂。我自己也被这种问题坑过好几次,按需引入真不是那么简单的。
你配置的
usedExports和sideEffects都没问题,但 Tree Shaking 的前提是模块必须是 ES Module 格式,静态分析才能识别哪些导出被用到了。CommonJS 是动态加载的,webpack 没法在编译时确定,只能全量打包。解决方案有两个,推荐第一个。
方案一:换成 lodash-es
lodash-es 是官方提供的 ES Module 版本,配合你的配置,Tree Shaking 宔美生效。记得把 babel-plugin-lodash 卸了,用 lodash-es 不需要这玩意儿。
方案二:路径引入
这种方式直接引入具体文件,不经过模块解析,自然也不会打包整个库。缺点就是写法麻烦,引入多个方法的时候要写一堆。
另外说一句,babel-plugin-lodash 要生效的话,你得确保 babel 配置正确加载了这个插件,而且它主要是处理路径转换的,本质上还是方案二的思路。但前端这块我建议直接用 lodash-es,省心。
还有个小坑,如果你用了 @babel/preset-env 并且开启了 modules 转换,会把 ES Module 编译成 CommonJS,Tree Shaking 又废了。配置里得加上:
这样 ES Module 就能保留原样,webpack 才能做 Tree Shaking。