Babel 进阶二

2022-04-02  本文已影响0人  _于曼丽_

参考文档

@babel/plugin-transform-runtime 插件用来替换内联辅助函数,替换全局 API,引入 regeneratorRuntime 函数。
@babel/runtime 工具包提供内联辅助函数,引入 regeneratorRuntime 函数。
@babel/runtime-corejs2 工具包提供内联辅助函数,提供非全局的 core-js2 版本的 API,引入 regeneratorRuntime 函数。
@babel/runtime-corejs3 工具包提供内联辅助函数,提供非全局的 core-js3 版本的 API,引入 regeneratorRuntime 函数。
@babel/runtime@babel/runtime-corejs2@babel/runtime-corejs3 这三个工具包是用来配合 @babel/plugin-transform-runtime 插件使用的,@babel/plugin-transform-runtime 插件根据配置会自动调用这三个工具包。
通常根据需要安装其中一个工具包即可。

@babel/plugin-transform-runtime

@babel/plugin-transform-runtime 插件有三个作用:

  1. 替换内联辅助函数
  2. 替换全局 API
  3. 引入 regeneratorRuntime 函数

替换内联辅助函数

参考文档

在 Babel 在使用 @babel/preset-env 进行语法转换的时候(不是补充 API),常常会注入一些辅助函数。例如转换 ES6 的 Class 语法的时候:

配置文件:

const presets = ['@babel/preset-env']
const plugins = []

module.exports = {
  presets,
  plugins
}

转换前:

class Person {
  sayname() {
    return 'name'
  }
}
var john = new Person()
console.log(john)

转换后:

"use strict";

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

var Person = /*#__PURE__*/function () {
  function Person() {
    _classCallCheck(this, Person);
  }

  _createClass(Person, [{
    key: "sayname",
    value: function sayname() {
      return 'name';
    }
  }]);

  return Person;
}();

var john = new Person();
console.log(john);

可以看到转换后的代码上面增加了好几个函数声明,这就是注入的函数,我们称之为辅助函数。

在我们正常的前端工程开发的时候,少则几十个js文件,多则上千个。如果每个文件里都使用了class类语法,那会导致每个转换后的文件上部都会注入这些相同的函数声明。这会导致我们用构建工具打包出来的包非常大。

我们把这些辅助函数声明都放在一个npm包里,需要使用的时候直接从这个包里引入到我们的文件里。这样即使上千个文件,也会从相同的包里引用这些函数。通过webpack这一类的构建工具打包的时候,我们只会把使用到的npm包里的函数引入一次,这样就做到了复用,减少了体积。

@babel/runtime/helpers 包提供辅助函数,安装 @babel/preset-env 的时候会自动安装 @babel/runtime,不过在项目开发的时候,我们一般都会再单独安装一遍 @babel/runtime

我们手动替换掉辅助函数声明,之前文件的代码就变成如下所示:

"use strict";

var _classCallCheck = require("@babel/runtime/helpers/classCallCheck");
var _defineProperties = require("@babel/runtime/helpers/defineProperties");
var _createClass = require("@babel/runtime/helpers/createClass");

var Person = /*#__PURE__*/function () {
  function Person() {
    _classCallCheck(this, Person);
  }
  _createClass(Person, [{
    key: "sayname",
    value: function sayname() {
      return 'name';
    }
  }]);
  return Person;
}();

var john = new Person();
console.log(john);

这样就解决了代码复用和最终文件体积大的问题。不过,这么多辅助函数要一个个记住并手动引入太麻烦了,@babel/plugin-transform-runtime 插件就来帮我们解决这个问题。

@babel/plugin-transform-runtime 有三大作用,其中之一就是自动移除语法转换后内联的辅助函数(inline Babel helpers),使用 @babel/runtime/helpers 里的辅助函数来替代。这样就减少了我们手动引入的麻烦。

现在我们除了安装 @babel/runtime 包提供辅助函数模块,还要安装 Babel 插件 @babel/plugin-transform-runtime

npm i -D @babel/plugin-transform-runtime
npm i @babel/runtime

配置文件:

const presets = ['@babel/preset-env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      helpers: true
    }
  ]
]

module.exports = {
  presets,
  plugins
}

转换前代码:

class Person {
  sayname() {
    return 'name'
  }
}
var john = new Person()
console.log(john)

转换后代码:

"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));

var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));

var Person = /*#__PURE__*/function () {
  function Person() {
    (0, _classCallCheck2["default"])(this, Person);
  }

  (0, _createClass2["default"])(Person, [{
    key: "sayname",
    value: function sayname() {
      return 'name';
    }
  }]);
  return Person;
}();

var john = new Person();
console.log(john);

可以看到,Babel 转码之后,@babel/plugin-transform-runtime 插件自动替换掉了所有的内联辅助函数,转为引用 @babel/runtime 包中的辅助函数。这样在通过 Webpack 打包的时候,不管有多少个 js 文件使用了辅助函数,打包之后的代码里只引入一次相应的辅助函数。

替换全局 API

参考文档

通过引入 @babel/polyfill 或者 core-js/stable,可以补齐全局的 API,但是这样会对全局环境产生污染。例如 Promise API,引入 @babel/polyfillcore-js/stable 会重写了 window.Promise 及其原型链。

如果我们不想在引入 API 的同时污染全局环境,可以配置 @babel/plugin-transform-runtime 插件,它会将全局 API 的引用替换成 @babel/runtime-corejs2 或者 @babel/runtime-corejs3 包中的非全局 API。

npm i -D @babel/plugin-transform-runtime
npm install @babel/runtime-corejs2
# 也可以安装版本 3
# npm install @babel/runtime-corejs3

配置文件:

const presets = ['@babel/env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      // 这里的版本号要与 @babel/runtime-corejs2 一致
      corejs: 2
    }
  ]
]

module.exports = {
  presets,
  plugins
}

转换前代码:

var obj = Promise.resolve();

转换后代码:

"use strict";

var _interopRequireDefault = require("@babel/runtime-corejs2/helpers/interopRequireDefault");

var _promise = _interopRequireDefault(require("@babel/runtime-corejs2/core-js/promise"));

var obj = _promise["default"].resolve();

可以看到转换后的代码并没有定义全局变量 Promise,而是使用 _promise["default"] 代替所有使用 Promise 的地方,这样就不会污染全局环境了。

引入 regeneratorRuntime 函数

配置文件:

const presets = ['@babel/env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      regenerator: true
    }
  ]
]

module.exports = {
  presets,
  plugins
}

转码之前:

function* gen () {
  yield 100;
}

转码之后:

"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

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

var _marked = /*#__PURE__*/_regenerator["default"].mark(gen);

function gen() {
  return _regenerator["default"].wrap(function gen$(_context) {
    while (1) {
      switch (_context.prev = _context.next) {
        case 0:
          _context.next = 2;
          return 100;

        case 2:
        case "end":
          return _context.stop();
      }
    }
  }, _marked);
}

可以看到,转换后的代码使用 _regenerator["default"] 代替全局函数 regeneratorRuntime

babel/plugin-transform-runtime 的配置项

参考文档

以下是各个配置项的默认值,如果没有设置对应的配置项,则该配置项取默认值。

const presets = ['@babel/env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      "helpers": true,
      "corejs": false,
      "regenerator": true,
      "useESModules": false,
      "absoluteRuntime": false,
      "version": "7.0.0-beta.0"
    }
  ]
]

module.exports = {
  presets,
  plugins
}

helpers

该项是用来设置是否要自动引入辅助函数包,默认值为 true。

corejs

该项是用来定义如何处理 ES6 新增的全局 API,默认值为 false。

regenerator

该项是用来定义如何处理 Generator/async 函数的,默认值为 true。

useESModules

该项用来设置是否使用 ES6 的模块化用法,取值是布尔值,默认是fasle。在用 Webpack一类的打包工具的时候,我们可以设置为 true,以便做静态分析。

absoluteRuntime 和 version

保持默认值就可以,可以省略不填。

@babel/runtime

配合 @babel/plugin-transform-runtime 插件使用的工具包,用来提供辅助函数和 regeneratorRuntime 函数。

当我们只需要通过 @babel/plugin-transform-runtime 插件来替换内联辅助函数、按需引入 regeneratorRuntime 函数,不需要替换全局 API 的时候,就可以安装 @babel/runtime 包。

npm i -D @babel/core @babel/cli @babel/preset-env @babel/plugin-transform-runtime
npm i @babel/runtime

安装 @babel/preset-env 的时候会自动安装 @babel/runtime 包,不过在项目开发的时候,我们一般都会手动安装一遍 @babel/runtime

Babel 配置文件:

const presets = ['@babel/preset-env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      helpers: true,
      corejs: false,
      regenerator: true
    }
  ]
]

module.exports = {
  presets,
  plugins
}

@babel/runtime-corejs2

配合 @babel/plugin-transform-runtime 插件使用的工具包,用来提供辅助函数、regeneratorRuntime 函数、core-js2 版本的非全局 API。

当我们需要通过 @babel/plugin-transform-runtime 插件来替换内联辅助函数、按需引入 regeneratorRuntime 函数、替换 core-js2 版本的全局 API 的时候,就可以手动安装 @babel/runtime-corejs2

npm i -D @babel/core @babel/cli @babel/preset-env @babel/plugin-transform-runtime
npm i @babel/runtime-corejs2

Babel 配置文件:

const presets = ['@babel/preset-env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      helpers: true,
      corejs: 2,
      regenerator: true
    }
  ]
]

module.exports = {
  presets,
  plugins
}

@babel/runtime-corejs3

配合 @babel/plugin-transform-runtime 插件使用的工具包,用来提供辅助函数、regeneratorRuntime 函数、core-js3 版本的非全局 API。

当我们需要通过 @babel/plugin-transform-runtime 插件来替换内联辅助函数、按需引入 regeneratorRuntime 函数、替换 core-js3 版本的全局 API 的时候,就可以手动安装 @babel/runtime-corejs3

npm i -D @babel/core @babel/cli @babel/preset-env @babel/plugin-transform-runtime
npm i @babel/runtime-corejs3

Babel 配置文件:

const presets = ['@babel/preset-env']
const plugins = [
  [
    '@babel/plugin-transform-runtime',
    {
      helpers: true,
      corejs: 3,
      regenerator: true
    }
  ]
]

module.exports = {
  presets,
  plugins
}
上一篇下一篇

猜你喜欢

热点阅读