[转] 最近折腾 @babel/preset-env 的一些小心得
近来厂里的项目越来越多,代码共享必不可少。我现在采取的方案是:
- 把公共组件拿出来,开一个新仓库
- 使用 webpack 进行打包编译,
libraryTarget: 'umd'
- 将打包编译的代码一起提交到仓库
- 使用
npm i <owner>/<repo> -S
安装依赖,因为我厂的仓库均为私有,所以不能发布到 NPM
这套方案简单好用,实操效果良好。接下来我希望优化打包结果,于是研究了打包配置项,下面是我的一点心得。
@babel/preset-env
首先,Babel 推荐使用 @babel/preset-env 套件来处理转译需求。顾名思义,preset 即“预制套件”,包含了各种可能用到的转译工具。之前的以年份为准的 preset 已经废弃了,现在统一用这个总包。
同时,babel 已经放弃开发 stage-* 包,以后的转译组件都只会放进 preset-env 包里。
browserslist
@babel/preset-env 支持一些参数,用来处理哪些 feature 要转译,哪些不要。其中比较重要的是 targets
,用来指定目标环境。targets
使用 browserslist 来筛选浏环境,这样我们就不需要指定所有浏览器版本,而可以使用类似 last 2 versions
这样的描述。具体怎写,可以看文档,这里不再赘述。
如果你想知道自己配置的是否合适,可以在仓库目录下执行 npx browserslist
,列出所有目标浏览器,比如:
Babel 官方建议我们把 targets
写到 .browserslistrc
或者 package.json
里,这样其它工具也能更轻易的获取到目标浏览器。另外,npx browserslist
无法从 .babelrc
等 babel 配置文件里读取配置,所以执行的时候看到的会是默认结果。
useBuiltIns
接下来,我们可以配置 useBuiltIns
,这个属性决定是否引入 polyfill。它有三个可选值,默认是 false
,即不引入,或者说,Babel 编译结果不引入,把引入的位置、引入哪些 polyfill 交给用户处理。因为我们的页面中通常有大量的 JS,在每个文件里分别引用 polyfill 太浪费资源,所以可以在核心入口 JS 引用一次即可。
但是这样我们必须手动 import '@babel/polyfill'
引入所有 polyfill,其实并不理想,因为大部分浏览器不需要这些。
所以推荐用 useBuiltIns: 'usage'
即“按需引用”。虽然文档中标记为“experimental”,但我用起来也没遇到什么问题。如果目标浏览器不支持需要的 feature,那么就引入 polyfill,不然的话就不引用。由于目前的打包工具越发智能,随着 tree shaking 的完善,这样可以最低限度引入 polyfill。
core-js
core-js 目前最新版本是 3.0.1,关于 v3 和 v2 的对比,大家可以看这篇博文:https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md。这里简单总结一下,core-js 2 封版于 1.5 年之前,所以里面只有对 1.5 年之前 feature 的 polyfill,最近 1.5 年新增的 feature 都不支持,也就存在因为新功能没有 polyfill 于是在旧浏览器里失败的风险。
所以我们应当升级到最新版,npm i core-js@3 -D
然后修改 babel 配置:
注意,目前 Vue Cli 3 集成了 core-js 2,不支持升级到 v3,无法手动升级。需要等待 Vue Cli 4。
@babel/polyfill
@babel/polyfill 是对 core-js 的封装,引用了 core-js 的内容和生成器(regenerator-runtime)。 v7.4 之后,这个仓库就被废弃了,希望用户自己选择使用哪个兼容库。
换言之,以前:
需要被替换成
不过我不建议这么做。对于绝大部分情况,使用 @babel/preset-env + useBuiltIns: 'usage'
仍然是最好的选择。
总结
这些知识并不复杂,基本上文档里都有。不过一次性看大量英文文档可能对很多同学来说都是负担。我比较提倡这样学习:
- 遇到需求就去看一遍,不求全部理解,能解决目前的问题即可
- 重复这个过程,争取每次都比上一次理解更多
- 建立不同工具之间的逻辑体系,要求能够内恰
- 继续重复这个过程,知道确认自己理解了
- 通过看文档巩固