@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例子
{ "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转换的目的是不污染全局作用域。
@babel/runtime-corejs3 = @babel/runtime + core-js 3 吗