@babel/plugin-transform-runtime 有什么用

@babel/plugin-transform-runtime 有什么用

用于解决两个问题:

  1. 避免在多文件重复输出helper方法造成冗余,使helper方法变成引用公共依赖 @babel/runtime-corejs3
  2. babel会将编译前代码中的ES新特性进行全局代理,从而实现polyfill。当我们在写一个独立工具库依赖给到业务应用使用的时候,这时独立工具库中全局代理代码,就会影响到业务应用的代码了,比如工具库和业务应用里,都对Array.prototype.includes进行了不一样了代理; @babel/plugin-transform-runtime会把polyfill再进行一个沙箱处理,从而避免相互影响。

babel转义代码分两步,一个是语法转义,一个是api转义;

简单的语法转义比如const -> var , 但是复杂的语法转义还需要借助babel的helper方法。比如例子代码:

js 复制代码
class Classes {
    constructor(){}
    fn(){}
}

会转义为:

js 复制代码
"use strict";

function _classCallCheck(instance, Constructor) { //... }
function _createClass(Constructor, protoProps, staticProps) { //... }
// 省略N行
var Classes = /*#__PURE__*/function () {
  function Classes() {
    _classCallCheck(this, Classes);
  }
  _createClass(Classes, [{
    key: "fn",
    value: function fn() {}
  }]);
  return Classes;
}();

其中_createClass 就是babelhelper方法,会输入到对应的编译好的文件中;那么就会有个问题,假如100个文件,里面都用了class语法,就会导致所有的文件都会输入helper方法,当跑在同一个应用时,这100个文件就会产生冗余重复99次helper方法。而用了@babel/plugin-transform-runtime就可以把helper指向公共依赖@babel/runtime-corejs3/helpers/xxx方法,减少转码后的文件大小。当配置babel plugin 加上@babel/plugin-transform-runtime,编译结果就或变为:

js 复制代码
"use strict";
  
var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime-corejs3/helpers/createClass"));

var Foo = /*#__PURE__*/function () {
  function Foo() {
    (0, _classCallCheck2["default"])(this, Foo);
  }
  (0, _createClass2["default"])(Foo, [{
    key: "saySth",
    value: function saySth() {}
  }]);
  return Foo;
}();

babel 配置:

js 复制代码
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        useBuiltIns: "usage",
        "corejs": 3
      },
    ]
  ],
  "plugins": [
    [
      "@babel/plugin-transform-runtime",
      {
        "corejs": 3 // 指定 runtime-corejs 的版本,目前有 2 3 两个版本
      }
    ]
  ]
};

再说babel解决的另一个问题,babel会引用corejs对ES特性进行polyfill,比如以下代码会被处理:

js 复制代码
const arr = [1,2,3,4];
const flag = arr.includes(2);

以上为例子1

处理为:

js 复制代码
"use strict";

require("core-js/modules/es.array.includes.js");
var arr = [1, 2, 3, 4];
var flag = arr.includes(2);

我们看一下core-js/modules/es.array.includes.js

js 复制代码
'use strict';
var $ = require('../internals/export');
var $includes = require('../internals/array-includes').includes;
var fails = require('../internals/fails');
var addToUnscopables = require('../internals/add-to-unscopables');

// FF99+ bug
var BROKEN_ON_SPARSE = fails(function () {
  // eslint-disable-next-line es/no-array-prototype-includes -- detection
  return !Array(1).includes();
});

// `Array.prototype.includes` method
// https://tc39.es/ecma262/#sec-array.prototype.includes
$({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE }, {
  includes: function includes(el /* , fromIndex = 0 */) {
    return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
  }
});

// https://tc39.es/ecma262/#sec-array.prototype-@@unscopables
addToUnscopables('includes');

代码其实很简单,大致就是对Array.prototype.includes 通过definePrototy等方法进行定义polyfill。这里会改动到Array的原型。

这里做个实验,把编译后的代码和core-js/modules/es.array.includes.js中includes改为includes1,确定core-js/modules/es.array.includes.js是定义了原型:

js 复制代码
// test.js
require("core-js/modules/es.array.includes.js");
var arr = [1, 2, 3, 4];
var flag = arr.includes1(2);
console.log(flag); // true
console.log(Array.prototype.includes1); // [Function: includes1]

// core-js/modules/es.array.includes.js
// ...
$({ target: 'Array', proto: true, forced: BROKEN_ON_SPARSE }, {
  includes1: function aincludes(el /* , fromIndex = 0 */) {
    console.log(11111111111); // 111111111
    return $includes(this, el, arguments.length > 1 ? arguments[1] : undefined);
  }
});
// ...

无论任何环境原生情况都是没有Array.prototype.includes1的,执行test.js顺利打印出es.array.includes.js中includes1定义,证明babel通过对原型属性拦截进行polyfill。

在单次编译里面可以认为改对象原型是没问题的,但是如果这次编译的结果被业务应用使用到了,并且业务应用也有对对象原型相同的属性的修改,这是就会冲突了。那babel是如何解决这个问题的呢?

通过@babel/plugin-transform-runtime会把polyfill改为从@babel/runtime-corejs3中获取,并且原本includes写法改为另一种形式,从而避免污染Array方法;

js 复制代码
"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs3/helpers/interopRequireDefault");
var _includes = _interopRequireDefault(require("@babel/runtime-corejs3/core-js-stable/instance/includes"));
var arr = [1, 2, 3, 4];
var flag = (0, _includes["default"])(arr).call(arr, 2);

参考文档

相关推荐
憧憬成为web高手4 小时前
ACTF 12307复现
前端·bootstrap·html
wordbaby5 小时前
Axios 上传大文件崩溃:鸿蒙 RNOH 下 XHR 返回空响应头引发的"假失败"
前端·react native
wordbaby5 小时前
React Native 列表分页实战:下拉刷新与上拉加载的工程化方案
前端·react native
wordbaby6 小时前
脱离 Tab 栏的艺术:React Native 全屏子页面的导航架构实践
前端·react native·harmonyos
陈随易6 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
wordbaby6 小时前
React Native 新架构落地鸿蒙:跨三端政务级应用的工程实践与深度复盘
前端·react native·harmonyos
excel8 小时前
为什么我推荐使用 Termius:现代 SSH 工具的完整体验
前端·后端
ZC跨境爬虫8 小时前
模块化烹饪小程序开发日记 Day7:(菜谱详情接口开发与JSON数据读取全流程)
前端·javascript·css·ui·微信小程序·json
এ慕ོ冬℘゜8 小时前
JS 前端基础面试题
开发语言·前端·javascript
LaughingZhu8 小时前
Product Hunt 每日热榜 | 2026-05-25
前端·人工智能·经验分享·chatgpt·html