`@babel/preset-env`+`useBuiltIns`+`@babel/runtime`+`Browserlistrc`的最佳实践是什么
useBuiltIns
与@babel/transform-runtime
结合使用时,@babel/preset-env
的不同配置得到不同的输出。我已阅读文档,但无法确定最佳做法应该是什么。
例如,当我的目标浏览器列表包括Edge 18时,@babel/preset-env
WITHuseBuiltIns
将为string.replace
添加一个多边形填充。
但是当我改用@babel/transform-runtime
时,不会添加该填充。
那么,从这个问题开始:
Does `string.replace` need to be polyfilled for Edge 18?
我检查了caniuse.com,结果显示它完全受支持-这意味着不需要填充。
然而,根据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
,它输出所需的所有策略填充。正如您在下图中看到的,相当多的字符串方法需要进行多填充,主要是为了支持Edge 18。
到目前为止,一切顺利。看起来string.replace
是否需要为边缘18多填充。
巴别塔配置
第一种方法:@babel/preset-env
和useBuiltIns: 'usage'
当我使用useBuiltIns: 'usage'
从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
文件中:
// 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.*
多重填充的迹象。它们不再是必需的了吗?他们已经被"帮手"带进来了吗?看起来对象扩散和数组映射与多填充字符串实例方法没有任何关系,所以我认为没有关系。
最终
我的上一次尝试是将两种方法结合起来-并遵循recommendations:
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"));
b)为@babel/transform-runtime
设置corejs
:
- 与第二种方法相同(见上文)
比较不同方法的输出
仅使用useBuiltIns
:
- 引入所需的字符串多填充,但会污染全局命名空间。
仅使用@babel/runtime-transform
:
- 不引入任何字符串多边形填充,但为数组贴图和对象扩散引入其他辅助对象/多边形填充??
同时使用useBuiltIns
和@babel/transform-runtime
:
- 引入所需的字符串多填充,但会污染全局命名空间。
- 还会引入对象扩散多边形填充(而不是数组贴图多边形填充)
- 从
@babel/runtime/helpers/objectSpread2
导入,而不是@babel/runtime-corejs3/helpers/objectSpread2
(运行时vs运行时-corejs3)-可能是未引入数组贴图多边形填充的原因??)
问题
以下哪种(如果有)是正确的方法?
我猜@babel/preset-env
和useBuiltIns
是最好的,因为它引入了多边形填充。
与@babel/transform-runtime
结合使用,我们还会获得对象展开的多边形填充(尽管@babel-preset-env
有corejs: { version: '3.6', proposals: true }
应该是多边形填充建议,所以我不确定为什么不使用@babel/transform-runtime
插件就不将其引入其中)
是否需要Array#贴图多边形填充?
解决方案
建议https://www.jmarkoski.com/understanding-babel-preset-env-and-transform-runtime:
应用程序:如果您正在创作应用程序,请在应用程序的顶部使用import‘core-js,useBuiltIns设置为Entry,@Babel/Transform-Runtime仅用于助手(@babel/runtime作为依赖项)。这样你污染了全球环境,但你不在乎,这是你的应用程序。您将受益于应用程序顶部包含的别名为@babel/run和PolyFill的帮助器。这样,您也不需要处理NODE_MODULES(除非依赖项使用了必须转换的语法),因为如果某些依赖项使用了需要多边形填充的功能,则您已经在应用程序的顶部包含了该多边形填充。
库:如果您正在创作库,请仅使用带有corejs选项的@babel/Transform-runtime加上@babel/run-corejs3作为依赖项,并使用@babel/preset-env进行带有useBuiltIns:false的语法转换。此外,我还将传输我将从node_module使用的包。为此,您将需要设置AbsoluteRuntime选项(https://babeljs.io/docs/en/babel-plugin-transform-runtime#absoluteruntime)以从单个位置解析运行时依赖项,因为@babel/Transform-Runtime直接从@babel/run-corejs3导入,但这仅在@babel/run-corejs3位于正在编译的文件的node_module中时才有效。
更多信息:
- https://github.com/zloirock/core-js/issues/848
- https://github.com/zloirock/core-js/issues/833
- https://babeljs.io/docs/en/babel-plugin-transform-runtime
相关文章