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

Confused about useBuiltIns option of @babel/preset-env (using Browserslist Integration)

我正在使用 Babel 7 和 Webpack 4 开发一个 Web 项目。我以前从未使用过 Babel,所以无法真正理解它的某些部分。基于 documentation 我正在使用 @babel/preset-env 因为它似乎是推荐的方式(特别是对于初学者)。还通过我的 .browserslistrc 文件使用 Browserslist 集成。

Webpack 编译得很好(babel-loader 版本 8.0.2),我没有错误,但我对此感到困惑 useBuiltIns: "entry" option mentioned here 以及如何 polyfill 系统正在 Babel 中运行。

.babelrc.js

module.exports = {
  presets: [
    ['@babel/preset-env', {
      "useBuiltIns": "entry" // do I need this?
    }]
  ],
  plugins: [
    '@babel/plugin-syntax-dynamic-import'
  ]
};

.browserslistrc
复制自 here(认为合理,因为我的项目正在使用 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 默认处理所有重写和 polyfill,我这边不需要任何额外的 import/require...

谢谢!

-- 编辑--

Babel 的团队刚刚 updated the docs of @babel/polyfill 基于一些 GitHub 问题(包括我的)抱怨 unclear/misleading 文档。现在很明显如何使用它。 (......之后我原来的问题似乎很愚蠢:)

1) Do I need to use that useBuiltIns: "entry" option?

是的,根据 babel 文档:

"This option enables a new plugin that replaces the statement import "@babel/polyfill" 或 require("@babel/polyfill") 以及基于环境的@babel/polyfill 的个人需求" - 基本上,包括所有需要的 polyfill (当你安装了@babel/polyfill需要的时候)。

2) Do I need to install @babel/polyfill package and start my vendors.js with require("@babel/polyfill"); ?

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

3) What if I omit both?

你不会有 polyfills。

1) Do I need to use that useBuiltIns: "entry" option?

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

TL;DR

useBuiltIns基本上有3个选项:

"entry":使用此选项时,@babel/preset-envcore-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":在这种情况下,当目标环境不支持使用某些功能时,将自动添加 polyfill。所以:

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 或再生器),因为只会根据浏览器列表中设置的目标环境自动添加所需的 polyfill。


false: 这是没有自动添加 polyfill 时的默认值。


2) Do I need to install @babel/polyfill package and start my vendors.js with require("@babel/polyfill"); ?

babel v7.4core-js v3 之前的环境。

TL;DR

没有。从 babel v7.4core-js v3 开始(用于底层填充)@babel/preset-env 将仅在知道需要哪些填充并且按照推荐的顺序添加填充。

此外,@babel/polyfill 被认为已弃用,取而代之的是单独包含 core-jsregenerator-runtime

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

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


3) What if I omit both?

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


可以在 core-js creator's page

找到更详细和完整的信息

也请随意玩babel sandbox