我正在参加「掘金·启航计划」
说到 @babel/plugin-transform-runtime
真是熟悉又陌生,经常在 Babel 配置里看到,问它做了什么,却又答不上来,今天通过两个例子,一起实践下。
引用下 官方 的描述:
A plugin that enables the re-use of Babel's injected helper code to save on codesize.
译:一个插件,可以复用 Babel 注入的辅助代码,以节省代码大小。
看起来说明白了,但又不那么清楚。下面我们一起动手实践下,看看它到底做了什么。
功能一:自动引入辅助函数
首先创建一个源文件
export class D {
d = 0;
constructor() {
this.d = 111;
}
}
使用 @babel/preset-env
转换
简单提一下,
@babel/preset-env
是一大堆插件的集合,包含了当前浏览器环境下,所有语言特性的插件,可以根据 browserList 的结果,选择合适的插件将新语言特性转译成旧浏览器可以支持的表达方式。
/** ---------------- babel.config.js --------------- */
module.exports = {
presets: ['@babel/preset-env']
};
/** -------------------- 转换后的文件 ----------------------- */
function _classCallCheck(instance, Constructor) {
/** xxx */
}
function _defineProperties(target, props) {
/** xxx */
}
function _createClass(Constructor, protoProps, staticProps) {
/** xxx */
}
var D = /*#__PURE__*/ _createClass(function D() {
_classCallCheck(this, D);
this.d = 0;
this.d = 111;
});
export { D };
我们可以看到 @babel/preset-env
在处理语法转换时会注入很多辅助函数(_classCallCheck、_createClass
等),如果项目文件很多,会导致体积十分庞大
为了解决这个问题,@babel/runtime
出现了,它将这些辅助函数整合到了一起,我们可以通过包来复用这些代码。
var _classCallCheck = require('@babel/runtime/helpers/classCallCheck');
var _defineProperties = require('@babel/runtime/helpers/defineProperty');
/** xxx */
这样解决了代码复用的问题,但是每次手动引入过于麻烦,于是 @babel/plugin-transform-runtime
登场。
module.exports = {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
};
/** -------------------- 转换后的文件 ----------------------- */
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault');
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.D = void 0;
/** ⚠️ 注意看这里 */
var _createClass2 = _interopRequireDefault(
require('@babel/runtime/helpers/createClass')
);
var _classCallCheck2 = _interopRequireDefault(
require('@babel/runtime/helpers/classCallCheck')
);
var _defineProperty2 = _interopRequireDefault(
require('@babel/runtime/helpers/defineProperty')
);
var D = /*#__PURE__*/ (0, _createClass2.default)(function D() {
(0, _classCallCheck2.default)(this, D);
(0, _defineProperty2.default)(this, 'd', 0);
this.d = 111;
});
exports.D = D;
功能二:为类库打包增加 Polyfill
在开发类库的时候,也会用到一些新语法,需要有对应的 Polyfill,但是如果项目中不存在该怎么办呢?我们又不能在组件层注入全局 Polyfill (不想组件影响项目)
因此 @babel/plugin-transform-runtime
提供了局部 Polyfill 的方法。
创建源文件
export const a = new Promise((resolve, reject) => {
resolve(true);
});
export async function asyncFn() {
await a;
}
按照默认配置进行代码转换
/** ---------------- babel.config.js --------------- */
module.exports = {
presets: ['@babel/preset-env'],
plugins: ['@babel/plugin-transform-runtime']
};
/** -------------------- 转换后的文件 ----------------------- */
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault');
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.a = void 0;
exports.asyncFn = asyncFn;
var _regenerator = _interopRequireDefault(
require('@babel/runtime/regenerator')
);
var _asyncToGenerator2 = _interopRequireDefault(
require('@babel/runtime/helpers/asyncToGenerator')
);
/** ⚠️ 主意看这行 */
var a = new Promise(function (resolve, reject) {
resolve(true);
});
exports.a = a;
function asyncFn() {
/** xxx */
}
根据转换后的代码可以发现,Promise
仍然用的全局的,也就是项目中必须注入 Polyfill,否则类库会出错。
我们修改下配置,通过设置 core-js 来转换 (core-js 可以配置多种, 我们这里使用 version: 3
详见 官方文档)
/** ---------------- babel.config.js --------------- */
module.exports = {
presets: ['@babel/preset-env'],
plugins: [['@babel/plugin-transform-runtime', { corejs: 3 }]]
};
/** -------------------- 输出结果 ----------------------- */
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
var _interopRequireDefault = require('@babel/runtime-corejs3/helpers/interopRequireDefault');
_Object$defineProperty(exports, '__esModule', {
value: true
});
exports.a = void 0;
exports.asyncFn = asyncFn;
var _regenerator = _interopRequireDefault(
require('@babel/runtime-corejs3/regenerator')
);
var _asyncToGenerator2 = _interopRequireDefault(
require('@babel/runtime-corejs3/helpers/asyncToGenerator')
);
var _promise = _interopRequireDefault(
require('@babel/runtime-corejs3/core-js-stable/promise')
);
var a = new _promise.default(function (resolve, reject) {
resolve(true);
});
exports.a = a;
function asyncFn() {
/** xxx */
}
可以看到,现在转换后的 Promise 是一个从 @babel/runtime-corejs3/core-js-stable/promise
导入的局部变量
总结
- 删除内联的辅助函数,并自动从
@babel/runtime/helpers
中引入,以节省代码大小。 - 以局部变量的方式在 core-js 中引入 Polyfill,
@babel/plugin-transform-runtime
引入的 Polyfill 不会对全局造成污染,所以很适合作为类库的打包。