对@babel/preset-env中的useBuiltIns选项(使用Browserslist集成)感到困惑

89
我正在使用Babel 7和Webpack 4开发一个Web项目。我以前没有使用过Babel,有些地方不太理解。根据文档,我使用@babel/preset-env,因为它似乎是推荐的方式(尤其适合初学者)。同时,通过我的.browserslistrc文件,也使用了Browserslist集成。
Webpack编译良好(babel-loader版本为8.0.2),没有错误,但我对这里提到的useBuiltIns: "entry" 选项以及Babel中的polyfill系统感到困惑。 .babelrc.js
module.exports = {
  presets: [
    ['@babel/preset-env', {
      "useBuiltIns": "entry" // do I need this?
    }]
  ],
  plugins: [
    '@babel/plugin-syntax-dynamic-import'
  ]
};

.browserslistrc
这里是从此处复制过来的(因为我的项目正在使用Bootstrap),请注意。

>= 1%
last 1 major version
not dead
Chrome >= 45
Firefox >= 38
Edge >= 12
Explorer >= 10
iOS >= 9
Safari >= 9
Android >= 4.4
Opera >= 30

所以我的问题是:

1)我需要使用useBuiltIns: "entry"选项吗?

2)我需要安装@babel/polyfill包并以require("@babel/polyfill");开头启动我的vendors.js吗?

3)如果我都省略了呢?

如果我做了1和2,我的vendors.js将增长到411 KB
如果我都省略了,它只有341 KB
在生产构建之后。

我认为@babel/preset-env默认情况下处理所有重写和polyfills,不需要我额外的import/require...

谢谢!

-- 编辑 --

Babel团队刚刚更新@babel/polyfill文档,基于一些GitHub问题(包括我的)抱怨文档不清晰/误导。现在如何使用它已经很明显了。(...然后我的原始问题似乎很愚蠢 :))

2个回答

130

我需要使用useBuiltIns: "entry"选项吗?

是的,如果您想根据目标环境包含polyfills。

TL;DR

实际上有三个useBuiltIns选项:

"entry":使用此选项时,@babel/preset-env将直接导入core-js替换为仅针对目标环境所需的特定模块的导入。

这意味着您需要添加:

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

到达您的入口点,这些行将被仅所需的polyfill替换。当针对chrome 72时,它将被@babel/preset-env转换为

import "core-js/modules/es.array.unscopables.flat";
import "core-js/modules/es.array.unscopables.flat-map";
import "core-js/modules/es.object.from-entries";
import "core-js/modules/web.immediate";
"usage":在这种情况下,当目标环境不支持某些功能的使用时,polyfills会自动添加。因此:
const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);

在像 ie11 这样的浏览器中,将被替换为

import "core-js/modules/es.array.includes";
import "core-js/modules/es.array.iterator";
import "core-js/modules/es.object.to-string";
import "core-js/modules/es.set";

const set = new Set([1, 2, 3]);
[1, 2, 3].includes(2);

如果目标浏览器是最新的 Chrome,则不会应用任何转换。

就我个人而言,这是我选择的武器,因为无需在源代码中包含任何内容(core-js 或 regenerator),只会根据在 browserlist 中设置的目标环境自动添加所需的 polyfills。


false:当没有自动添加 polyfills 时,这是默认值。


  

2)我需要安装 @babel/polyfill 包并以 require("@babel/polyfill"); 开始我的 vendors.js 吗?

对于babel v7.4core-js v3之前的环境,是需要的。

TL;DR

不需要。从 babel v7.4core-js v3 (它用于底层填充) 开始,@babel/preset-env 只会在知道哪些 polyfills 是必需的,并按推荐顺序添加它们时才会添加 polyfills。

此外,@babel/polyfill 已被弃用,应使用单独的 core-jsregenerator-runtime 包。

因此,使用除 false 以外的选项的 useBuiltIns 应该可以解决问题。

不要忘记将 core-js 添加为项目的依赖项,并在 @babel/preset-envcorejs 属性中设置其版本。


  

3)如果两者都省略会怎样?

正如 @PlayMa256 已经回答的那样,将不会有 polyfills。


可以在 core-js创建者页面上找到更详细和完整的信息。

也可以随意玩玩 babel 沙盒。


1
在使用"usage"时,我必须使用import "core-js/stable"; import "regenerator-runtime/runtime";吗? - Max
5
不需要,您只需要将 core-js 添加到依赖项中即可。 - Egor Litvinchuk
2
好的回答。Babel文档中说:“当使用usage或entry选项时,@babel/preset-env将作为裸导入(或需要)添加对core-js模块的直接引用。这意味着core-js将相对于文件本身进行解析,并且需要是可访问的。”没有上下文或示例很难理解。 - Richard Hunter
1
这将为人们节省一周时间:https://github.com/babel/babel/discussions/14443 - VimNing

15

1) 我需要使用useBuiltIns: "entry"选项吗?

是的,根据Babel文档:

“这个选项启用了一个新插件,它会根据环境基于需要替换语句import "@babel/polyfill"或require("@babel/polyfill"),从而包括所有所需的polyfills(当你在需要时安装了@babel/polyfill)。”

2) 我需要安装@babel/polyfill包并从require("@babel/polyfill");开始启动我的vendors.js吗?

您确实需要安装@babel/polyfill,它不是默认包含在Babel中。您必须将其包含在入口点中或在入口点顶部添加导入。

3) 如果我两者都省略了呢?

您将没有polyfills。


谢谢,现在我明白了。同时我已经阅读了babel-polyfill的文档,这部分非常有用:https://babeljs.io/docs/en/babel-polyfill#size - szegheo
当前关于此的文档:https://babeljs.io/docs/en/babel-polyfill#usage-in-node-browserify-webpack - CTS_AE
2
关于这个主题的语言相当混乱,最初似乎自相矛盾...一开始并不清楚的是,@babel/polyfill导入语句在你的入口点顶部确实是必要的,并且当使用useBuiltIns: 'entry'时,此语句会被自动替换为你在构建时需要导入的单个polyfills。 - Roman Scher
请注意,如果您将 useBuiltIns 设置为 "usage",则不再需要将 @babel/polyfill 添加到入口数组中。https://babeljs.io/docs/en/babel-polyfill#usage-in-node-browserify-webpack - Paul Razvan Berg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接