文章概览
本文主要内容包括:什么是babel-runtime、如何使用、使用场景与限制、如何结合babel-polyfill进行性能优化。
本文所有例子可以在 笔者的github 找到。
什么是babel-runtime
在文章《babel-polyfill使用与性能优化》中,笔者对babel-polyfill进行了介绍。
引入babel-polyfill会有一定副作用,比如:
- 引入了新的全局对象:比如Promise、WeakMap等。
- 修改现有的全局对象:比如修改了Array、String的原型链等。
在应用开发中,上述行为问题不大,基本可控。但如果在库、工具的开发中引入babel-polyfill,则会带来潜在的问题。
举个例子,我在项目中定义了跟规范不一致的Array.from()
函数(别管我为什么不一样,就是这么任性),同时引入了一个库(依赖babel-polyfill),此时,这个库可能覆盖了自定义的Array.from()
函数,导致出错。
这就是babel-runtime存在的原因。它将开发者依赖的全局内置对象等,抽取成单独的模块,并通过模块导入的方式引入,避免了对全局作用域的修改(污染)。
因此,如果是开发库、工具,可以考虑使用 babel-runtime。
入门例子
首先,安装依赖。babel-plugin-transform-runtime
用于构建过程的代码转换,babel-runtime
是实际导入项目代码的功能模块。
npm install babel-cli --save-dev
npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime
接着,创建 index.js。
// index.js
var promise = new Promise;
最后,运行 babel 转换代码,
`npm bin`/babel index.js
转换结果如下。没有用到全局的 Promise 对象,而是导入babel-runtime/core-js/promise
模块。
import _Promise from "babel-runtime/core-js/promise";
var promise = new _Promise();
技术实现细节
babel-plugin-transform-runtime 插件做了如下事情,下文分别举例说明。
- core-js aliasing:自动导入
babel-runtime/core-js
,并将全局静态方法、全局内置对象 映射到对应的模块。 - Helper aliasing:将内联的工具函数移除,改成通过
babel-runtime/helpers
模块进行导入,比如_classCallCheck
工具函数。 - Regenerator aliasing:如果你使用了 async/generator 函数,则自动导入
babel-runtime/regenerator
模块。
下面分别举例进行说明。
core-js aliasing
1、安装依赖。
npm install babel-cli --save-dev
npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime
2、创建index.js。
// index.js
var promise = new Promise;
var arr = Array.from('foo');
3、创建.babelrc。
{
"plugins": ["transform-runtime"]
}
4、运行转换命令。
`npm bin`/babel index.js
5、转换后的代码。
import _Array$from from 'babel-runtime/core-js/array/from';
import _Promise from 'babel-runtime/core-js/promise';
var promise = new _Promise();
var arr = _Array$from('foo');
helper aliasing
1、安装依赖
npm install --save-dev babel-cli
npm install --save-dev babel-plugin-transform-es2015-classes
npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime
2、创建index.js。
// index.js
class Person {}
3、创建.babelrc。
{
"plugins": [
"transform-es2015-classes",
"transform-runtime"
]
}
4、运行转换命令
`npm bin`/babel index.js
5、转码结果如下:
import _classCallCheck from "babel-runtime/helpers/classCallCheck";
let Person = function Person() {
_classCallCheck(this, Person);
};
regenerator-aliasing
1、安装依赖:
npm install --save-dev babel-cli
npm install --save-dev babel-plugin-transform-runtime
npm install --save-dev babel-plugin-transform-regenerator
2、创建index.js。
// index.js
function * run () {}
3、创建.babelrc。
{
"plugins": [
"transform-regenerator",
"transform-runtime"
]
}
4、运行转换命令。
`npm bin`/babel index.js
5、转码结果如下。
import _regeneratorRuntime from "babel-runtime/regenerator";
var _marked = /*#__PURE__*/_regeneratorRuntime.mark(run);
function run() {
return _regeneratorRuntime.wrap(function run$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}, _marked, this);
}
性能优化
前面章节提到,babel-plugin-transform-runtime 主要做了三件事情:core-js aliasing、Helper aliasing、Regenerator aliasing。
它们都可以通过配置进行开关,默认配置如下:
{
"plugins": [
["transform-runtime", {
"helpers": true,
"polyfill": true,
"regenerator": true,
"moduleName": "babel-runtime"
}]
]
}
还是前面的代码:
// index.js
var promise = new Promise;
var arr = Array.from('foo');
默认配置下,使用 babel-plugin-transform-runtime 的转换结果如下。虽然避免了修改全局对象,但是也引入了不少冗余的导入代码。
import _Array$from from 'babel-runtime/core-js/array/from';
import _Promise from 'babel-runtime/core-js/promise';
var promise = new _Promise();
var arr = _Array$from('foo');
修改配置文件.babelrc,将 polyfill 配置参数设置为 false:
{
"plugins": [
["transform-runtime", {
"polyfill": false
}]
]
}
再看下转换结果:
var promise = new Promise();
var arr = Array.from('foo');
备注:实际项目中,记得自行引入polyfill。
使用场景与限制
babel-runtime一般用于两种场景:开发库/工具、移除冗余工具函数(helper function)。
因为它不会对实例方法进行修改(比如Array.prototype.includes()),因此,在这种场景下需要使用 babel-polyfill。