@babel/plugin-transform-runtime(二)

@babel/plugin-transform-runtime有三大作用:

1.自动移除语法转换后内联的辅助函数(inline Babel helpers),使用@babel/runtime/helpers里的辅助函数来替代;

2.当代码里使用了core-js的API,自动引入@babel/runtime-corejs3/core-js-stable/,以此来替代全局引入的core-js/stable;

3.当代码里使用了Generator/async函数,自动引入@babel/runtime/regenerator,以此来替代全局引入的regenerator-runtime/runtime;

其中作用1已经在上一节讲过,这一节我们着重来学习作用2和作用3。

作用2和3其实是在做API转换,对内置对象进行重命名,以防止污染全局环境。

babel-polyfill一节,我们学习了引入'babel-polyfill'或'core-js/stable与regenerator-runtime/runtime'来做全局的API补齐。但这样可能有一个问题,那就是对运行环境产生了污染。例如Promise,我们的polyfill是对浏览器的全局对象进行了重新赋值,我们重写了Promise及其原型链。

有时候我们不想改变或补齐浏览器的window.Promise,那么我们就不能使用'babel-polyfill'或'core-js/stable与regenerator-runtime/runtime',因为其会对浏览器环境产生污染(即修改了浏览器的window.Promise)。

这个时候我们就可以使用@babel/plugin-transform-runtime,它可以对我们代码里ES6的API进行转换。还是以Promise举例子。

Babel转换前的代码

  var obj = Promise.resolve();

若使用了'babel-polyfill'或'core-js/stable与regenerator-runtime/runtime'来做全局的API补齐,那么Babel转换后的代码仍然是

  var obj = Promise.resolve();

polyfill只是补齐了浏览器的window.Promise对象。

若我们不使用polyfill,而开启@babel/plugin-transform-runtime的API转换功能。那么Babel转换后的代码将是

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

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

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

看到效果了没?@babel/plugin-transform-runtime把我们代码里的Promise变成了_promise["default"],而_promise["default"]拥有ES标准里Promise所有的功能。现在,即使浏览器没有Promise,我们的代码也能正常运行。

开启core-js相关API转换功能的Babel配置与安装的npm包如下

配套代码是github仓库 https://github.com/jruit/babel-tutorial 的babel14例子

@babel/plugin-transform-runtime Babel教程
  {
    "presets": [
      "@babel/env"
    ],
    "plugins": [
      ["@babel/plugin-transform-runtime", {
        "corejs": 3
      }]
    ]
  }
  npm install --save @babel/runtime-corejs3
  npm install --save-dev @babel/cli @babel/core  @babel/preset-env @babel/plugin-transform-runtime

那么,上面讲的API转换有什么用,明明通过polyfill补齐API的方式也可以使代码在浏览器正常运行?

其实,API转换主要是给开发JS库或npm包等的人用的,我们的前端工程一般仍然使用polyfill补齐API。

可以想象,如果开发JS库的人使用polyfill补齐API,我们前端工程也使用polyfill补齐API,但JS库的polyfill版本或内容与我们前端工程的不一致,那么我们引入该JS库后很可能会导致我们的前端工程出问题。所以,开发JS库或npm包等的人会用到API转换功能。

当然,我们前端工程开发的时候也是可以使用@babel/plugin-transform-runtime的API转换功能,毕竟没有污染全局环境,不会有任何冲突。@babel/plugin-transform-runtime的默认设置下,就是对generators/async开启了API转换功能。

细心的你可能已经发现了,我们安装npm包的时候,安装的是@babel/runtime-corejs3,而上一节我们安装的是@babel/runtime。

看名字挺像的,那么这两者有什么不同呢?

在我们不需要开启core-js相关API转换功能的时候,我们只需要安装@babel/runtime就可以了。上一节我们已经知道,@babel/runtime里存放的是Babel做语法转换的辅助函数。

在我们需要开启core-js相关API转换功能的时候,就需要安装@babel/runtime的进化版@babel/runtime-corejs3。这个npm包里除了包含Babel做语法转换的辅助函数,也包含了core-js的API转换函数。

除了这两个包,还有一个@babel/runtime-corejs2的包。它和@babel/runtime-corejs3的功能是一样的,只是里面的函数是针对core-js2版本的。

上面的例子主要是拿Promise来讲的,它属于作用2,即对core-js的API进行转换。其实理解了作用2,也就理解了作用3。

下面简单说一下作用3。

在之前章节,若我们转码前代码里有Generator函数或async函数,转码后需要引入'regenerator-runtime/runtime'做全局API补齐。

全局API补齐必然会对浏览器的window对象进行修改,如果我们不想要污染window,那么我们就不能引入'regenerator-runtime/runtime'了。

这个时候,我们可以开启@babel/plugin-transform-runtime的作用3,对Generator/async进行API转换。

需要注意的是,@babel/plugin-transform-runtime对Generator/async进行API转换功能,默认是开启的,不需要我们设置。

如何开启或关闭@babel/plugin-transform-runtime的某个功能,除了与安装的npm包有关,也与Babel配置文件的配置有关,我们下一节来讲。

注:

1.如果我们使用@babel/plugin-transform-runtime来做polyfill的事情,那么就不要再使用之前讲过的polyfill方式了,无论是单独引入还是@babel/preset-env的方式。因为我们用transform-runtime来做api转换的目的是不污染全局作用域。

笔记与思考

发表评论

邮箱地址不会被公开。 必填项已用*标注