s

Runtime transform/runtime 转化器详解

Runtime transform 运行时编译es6
入口文件引用作为辅助和内建,自动添加垫片到你的当前代码模块而非全局

这个插件建议放在 library/tool中

注意:
实例方法,例如”foobar”.includes(“foo”)将不能够使用,因为它将修正内置的垫片。

为什么使用它 why
Babel对常用的函数使用非常小的辅助(内置的垫片比较少),例如_extend。默认情况下它将会添加到每个引用的文件。这种重复有时候是非常没必要的。特别是你的应用分散在很多文件中。

这是transform-runtime插件之所以产生的原因:所有的这些辅助(垫片)将会引用babel-runtime来避免编译时重复。runtime将会编译到你的build中。

另一个目的是,这个转换器为你的代码创建了一个沙盒环境。如果你使用babel-polyfill并且把它内置提供promise,set,map这样的对象或功能,他们将会污染全局环境。也许在一个应用中或者命令行工具中没问题,但是如果你的代码是个库,你想发布给其他人使用,因为使用的人可能在各种各样的执行环境中,所以可能导致错误,不能执行。

转换器transformer会将这些内置(垫片)设置别名到core-js中,因此你可以不使用require来无缝的使用(垫片中的对象和方法)。

如何生效和工作,请看技术细节

安装
注意:生产版本(Production) vs 开发版本(development)依赖

在大多数情况下,你需要安装babel-plugin-transform-runtime作为开发版本的依赖(设置–save-dev)。

1
2
<code>npm install --save-dev babel-plugin-transform-runtime</code>
并且babel-runtime作为生产版本依赖(设置 --save)
1
2
<code>npm install --save babel-runtime</code>
转换器插件一般只用在开发时,而里面的实际垫片(runtime itself)的代码在你部署或发布库时是需要放到其中的。

请看下面的例子

用法 通过.babelrc(推荐)
把下面的代码添加到你的babelrc文件中(这里说的是两种情况):

默认设置选项时的写法

1
2
3
<code>{
"plugins": ["transform-runtime"]
}</code>

使用自己设置设置

1
2
3
4
5
6
7
8
9
10
<code>{
"plugins": [
["transform-runtime", {
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}]
]
}</code>

通过命令行(CLI)

1
<code>babel --plugins transform-runtime script.js</code>

通过Node 接口 (Node API)

1
2
3
<code>require("babel-core").transform("code",{
plugins:["transform-runtime"]
})</code>

选项/设置 辅助(helpers)
默认值是:true

表示是否开启内联的babel helpers(即babel或者环境本来的存在的垫片或者某些对象方法函数)(clasCallCheck,extends,etc)在调用模块名字(moduleName)时将被替换名字。

查看详情

垫片/polyfill
默认值是:true

表示是否把内置的东西(Promise,Set,Map,tec)转换成非全局污染垫片。
查看详情

重新生成/regenerator
默认值是:true

是否开启generator函数转换成使用regenerator runtime来避免污染全局域。

查看详情

模块名字/moduleName
默认值:babel-runtime

当调用辅助(内置垫片)设置模块(module)名字/路径.

例子:
json

1
2
3
<code>{
"moduleName": "flavortown/runtime"
}</code>

javascript

1
<code>import extends from 'flavortown/runtime/helpers/extends';</code>

技术细节/Techincal details
runtime转换器插件主要做了三件事:

当你使用generators/async方法、函数时自动调用babel-runtime/regenerator

当你使用ES6 的Map或者内置的东西时自动调用babel-runtime/core-js

移除内联babel helpers并替换使用babel-runtime/helpers来替换

总的来说一句话,你可以使用内置的一些东西例如Promise,Set,Symbol等,就像使用无缝的使用polyfill,来使用babel 特性,并且无全局污染、极高代码库适用性。

再生器别名 Regenerator aliasing
无论你什么时候使用generator函数或者异步函数(async function).

1
2
3
<code>function* foo(){
}</code>

下面的将被生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
<code>"use strict";
var _marked = [foo].map(regeneratorRuntime.mark);
function foo() {
return regeneratorRuntime.wrap(function foo$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}, _marked[0], this);
}</code>

这种是不太理想的。因为你regenerator运行时会污染全局域的。
作为替代你需要runtime转换器来编译成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<code>"use strict";
var _regenerator = require("babel-runtime/regenerator");
var _regenerator2 = _interopRequireDefault(_regenerator);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var _marked = [foo].map(_regenerator2.default.mark);
function foo() {
return regeneratorRuntime.wrap(function foo$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}, _marked[0], this);
}</code>

这意味着在使用regenerator时不会污染当前的全局环境。

core-js的别名化/core-js aliasing
有时你想去使用内置的的东西(Promise,Set,Map,etc)。通常情况下你会使用一个全局的垫片。
runtime转换器所做的是转换成如下:

1
2
3
4
5
<code>var sym = Symbol();
var promise = new Promise;
console.log(arr[Symbol.iterator]());</code>

添加到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<code>"use strict";
var _getIterator2 = require("babel-runtime/core-js/get-iterator");
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _promise = require("babel-runtime/core-js/promise");
var _promise2 = _interopRequireDefault(_promise);
var _symbol = require("babel-runtime/core-js/symbol");
var _symbol2 = _interopRequireDefault(_symbol);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var sym = (0, _symbol2.default)();
var promise = new _promise2.default();
console.log((0, _getIterator3.default)(arr));</code>

这意味着你可以无缝的使用本地内置的方法而不用考虑是来自垫片还是本地。。
警告,实例方法将不能使用,例如”foobar”.includes(‘foo’)

辅助重命名 / Helper aliasing
通常babel会把辅助放在文件的顶部做一些常用任务来避免重复导入。
有时这些辅助的体积有点大并且不需要的没有用的东西也在其中。runtime转换器把所有的辅助转换到一个模块中(按他的意思是说只是把用到的转换到其中)。

如下演示:

1
2
<code>class Person {
}</code>

一般的转化成(即不是用runtime):

1
2
3
4
5
6
7
<code>"use strict";
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Person = function Person() {
_classCallCheck(this, Person);
};</code>

runtime转化器转化成:

1
2
3
4
5
6
7
8
9
10
11
12
<code>"use strict";
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck");
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Person = function Person() {
(0, _classCallCheck3.default)(this, Person);
};</code>