Tree Shaking 为什么没生效?我明明用了 ES6 模块啊
我在用 Webpack 打包一个 React 项目,发现 lodash 的整个包都被打包进去了,哪怕我只 import 了一个 debounce。我查了文档说 Tree Shaking 要求用 ES6 模块,我也确实这么写了,但还是没效果,是不是哪里配置错了?
这是我的代码:
import { debounce } from 'lodash';
function MyComponent() {
const handleResize = debounce(() => {
console.log('resized');
}, 300);
return <div onResize={handleResize}>Hello</div>;
}
我试过加 sideEffects: false 到 package.json,也确认 mode 是 production,但 bundle 里还是有整个 lodash……
lodash 主包是 CommonJS 格式导出的,不管你怎么 import,Webpack 都没法做 Tree Shaking。想生效得用 lodash-es,这个才是 ES Module 版本:
或者单独装具体的函数包,比如
lodash.debounce,也能解决。import就是 ES Module,其实根本不是那么回事。问题出在你引入的包本身。npm 上的
lodash默认包,里面全是 CommonJS 格式的代码。Tree Shaking 的核心是静态分析,CommonJS 是动态加载的,Webpack 根本没法在编译阶段安全地把你没用的代码剔除掉。所以不管你怎么配sideEffects,它只能把整个 lodash 都塞进去。要解决这个问题,最直接的办法是把包换成
lodash-es。这才是官方提供的 ES Module 版本。代码改一行就行:
这样 Webpack 才能识别出哪些导出是没用的,直接把没用的函数在打包时干掉。重新跑一下构建,你会发现体积瞬间小几十 KB。
如果你项目太大,到处都是
import { ... } from 'lodash',懒得改代码,也可以用babel-plugin-lodash配合lodash-webpack-plugin。这俩插件组合能把你的引用自动转成import debounce from 'lodash/debounce'这种按需加载的方式,也能达到优化效果。不过既然还在开发阶段,直接切
lodash-es最省事,原生支持 Tree Shaking,别让用户白白下载那么大一堆没用的代码。