站点图标 山维空间

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

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

  1. 把公共组件拿出来,开一个新仓库
  2. 使用 webpack 进行打包编译,libraryTarget: 'umd'
  3. 将打包编译的代码一起提交到仓库
  4. 使用 npm i <owner>/<repo> -S 安装依赖,因为我厂的仓库均为私有,所以不能发布到 NPM

这套方案简单好用,实操效果良好。接下来我希望优化打包结果,于是研究了打包配置项,下面是我的一点心得。

[2021-04-07] 更新:

我们目前采用 GitHub Registry 托管私有 packages 的方案,比上面直接安装仓库的方案更好,想了解的同学可以看 使用 GitHub Registry 托管私有 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

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

{
  "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. 通过看文档巩固
退出移动版