通常前端都会导入一些好用的第三方套件,但是有时后导入的套件并非是基于 es module 进行开发,webpack 没办法发挥 tree shaking 的功能,在 import 时一不注意就会载入一堆没有必要的 function。
在这篇文章中以 lodash 作为举例, lodash 是个能够帮我们处理各种资料的函式库,减少写一些比较琐碎的程式码。但因为 lodash 在 2012 年就被开源,历史较为久远,可能有多种缘故,导致目前 lodash 本身并不是使用 es module。所以如果在意 bundle size 的大小,就要特别注意在 import lodash 的方式。
先安装我们需要的 lodash :
yarn add lodash
安裝 webpack-bundle-analyzer
yarn add -D webpack-bundle-analyzer
webpack.config.js 中加入以下代码
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [
new BundleAnalyzerPlugin()
]
}
然后用 yarn start 启动 server ,跟方法 1 一样,除了原本专案的 8080 port 之外,你还会看到在 8888 port 启动了 webpack-bundle-analyzer
不指定 function 路径也就像我们平常使用 named exports 的 module 一样,我们稍微修改 App.js 的程式码,在 component 里面加上 lodash 的 isEmpty:
import React from 'react';
import { isEmpty } from 'lodash';
const App = ({ title }) => (
<div>{isEmpty(title) ? 'Title is Empty!!' : title}</div>
);
export default App;
接着,我们用 webpack bundle analyzer 看看使用这种 import 方式的 bundle size 为多少。
很夸张的是,明明只有用到 isEmpty 这个 function,结果 lodash 打包后的档案大小却足足有 531KB, 不禁让人怀疑 isEmpty 是多么伟大的 function ,做了包山包海的事情。
接下来,我们换一种 import 的方式,看看对 bundle size 会有什么影响。
天哪,换一种方式结果让 lodash 打包后的大小足足少了 22 倍,这是什么魔法?
import isEmpty from 'lodash/isEmpty';
为什么两种 import 的方式会导致 bundle size 不一样
我们必须知道 lodash 是一个使用 UMD (Universal Module Definition) 的套件,这意味着 lodash 并不满足在 webpack 中的 tree-shaking 必须是 es module 的条件。所以第一种方法实际上会载入完整的 lodash ,最终导致 bundle size 莫名的巨大;而第二种方法就是只载入一个档案,再从档案中拿出我们需要的 isEmpty,如此一来就不用担心载入整包 lodash 的问题。
可是如果都要像第二种方法这样写 code 实际上有点麻烦,而且团队可能一开始没考虑到这个问题,程式码已经有多处使用第一种方法,改起来十分麻烦。
以下提供两种我认为比较简易的解法,可以用最少量的配置,达到降低 bundle size 的方法。
这也是 lodash 的 GitHub 提到的作法,lodash 的 GitHub 中写道:「Looking for Lodash modules written in ES6 or smaller bundle sizes? Check out lodash-es.」,所以第一种解法便是改用 lodash-es:
// 下載 lodash-es
yarn add lodash-es
// 修改程式碼 lodash 的引用,變成使用 lodash-es
import { isEmpty } from 'lodash-es';
你可以看到 bundle size 顺利地从 531KB 降低到 24KB 左右,与上面提到的第二种 import 的方法有异曲同工之妙。
至于为什么第二种 import 方法与用 lodash-es 最终打包后的档案大小不一样,这又是另一个议题了。
如果你不想动到大量的程式码,上面使用 lodash-es 意味者必须全域取代 lodash 的引用,其实有另一个解法是使用 babel 的插件,让 babel 帮我们从第一种 import 的方式改成第二种。
首先,安装 babel-plugin-import 这个插件:
yarn add -D babel-plugin-import
然后修改 .babelrc 中的设定:
{
...
"plugins": [
[
"import",
{
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}
]
]
}
再用 webpack bundle analyzer 看看打包后的档案大小,可以看到档案打小与第二种 import 的方式一样都是 24.31KB,同样成功地降低 bundle size。
在这篇文章中我们了解了如何透过 webpack bundle analyzer 分析打包后的档案,并且透过这个工具看到不同 import lodash 方式对于 bundle size 的影响。
针对如何降低 lodash 被打包后的档案大小,本文提供两种方式,分别是使用 lodash-es 全域取代原本 lodash 的引用,或使用 babel-plugin-import 非侵入式的改动大量的程式码,而是在打包时处理,这两种方式都可以达到不把完整的 lodash 都打包进 bundle 的结果,就看各位如何选择啰!
原文链接:
https://medium.com/starbugs/the-correct-way-to-import-lodash-libraries-bdf613235927