@babel/preset-env
对于与结合useBuiltIns
使用的不同配置,我得到不同的输出@babel/transform-runtime
。我已阅读文档,但无法弄清楚最佳实践应该是什么。
例如,当我的目标浏览器列表包括 Edge 18 时, @babel/preset-env
withuseBuiltIns
将添加一个 polyfill 。string.replace
但是当我使用它时@babel/transform-runtime
,不会添加那个 polyfill。
所以,从这个问题开始:
Does `string.replace` need to be polyfilled for Edge 18?
我检查了caniuse.com,它显示它完全受支持 - 这意味着不需要 polyfill。
但是,根据 Manuel Beaudru 的博文core-js@3,babel and a look into the future
caniuse
,mdn
并且compat-table
是很好的教育资源,但并不是真正打算用作开发人员工具的数据源:仅compat-table
包含一组良好的 ES 相关数据,并且由 @babel/preset-env 使用,但它有一些限制
并进一步:
出于这个原因,我创建了这个
core-js-compat
包:它为不同的目标引擎提供了关于 core-js 模块的必要性的数据。使用时core-js@3
,@babel/preset-env
将使用该新包而不是compat-table.
所以我将我的目标浏览器传递给core-js-compat
它,它会输出所有需要的 polfills。如下图所示,很多字符串方法需要填充,主要是为了支持 Edge 18。
到目前为止,一切都很好。看起来string.replace
确实需要为 Edge 18 填充。
通天塔配置
第一种方法:@babel/preset-env
和useBuiltIns: 'usage'
当我使用useBuiltIns: 'usage'
从以下位置引入每个文件的 polyfill 时core-js
:
// babel.config.js
presets: [
[
'@babel/preset-env',
{
debug: false,
bugfixes: true,
useBuiltIns: 'usage',
corejs: { version: "3.6", proposals: true }
}
],
'@babel/preset-flow',
'@babel/preset-react'
],
什么时候debug: true
,Babel 说它会在我的PriceColumn.js
文件中添加以下 polyfill:
// Console output
[/price-column/PriceColumn.js] Added following core-js polyfills:
es.string.replace { "edge":"17", "firefox":"71", "ios":"12", "safari":"12" }
es.string.split { "edge":"17" }
web.dom-collections.iterator { "edge":"17", "ios":"12", "safari":"12" }
一个区别是它说es.string.replace
的是 target edge: 17
,而不是edge: 18
我们在core-js-compat
上面的输出中看到的 - 可能是我已经做过的事情,但现在没问题。
Babel 在转译PriceColumn.js
文件顶部添加的内容:
// PriceColumn.js
"use strict";
require("core-js/modules/es.string.replace");
require("core-js/modules/es.string.split");
require("core-js/modules/web.dom-collections.iterator");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
再说一次,到目前为止一切都很好。
第二种方法:@babel/runtime
和@babel/transform-runtime
根据core-js文档:
@babel/runtime
withcorejs: 3
选项简化了使用core-js-pure
.core-js
它自动将 JS 标准库中现代特性的使用替换为从没有全局命名空间污染的版本中导入
听起来不错——让我们试试吧!
注释掉useBuiltIns
并添加@babel/transform-runtime
插件配置:
// babel.config.js
presets: [
[
'@babel/preset-env',
{
debug: true,
// bugfixes: true,
// useBuiltIns: 'usage',
// corejs: { version: '3.6', proposals: true }
}
],
'@babel/preset-flow',
'@babel/preset-react'
],
plugins: [
[
'@babel/transform-runtime',
{
corejs: { version: 3, proposals: true },
version: '^7.8.3'
}
]
],
在控制台输出中,我看到:
Using polyfills: No polyfills were added, since the `useBuiltIns` option was not set.
检查添加到文件顶部的内容:
// PriceColumn.js
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _Object$defineProperty = require("@babel/runtime-corejs3/core-js/object/define-property");
_Object$defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/objectSpread2"));
var _map = _interopRequireDefault(require("@babel/runtime-corejs3/core-js/instance/map"));
因此,helpers
添加了不同的 - 但没有es.string.*
polyfills 的迹象。他们不再需要了吗?他们是不是已经被“帮手”带进来了?它看起来不像对象扩展和数组映射与填充字符串实例方法有任何关系,所以我认为没有。
最后
我最后一次尝试是结合这两种方法 - 并遵循建议:
a) 设置corejs
为@babel/preset-env
:
// babel.config.js
presets: [
[
'@babel/preset-env',
{
debug: true,
// bugfixes: true,
useBuiltIns: 'usage',
corejs: { version: '3.6', proposals: true }
}
],
'@babel/preset-flow',
'@babel/preset-react'
],
plugins: [
[
'@babel/transform-runtime',
{
// corejs: { version: 3, proposals: true },
version: '^7.8.3'
}
]
]
这是输出:
// PriceColumn.js
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
require("core-js/modules/es.string.replace");
require("core-js/modules/es.string.split");
require("core-js/modules/web.dom-collections.iterator");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
b) 设置corejs
为@babel/transform-runtime
:
- 与第二种方法相同(见上文)
比较不同方法的输出
仅使用useBuiltIns
:
- 引入所需的字符串 polyfill,但会污染全局命名空间。
仅使用@babel/runtime-transform
:
- 不引入任何字符串 polyfills,但引入了其他助手/polyfills ??,用于数组映射和对象传播
结合使用useBuiltIns
和@babel/transform-runtime
:
- 引入所需的字符串 polyfill,但会污染全局命名空间。
- 还引入了 Object spread polyfill(但不是 Array map polyfill)
- 从
@babel/runtime/helpers/objectSpread2
,而不是@babel/runtime-corejs3/helpers/objectSpread2
(运行时与运行时-corejs3)导入 - 可能是未引入 Array map polyfill 的原因??)
问题
哪一个(如果有的话)是正确的方法?
我猜@babel/preset-env
withuseBuiltIns
是最好的,因为它引入了 polyfills。
污染全局命名空间有什么缺点?这只是图书馆的问题吗?
结合@babel/transform-runtime
,我们还获得了一个用于对象传播的 polyfill(尽管@babel-preset-env
有corejs: { version: '3.6', proposals: true }
which should polyfill 提议,所以我不确定为什么不使用@babel/transform-runtime
插件就不能将它引入那里)
我们需要 Array#map polyfill 吗?