transformIgnorePatterns 是 Jest 配置的一个功能,它是一个正则字符串数组。任何匹配这些正则表达式的代码,都不会被 babel-jest 重新编译。默认是一个字符串“node_modules”。这就是为什么Jest 不会重新编译任何库代码。
当我们提供了自定义配置,就是告诉 Jest 重新编译的时候如何忽略代码。也就是为什么你刚才看到的变态的正则表达式有一个负向先行断言在里面,目的是为了匹配除了库以外的所有代码。换句话说,我们告诉 Jest 忽略 node_modules 中除了指定库之外的所有代码。
这又一次证明了 JavaScript 配置比 JSON 配置要好,因为我可以轻松地通过字符串操作,往正则表达式里插入库名字的数组拼接。
第二个是 transform 配置,他指向一个自定义的 babel-jest 转换器。我不敢100%确定这个是必须的,但我还是加上了。设置它用于在重新编译所有代码时加载我们的 Babel 配置。
// Babel-Jest 转换器 const babelJest = require(\'babel-jest\'); const path = require(\'path\'); const cwd = process.cwd(); const babelConfig = require(path.resolve(cwd, \'babel.config\')); module.exports = babelJest.createTransformer(babelConfig);这些都配置好后,你在测试代码应该又能跑了。记住了,任何使用库的 es2015 模块都需要这样配置,不然测试代码跑不动。
Npm/Yarn Link 就是魔鬼接下来轮到另一个痛点了:链接库。使用 npm/yarn 链接的过程就是创建一个指向本地项目目录的符号链接。结果表明,Babel 在重新编译通过这种方式链接的库时,会抛出很多错误。我之所以花了这么长时间才弄清楚 Jest 这档子事儿,原因之一就是我一直通过这种方式链接我的库,出现了一堆错误。
解决办法就是:不要使用 npm/yarn link。用类似 “yalc” 这样的工具,它可以连接本地项目,同时能模拟正常的 npm 安装过程。它不但没有 Babel 重编译的问题,还能更好地处理传递性依赖。
针对特定库的优化。如果完成了以上所有步骤,你的应用基本上实现了比较健壮的 tree shaking。不过,为了进一步减少文件包大小,你还可以做一些事情。我会列举一些特定库的优化方法,但这绝对不是全部。它尤其能为我们提供灵感,做出一些更酷的事情。
MomentJS 是出了名的大体积库。幸好它可以剔除多语言包来减少体积。在下面的代码示例中,我排除了 momentjs 所有的多语言包,只保留了基本部分,体积明显小了很多。
// 用 IgnorePlugin 移除多语言包 const { IgnorePlugin } from \'webpack\'; const config = { plugins: [ new IgnorePlugin(/^\.\/locale$/, /moment/) ] };Moment-Timezone 是 MomentJS 的老表,也是个大块头。它的体积基本上是一个带有时区信息的超大 JSON 文件导致的。我发现只要保留本世纪的年份数据,就可以将体积缩小90%。这种情况需要用到一个特殊的 Webpack 插件。
// MomentTimezone Webpack Plugin const MomentTimezoneDataPlugin = require(\'moment-timezone-data-webpack-plugin\'); const config = { plugins: [ new MomentTimezoneDataPlugin({ startYear: 2018, endYear: 2100 }) ] };Lodash 是另一个导致文件包膨胀的大块头。幸好有一个替代包 Lodash-es,它被编译成 es2015 模块,并带有 sideEffects 标志。用它替换 Lodash 可以进一步缩减包的大小。
另外,Lodash-es,react-bootstrap 以及其他库可以在 Babel transform imports 插件的帮助下实现瘦身。该插件从库的 index.js 文件读取 import 语句,并使其指向库中特定文件。这样就使 webpack 在解析模块树时更容易对库做 tree shaking。下面的例子演示了它是如何工作的。
// Babel Transform Imports // Babel config const config = { plugins: [ [ \'transform-imports\', { \'lodash-es\': { transform: \'lodash/${member}\', preventFullImport: true }, \'react-bootstrap\': { transform: \'react-bootstrap/es/${member}\', // The es folder contains es2015 module versions of the files preventFullImport: true } } ] ] }; // 这些库不再支持全量导入,否则会报错 import _ from \'lodash-es\'; // 具名导入依然支持 import { debounce } from \'loash-es\'; // 不过这些具名导入会被babel编译成这样子 // import debounce from \'lodash-es/debounce\'; 总结全文到此结束。这样的优化可以极大地缩减打包后的大小。随着前端架构开始有了新的方向(比如微前端),保持包大小最优化变得比以往更加重要。希望本文能给那些正在给应用程序做tree shaking的同学带来一些帮助。
交流欢迎扫码关注微信公众号“1024译站”,为你奉上更多技术干货。