探究下babel-preset-env和babel-plugin-transform-runtime的使用
本文主要讲 @babel/preset-env的useBuiltIns 和 @babel/plugin-transform-runtime 的使用。
不会讲其余内容。
@babel/preset-env
@babel/preset-env 是一个非常强大的预设,可以帮助我们对JavaScript代码进行语法转换和设置polyfills(如果目标环境需要的话)。
useBuiltIns
这个配置项告诉 @babel/preset-env如何处理 polyfills。它有三个值,分别是 "usage" | "entry" | false, 默认是 false。
当useBuiltIns的值为:"usage"|"entry"时,需要指定corejs(自从babel 7.4.0后,@babel/polyfill 被认为过时了)。
corejs 有个两个选择, core-js@3和core-js@2。两者的区别是:core-js@2仅支持全局变量(如:Promise)和静态属性(如:Array.from), core-js@3还支持实例属性(如:[].includes)
1.当值为entry
需要在一个入口js文件顶部,手动添加如下代码:
// entry.js
import "core-js";
然后使用babel编译下,输出结果可能如下:
"use strict";
require("core-js/modules/es.symbol");
require("core-js/modules/es.symbol.description");
require("core-js/modules/es.symbol.async-iterator");
// 此处省略n个省略号
babel会根据 @babel/env 的target配置,将目标环境不支持的polyfill一次性全部引进来。不管代码有没有用到,只要目标环境不支持,就 require 进来。
2.当值为"usage"
这个配置下,babel会按需引入polyfill到每个文件中。意思是,只有需要用到某个polyfill时,才会require对应的polyfill。
注意:一个文件只会require一次相同的polyfill
看下面这个例子:
// a.js
var a = Promise.resolve();
var b = Promise.resolve();
// @babel/env 配置如下:
[
"@babel/env",
{
"targets": {
"ie": 9
},
"useBuiltIns": "usage",
"corejs": 3
}
]
babel输出结果如下:
"use strict";
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
var a = Promise.resolve();
var b = Promise.resolve();
3.当值为false
babel不会自动添加polyfills,也不会转换import "core-js" 和
import "@babel/polyfill"
@babel/plugin-transform-runtime
为什么要使用 @babel/plugin-transform-runtime?
有下面两个原因:
默认情况下,babel会在需要的文件中插入许多小的帮助方法。当项目中存在多个文件中,这种小的帮助方法可能会重复。这是没有必要的。@babel/plugin-transform-runtime会将所有帮助函数,引用自 @babel/runtime,从而避免了帮助函数重复出现在了编译后的代码中。
如果直接import core-js, 其内置的诸如Promise,Map,Set会污染全局变量。@babel/plugin-transform-runtime 会创建一个沙箱环境,避免全局变量污染。
看一下不使用@babel/plugin-transform-runtime的编译结果
// a.js
var a = async function () {};
// b.js
var b = async function () {};
// babel配置如下:
{
"presets": [
[
"@babel/env",
{
"targets": {
"ie": 9
},
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
babel编译后输出如下:
// a.js
"use strict";
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
require("regenerator-runtime/runtime");
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
var a = /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function a() {
return _ref.apply(this, arguments);
};
}();
// b.js
"use strict";
require("core-js/modules/es.object.to-string");
require("core-js/modules/es.promise");
require("regenerator-runtime/runtime");
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
var b = /*#__PURE__*/function () {
var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function a() {
return _ref.apply(this, arguments);
};
}();
从上面的输出结果中可以看出:asyncGeneratorStep 和 _asyncToGenerator 两个帮助函数代码重复了。
看下使用@babel/plugin-transform-runtime的编译结果
// a.js
var a = async function () {};
// b.js
var b = async function () {};
// babel配置如下:
{
"presets": [
[
"@babel/env",
{
"targets": {
"ie": 9
}
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
babel的编译结果如下:
// a.js
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/asyncToGenerator"));
var a = /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function a() {
return _ref.apply(this, arguments);
};
}();
// b.js
"use strict";
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _regenerator = _interopRequireDefault(require("@babel/runtime-corejs3/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/asyncToGenerator"));
var b = /*#__PURE__*/function () {
var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
case "end":
return _context.stop();
}
}
}, _callee);
}));
return function b() {
return _ref.apply(this, arguments);
};
}();
从上面的编译结果可以看出,使用 @babel/plugin-transform-runtime 编译后,重复的代码更少了。
总结:
推荐配置类似这样:
{
"presets": [
[
"@babel/env",
{
"targets": {
"ie": 9
}
}
]
],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"corejs": 3
}
]
]
}
这样的配置,既可以转换es6及以上的语法,又能添加polyfill, 还不会污染全局环境,还能避免了重复注入相同的帮助函数。
优点简直不要太多。
推荐下个人公众号:
qrcode_for_gh_0af70036b598_258.jpg
发表评论 (审核通过后显示评论):