最近折腾 @babel/preset-env 的一些小心得

近来厂里的项目越来越多,代码共享必不可少。我现在采取的方案是:

  1. 把公共组件拿出来,开一个新仓库
  2. 使用 webpack 进行打包编译,libraryTarget: 'umd'
  3. 将打包编译的代码一起提交到仓库
  4. 使用 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,列出所有目标浏览器,比如:

zhailujiadeiMac:fe meathill$ npx browserslist
and_chr 73
and_ff 66
and_qq 1.2
and_uc 11.8
android 67
android 4.4.3-4.4.4
baidu 7.12
chrome 73
chrome 72
edge 18
edge 17
firefox 66
firefox 65
ios_saf 12.2
ios_saf 12.0-12.1
kaios 2.5
op_mini all
op_mob 46
op_mob 12.1
opera 58
opera 57
safari 12.1
safari 12
samsung 9.2
samsung 8.2

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 配置:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "> 5%",
        "useBuiltIns": "usage",
        "corejs": 3
      }
    ]
  ]
}

注意,目前 Vue Cli 3 集成了 core-js 2,不支持升级到 v3,无法手动升级。需要等待 Vue Cli 4。

@babel/polyfill

@babel/polyfill 是对 core-js 的封装,引用了 core-js 的内容和生成器(regenerator-runtime)。 v7.4 之后,这个仓库就被废弃了,希望用户自己选择使用哪个兼容库。

换言之,以前:

import "@babel/polyfill";

需要被替换成

import "core-js/stable";
import "regenerator-runtime/runtime";

不过我不建议这么做。对于绝大部分情况,使用 @babel/preset-env + useBuiltIns: 'usage' 仍然是最好的选择。


总结

这些知识并不复杂,基本上文档里都有。不过一次性看大量英文文档可能对很多同学来说都是负担。我比较提倡这样学习:

  1. 遇到需求就去看一遍,不求全部理解,能解决目前的问题即可
  2. 重复这个过程,争取每次都比上一次理解更多
  3. 建立不同工具之间的逻辑体系,要求能够内恰
  4. 继续重复这个过程,知道确认自己理解了
  5. 通过看文档巩固

作者: meathill

爱编程,爱旅游,爱吐槽。 今年的目标是完成并运营至少一个 Side Project。 《Electron + Vue 实战开发》龟速创作中……

欢迎吐槽,请勿装死

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据