当我在使用@babel/preset-env
和useBuiltIns
与@babel/transform-runtime
结合使用时,会得到不同的输出结果。我已经阅读了文档,但还没有找出最佳实践应该是什么。
例如,当我的目标浏览器列表包括Edge 18时,@babel/preset-env
与useBuiltIns
会为string.replace
添加一个polyfill。
但是,当我改用@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
,并输出了所有所需的polyfill。如下图所示,需要为许多字符串方法提供polyfill,大多数是为了支持Edge 18。
到目前为止,一切都好。看起来对于Edge 18,确实需要对string.replace
进行polyfill。
Babel配置
第一种方法:@babel/preset-env
和useBuiltIns: 'usage'
当我使用useBuiltIns: 'usage'
从core-js
中带入每个文件的polyfills时:
// 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
文件中添加以下 polyfills:
// 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
是针对 edge: 17
而不是我们在上面从 core-js-compat
中看到的 edge: 18
- 可能是我做的什么,但现在没关系。
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
选项使用corejs: 3
可以简化与core-js-pure
的工作。它会自动将 JS 标准库中的现代特性替换为来自未污染全局命名空间的core-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.*
的拼写补丁。它们不再需要了吗?它们已经被“helpers”带来了吗?看起来对象扩展和数组映射与多填充字符串实例方法没有任何关系,所以我认为不是。
最后
我的最后尝试是结合这两种方法,并遵循建议:
a) 为@babel/preset-env
设置corejs
:
// 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"));
The recommended approach is to use the
@babel/preset-env
with useBuiltIns
option to bring in the required polyfills while minimizing global namespace pollution. Polluting the global namespace can cause issues for libraries, but may not be a problem for standalone applications. The combination of useBuiltIns
and @babel/transform-runtime
also provides a polyfill for object spread, but if the Array#map polyfill is needed will depend on the specific requirements of the application.
absoluteRuntime
吗?如果你把一个有着绝对路径的库发布到 npm 上,那么它将无法正常运行。你的意思是针对那些在发布之前被打包的库吗? - loganfsmythabsoluteRuntime
,所以似乎库点需要一些注意事项。 - loganfsmyth