前言
我们知道 lodash 是一个非常常见的工具包,但在实际项目中,我们并没有使用 lodash 的提供的所有方法,因此我们会通过按需引入的方式去使用 lodash,进而减少产物的体积。
lodash
在使用 lodash 时,如果需要按需引入,我们需要手动的进行按需,如:
import head from 'lodash/head';
lodash-es
lodash-es 是 esm 的版本,得益于 esm 的静态分析带来的 tree-shaking 的能力,如
import { head } from 'lodash-es'
对于新项目而言,建议使用 lodash-es 替代 lodash
babel-plugin-lodash
对于旧项目而言,使用 lodash-es 替换 lodash 的成本太高了,因此我们可以通过 babel-plugin-lodash 去做转化。
通过查阅源码我们发现 babel-plugin-lodash 的主要是将引用路径进行替换,已达到瘦身的效果
import { pick } from 'lodash'
// 通过 babel-plugin-lodash 会转化为
import pick from 'lodash/pick'
举个🌰
// 源代码
import { pick } from 'lodash';
const d = pick({a: 1, b: 2}, 'a');
console.log(`d===>`, d);
// babel.config.js
module.exports = {
presets: ["@babel/preset-env"],
plugins: ["babel-plugin-lodash"]
};
通过执行 babel src -d dist, 可以得到转化结果:
"use strict";
var _pick2 = _interopRequireDefault(require("lodash/pick"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var d = (0, _pick2["default"])({
a: 1,
b: 2
}, 'a');
console.log("d===>", d);
但体积还是特别大,例如
import map from 'lodash/map'
它会打包多个 lodash 模块,原因是 map 模块里面内联了其他模块
lodash-webpack-plugin
通过查阅源码我们可以发现,lodash-webpack-plugin会根据 Map 的 对应关系 ( github.com/lodash/loda…)去对一些模块做替换操作。
可以看到,lodash-webpack-plugin 会对模块做一些替换操作,例如 clamp 模块会依赖 toNumber 进行参数处理,但是使用 lodash-webpack-plugin 后,会把 toNumber 替换成 identity,导致 clamp 不再支持字符串参数。如果传入的是字符串,返回的结果将发生变化。 因此如果使用的是 lodash-webpack-plugin 会有一些坑点,如影响第三方模块的行为、影响 lodash 自身模块的行为 造成的后果是出现 bug 比较难定位到问题
举个🌰:
// 源代码
// 主要验证 lodash-webpack-plugin
// 相关链接 https://github.com/lodash/lodash-webpack-plugin
import { clamp } from 'lodash';
/**
* clamp函数,包含number(需要判断的值)upper(上边界)lower(下边界)三个参数。如果number超出上边界或下边界,会返回距离number差值最小的边界值。如果包含在两个边界值中,则返回number
*/
console.log(`a====>`, clamp(10, 5, 20)); // 10
console.log(`b====>`, clamp('123', '5', '20')); // 20
console.log(`c====>`, clamp('123', '1', '20')); // 20
console.log(`d====>`, clamp(123, 1, 20)); // 20
webpack 配置
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const path = require('path');
module.exports = {
devtool: false,
mode: 'development',
entry: './src/index.js',
output: {
path: path.join(__dirname, './dist'),
filename: '[name].js',
libraryTarget: 'commonjs',
},
module: {
rules: [{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
plugins: ['lodash'],
presets: ['@babel/preset-env']
}
}
}]
},
plugins: [
new LodashModuleReplacementPlugin,
],
};
输出的代码:
总结
对于新项目而言,采用 lodash-es 是一个不错的方案,对于旧项目而言,babel-plugin-loadsh 要比 lodash-webpack-plugin 可靠。