React项目用lodash-es为啥Tree Shaking没效果?
大家好,我在React项目里改用lodash-es做Tree Shaking优化,但打包后发现整个lodash都被引入了。比如这样写:
import _ from 'lodash-es';
const ItemList = ({ items }) => (
<ul>
{_.map(items, item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
按说应该只打包map方法,但看bundle分析整个lodash都进去了。试过改成解构导入:
import { map } from 'lodash-es';
还是没变化,这是哪里出问题了?项目用create-react-app脚手架,没 ejected过…
简单说就是:你写了
import { map } from 'lodash-es',Babel 一转手就变成var _ = require('lodash')这种,Tree Shaking 自然失效了。解决办法有两个方向:
第一种,也是最稳妥的,直接换用 lodash 源码的子包,比如:
或者更狠一点,直接用 lodash-es 提供的命名导出(但要配合插件):
但第二种必须加个 Babel 插件:
babel-plugin-lodash,它会把_.map、_.get这种链式调用自动拆成单文件 import。没 eject 的 CRA 也能加,只要在根目录建个babel.config.js(不是 .babelrc),内容像这样:这样写
import _ from 'lodash-es'; _map(items, ...)或_.map(items, ...)都能正确 Tree Shaking。不过说实话,现在 lodash-es +
babel-plugin-lodash这套方案有点过时了。lodash 本身已经很轻量,很多工具函数其实可以被替代。比如_.map可以直接用原生Array.prototype.map,_.get也有小而美的单独包lodash.get。真要榨干体积,建议用lodash-es+ 插件,或者干脆手写几个高频函数——开发体验和 bundle 体积之间自己权衡吧。对了,记得清理下 node_modules 重装一次,Babel 缓存有时候会坑死人。
关键是 import 的方式要精确到具体方法,不能用大括号解构。另外,create-react-app 默认的生产环境打包可能没完全启用 tree shaking,记得加个环境变量:
这样再打包看看,应该就只留下用到的 map 方法了。如果还不行,可能是其他地方又偷偷引用了整个 lodash,去找找看有没有
import _ from 'lodash-es'这种写法。