探究下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

本文章由javascript技术分享原创和收集

发表评论 (审核通过后显示评论):