babel-polyfill和transform-runtime揭秘
当前前端的开发,已经基本离不开babel的使用了。
而babel下两员大将babel-polyfill和transform-runtime也经常出现在各位前端同胞的业务及库的开发中,让我们得以欢快地使用js的各种高级语法以及牛X的api。可虽说是如此常用,很多前端同胞甚至是前端老司机也常常搞不清二者的关系,以至陷入莫名的疑惑当中。
正在这个时候,一名不愿露面的网友,本着刨根问底的钻(qiu)研(nue)精神,一窥二者的本质,向大家聊一聊两者的关系。
在此之前,让我们先了解一下core-js这个库,版本2.5.7。打开它的github主页,如下:

我们发现,呃,作者正在找工作,这个不是重点。从这段文字中我们知道了core-js是一个模块化的js标准库,包含着各种垫片等。重点在最后一句,我们可以按需使用,或者不污染全局命名空间地使用它。
也就是说我们至少应该有两种方式使用它:
在程序入口的最开始处引入,当成垫片使用,会污染全局命名空间。
1
require('core-js/shim')
当成一个普通的commonjs库使用,不污染全局命名空间。
1
var core = require('core-js/library')
实际上,还有第三种,一股脑全引入,同样会污染全局命名空间:
1
require('core-js')
好的,回到我们的主角当中。
babel-polyfill
我们先来看看babel-polyfill,以版本6.26.3为例,找到安装包的入口文件lib/index.js,简洁的数行代码:
1 | if (global._babelPolyfill) { |
注释后面的就不用看了,将在下一个主版本发布时移除掉。然后我们看到只引入了两个库core-js/shim和regenerator-runtime/runtime。前者根据core-js的第一条使用方式,是作为js垫片使用的。后者会提供一个全局函数regeneratorRuntime,这个就厉害了 ,我们之所以能够欢快的使用async和await,全是它的功劳。到此我们大概知道了babel-polyfill实际上是一种垫片技术,保证了js在各版本下的一致性。
babel-plugin-transform-runtime
再来看看babel-plugin-transform-runtime,以6.23.0为例,这是一个babel插件,依赖babel-runtime,而babel-runtime又依赖core-js和regenerator-runtime。是不是隐约觉得babel-polyfill和babel-plugin-transform-runtime已经产生了某种联系?
该插件中有一个definitions.js文件,定义了一些builtins(即浏览器内建对象、方法),及一些如Array、Object、Math、String、Number等类的类方法的映射路径。这些路径如何映射,又映射到哪里呢?
依Array的includes方法举例说明,definitions.js中这样定义到:
1 | export default { |
babel插件,是对babel转换后的AST(抽象语法树)进行的一系列处理,该插件对我们代码中用到的类方法的处理如下:
1 | const moduleName = getRuntimeModuleName(state.opts); |
其中moduleName默认是babel-runtime,${moduleName}/core-js/${methods[prop.name]}代入变量还原后就是babel-runtime/core-js/array/includes。找到对应路径的文件,代码如下:
1 | module.exports = { "default": require("core-js/library/fn/array/includes"), __esModule: true }; |
引用了core-js/library,根据core-js的第二条使用方式 —— 当成一个普通的commonjs库使用,不污染全局命名空间。而且可以针对某个方法或builtins单独引入。
这里还有个疑问,看过transform-runtime使用文档的会知道,它并不支持实例方法,如[1, 2, 3].includes(1)将无法起作用,那上面的Array的includes又是什么情况呢?事实上,它仅仅是提供了一个类方法的使用,及Array.includes,使用方式Array.includes([1, 2, 3], 1),第一个参数接收一个数组实例。
例如,使用transform-runtime将
1 | const a = [1, 3] |
转换为
1 | ; |
总结
现在我们总结下两者的区别与应用场景:
babel-polyfill提供完整的补丁,保证各浏览器下的一致性,但体积大,会污染全局变量,适合应用于业务开发当中,开发人员无需过多关注兼容性问题。transform-runtime按需提供,不支持实例的方法,不污染全局变量,适合于库的开发
- 本文链接:https://vhtml.github.io/2018/05/02/babel-polyfill-vs-transform-runtime/
- 版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!