大家对

  • @babel/preset-env
  • @babel/plugin-transform-runtime
  • @babel/runtime
  • core-js
  • @babel/polyfills
  • babel-polyfills

等等这些熟悉但又陌生的原因。

babel 6 & babel 7

在 babel@6 时候,最常收到反馈之一就是 regeneratorRuntime is not defined

而到了 babel@7,最常收到反馈之一 Cannot find module ‘core-js/library/fn/**’.

@babel/preset-env

在 babel@7 推出之际,babel 官方把 babel preset stage 以及 es2015 es2016 等等都废弃了,取而代之的是 @babel/preset-env。

  • 在 babel@6 年代,我们使用的是 stage,那 stage 其实只会翻译 Syntax,而 API 则交给 babel-plugin-transform-runtime 或者 babel-polyfill 来实现。(这也是为什么大家在老项目中可以看到有引入 babel-polyfill 的原因)
  • 在 babel@7 年代,我们废弃了 stage,使用的 preset-env,同时他也可以提供 polyfill 的能力

通过官方文档的描述,preset-env 主要做的是转换 JavaScript 最新的 Syntax(指的是 const let … 等), 而作为可选项 preset-env 也可以转换 JavaScript 最新的 API (指的是比如 数组最新的方法 filter 、includes,Promise 等等)。

targets

该参数决定了我们项目需要适配到的环境,比如可以申明适配到的浏览器版本,这样 babel 会根据浏览器的支持情况自动引入所需要的 polyfill。

useBuiltIns

“usage” | “entry” | false, defaults to false

false
false: 这种方式下,不会引入 polyfills,你需要人为在入口文件处@import ‘@babel/polyfill’;

但如上这种方式在 @babel@7.4 之后被废弃了,取而代之的是在入口文件处自行 import 如下代码

  1. import 'core-js/stable';
  2. import 'regenerator-runtime/runtime';
  3. // your code

不推荐采用 false,这样会把所有的 polyfills 全部打入,造成包体积庞大

usage:

我们在项目的入口文件处不需要 import 对应的 polyfills 相关库。babel 会根据用户代码的使用情况,并根据 targets 自行注入相关 polyfills。

entry:

我们在项目的入口文件处 import 对应的 polyfills 相关库,例如

  1. import 'core-js/stable';
  2. import 'regenerator-runtime/runtime';
  3. // your code

此时 babel 会根据当前 targets 描述,把需要的所有的 polyfills 全部引入到你的入口文件(注意是全部,不管你是否有用到高级的 API

2个问题

问题一:还是会有一定程度的代码重复,举个例子:

问题二:针对项目,polyfill 会污染全局可以接受,但是作为 Library 我更希望它不会污染全局环境

corejs:

使用 preset-env 注入的 polyfill 是会污染全局的,但是如果是自己的应用其实是在可控的。

总结下:用 corejs-3,开启 proposals: true,proposals 为真那样我们就可以使用 proposals 阶段的 API 了。

@babel/plugin-transform-runtime

很明显该插件的出现就是复用 babel 注入的关联代码。

针对项目,polyfill 会污染全局可以接受,但是作为 Library 我更希望它不会污染全局环境

做了3件事情

Automatically requires @babel/runtime/regenerator when you use generators/async functions (toggleable with the regenerator option).

Can use core-js for helpers if necessary instead of assuming it will be polyfilled by the user (toggleable with the corejs option)

Automatically removes the inline Babel helpers and uses the module @babel/runtime/helpers instead (toggleable with the helpers option).

使用生成器/异步功能时自动需要@ Babel /运行时/重新生物器(使用Regenerator选项转换)。

如果需要,可以使用core-js为everyers而不是假设它将由用户聚集(与corejs选项)来电(togllable)

自动删除内联babel evergers并使用模块@ babel /运行时/ eververs(使用Helpers选项toglable)。

业务代码中怎么使用

只使用preset-env

  1. {
  2. "presets": [
  3. [
  4. "@babel/preset-env",
  5. {
  6. "targets": {
  7. "chrome": "58" // 按自己需要填写
  8. },
  9. "useBuiltIns": "entry",
  10. "corejs": {
  11. "version": 3,
  12. "proposals": true
  13. }
  14. }
  15. ]
  16. ],
  17. "plugins": []
  18. }
  19. import 'core-js/stable';
  20. import 'regenerator-runtime/runtime';
  21. // 入口文件代码

这样配置的原因是:targets 下设置我们业务项目所需要支持的最低环境配置,useBuiltIns 设置为 entry ,将最低环境不支持的所有 polyfill 都引入到入口文件(即使你在你的业务代码中并未使用)。

这是一种兼顾最终打包体积和稳妥的方式,为什么说稳妥呢,因为我们很难保证引用的三方包有处理好 polyfill 这些问题。当然如果你能充分保证你的三方依赖 polyfill 处理得当,那么也可以把 useBuiltIns 设置为 usage。

解决2个问题,结合plugin-transform-runtime使用

如果是业务项目开发者:@babel/plugin-transform-runtime ,建议关闭 corejs,polyfill 的引入由 @babel/preset-env 完成,即开启 useBuiltIns(如需其他配置,自行根据诉求配置)

  1. {
  2. "presets": [
  3. [
  4. "@babel/preset-env",
  5. {
  6. "useBuiltIns": "entry",
  7. "corejs": {
  8. "version": 3,
  9. "proposals": true
  10. }
  11. }
  12. ]
  13. ],
  14. "plugins": [
  15. [
  16. "@babel/plugin-transform-runtime",
  17. {
  18. "corejs": false
  19. }
  20. ]
  21. ]
  22. }
  23. 并在入口文件处 import 如下内容
  24. import 'core-js/stable';
  25. import 'regenerator-runtime/runtime';
  26. // 入口文件代码

如果是 Library 开发者

@babel/plugin-transform-runtime ,建议开启 corejs,polyfill 由 @babel/plugin-transform-runtime 引入。@babel/preset-env 关闭 useBuiltIns。

  1. {
  2. "presets": [
  3. [
  4. "@babel/preset-env",
  5. ]
  6. ],
  7. "plugins": [
  8. [
  9. "@babel/plugin-transform-runtime",
  10. {
  11. "corejs": {
  12. "version": 3,
  13. "proposals": true
  14. }
  15. }
  16. ]
  17. ]
  18. }