如何区分 babel polyfill 和 transform-runtime

官方文档上

Runtime transform

Externalise references to helpers and builtins, automatically polyfilling your code without polluting globals

从最终的行为来解释就是说babel引入了helper工具函数自动来执行polyfill并且不污染全局作用于,采用require的方式。

This plugin is recommended in a library/tool.

推荐在工具库中使用。

NOTE: Instance methods such as “foobar”.includes(“foo”) will not work since that would require modification of existing built-ins (Use babel-polyfill for that).

同时该插件并不会转换诸如数组的includes方法

polyfill

This will emulate a full ES2015+ environment and is intended to be used in an application rather than a library/tool. This polyfill is automatically loaded when using babel-node

polyfill 本质上就是一个降级方案,它作用在全局,将你的ES6语法做转换。

差异

  • 都做转换
  • 但是polyfill转换的东西更多更全面
  • 而runtime仅仅转换一些语法,类似数组的API是不做转换的
  • polyfill作用在全局
  • 而runtime则是通过引用模块的方式来实现
  • 那些需要修改内置api才能达成的功能,譬如:扩展String.prototype,给上面增加includes方法,就属于修改内置API的范畴,这是polyfill来做的
不使用transform-runtime转换async/await
"use strict";

function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }

_asyncToGenerator(regeneratorRuntime.mark(function _callee() {
    return regeneratorRuntime.wrap(function _callee$(_context) {
        while (1) {
            switch (_context.prev = _context.next) {
                case 0:
                    _context.next = 2;
                    return loadStory();

                case 2:
                    console.log("Yey, story successfully loaded!");

                case 3:
                case "end":
                    return _context.stop();
            }
        }
    }, _callee, this);
}))();
使用transform-runtime 转换async/await
"use strict";

var _regenerator = require("babel-runtime/regenerator");

var _regenerator2 = _interopRequireDefault(_regenerator);

var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");

var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

(0, _asyncToGenerator3.default)(_regenerator2.default.mark(function _callee() {
    return _regenerator2.default.wrap(function _callee$(_context) {
        while (1) {
            switch (_context.prev = _context.next) {
                case 0:
                    _context.next = 2;
                    return loadStory();

                case 2:
                    console.log("Yey, story successfully loaded!");

                case 3:
                case "end":
                    return _context.stop();
            }
        }
    }, _callee, this);
}))();

这里可以看到两者的区别在于,使用了transform-runtime 之后 babel会自动引入模块的方式来实现es5的写法,可以看出是利用了babel的工具函数,工具函数中把Promise都实现了一遍。

而不用 transform-runtime 的时候,仅仅是使用 Promise 来实现 async/await 但是并未考虑对 Promise 做转换。

总结:

  • 具体项目还是需要使用 babel-polyfill,只使用 babel-runtime 的话,实例方法不能正常工作(例如 “foobar”.includes(“foo”))。
  • JavaScript 库和工具可以使用 babel-runtime,在实际项目中使用这些库和工具,需要该项目本身提供 polyfill。
  • 单独的库如果仅仅是转换ES6语法,那么也可以不使用runtime,babel本身就是会自带这部分的转换的。