<
Babel 之 babel-polyfill、babel-runtime、transform-runtime 详解
>
上一篇

键盘修改映射
下一篇

HTML5的元素嵌套规则
HTML5的元素嵌套规则

Babel 之 babel-polyfill、babel-runtime、transform-runtime 详解

引言

babel 默认只转换新的 JavaScript 语法,比如箭头函数、扩展运算(spread)。

不转换新的 API,例如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。如果想使用这些新的对象和方法,则需要为当前环境提供一个垫片(polyfill)。

此篇仅对三种 polyfill 进行介绍,并讲了他们的安装配置。具体的每种对新语法的转换结果,可以看参考链接的第一个。

三种 polyfill 介绍

babel-polyfill

目前最常用的配合 Babel 一起使用的 polyfill 是 babel-polyfill,通过改写全局 prototype 的方式实现,它会加载整个 polyfill,针对编译的代码中新的 API 进行处理,并且在代码中插入一些帮助函数,比较适合单独运行的项目。

babel-polyfill 解决了 Babel 不转换新 API 的问题,但是直接在代码中插入帮助函数,会导致污染了全局环境,并且不同的代码文件中包含重复的代码,导致编译后的代码体积变大。虽然这对于应用程序或命令行工具来说可能是好事,但如果你的代码打算发布为供其他人使用的库,或你无法完全控制代码运行的环境,则会成为问题。

babel-runtime

Babel 为了解决上述问题,提供了单独的包 babel-runtime 用以提供编译模块的工具函数,启用插件 babel-plugin-transform-runtime 后,Babel 就会使用 babel-runtime 下的工具函数。

babel-runtime 插件能够将这些工具函数的代码转换成 require 语句,指向为对 babel-runtime 的引用。每当要转译一个 api 时都要手动加上 require(‘babel-runtime’)。简单说 babel-runtime 更像是一种按需加载的实现,比如你哪里需要使用 Promise,只要在这个文件头部 require Promise from ‘babel-runtime/core-js/promise’就行了

不过如果你许多文件都要使用 Promise,难道每个文件都要 import 一遍不成?

babel-plugin-transform-runtime# 为了方便使用 babel-runtime,解决手动 require 的苦恼。它会分析我们的 ast 中,是否有引用 babel-rumtime 中的垫片(通过映射关系),如果有,就会在当前模块顶部插入我们需要的垫片。

transform-runtime 是利用 plugin 自动识别并替换代码中的新特性,你不需要再引入,只需要装好 babel-runtime 和 配好 plugin 就可以了。

好处是按需替换,检测到你需要哪个,就引入哪个 polyfill,如果只用了一部分,打包完的文件体积对比 babel-polyfill 会小很多。而且 transform-runtime 不会污染原生的对象,方法,也不会对其他 polyfill 产生影响。

所以 transform-runtime 的方式更适合开发工具包,库,一方面是体积够小,另一方面是用户(开发者)不会因为引用了我们的工具,包而污染了全局的原生方法,产生副作用,还是应该留给用户自己去选择。

⭐ 比较

babel-polyfill 与 babel-runtime 相比虽然有各种缺点,但在某些情况下仍然不能被 babel-runtime 替代, 例如,

[1, 2, 3].includes(3),Object.assign({}, {key: ‘value’}),Array,Object 以及其他”实例”下 es6 的方法,babel-runtime 是无法支持的, 因为 babel-runtime 只支持到 static 的方法。

安装配置

babel-polyfill# 因为这是一个 polyfill (它需要在你的源代码之前运行),我们需要让它成为一个 dependency,而不是一个 devDependency 。

npm install –save babel-polyfill

直接在代码中 require,或者在 webpack 的 entry 中添加,也可以在 babel 的 env 中设置 useBuildins 为 true 来开启。

//示例:vue-cli 脚手架中使用
import "babel-polyfill";
//示例:webpack 的 entry 中添加
entry: {
common: [
`babel-polyfill`,
`whatwg-fetch`,
`react`,
`react-dom`,
`redux`,
`react-redux`,
`js-cookie`,
],
},

babel-runtime 和 babel-plugin-transform-runtime# 在大多数情况下,你应该安装 babel-plugin-transform-runtime 作为开发依赖(使用 –save-dev),并且将 babel-runtime 作为生产依赖(使用 –save)。这个看 vue-cli 生成的 package.json 就能发现。

因为 babel 编译 es6 到 es5 的过程中,babel-plugin-transform-runtime 这个插件会自动 polyfill es5 不支持的特性,这些 polyfill 包就是在 babel-runtime 这个包里(core-js 、regenerator 等)

npm install –save-dev babel-plugin-transform-runtime

npm install –save babel-runtime

用法# 通过 .babelrc(推荐)

将以下内容添加到你的 .babelrc 文件中:

未包含选项:

Copy { “plugins”: [“transform-runtime”] } 包含选项:

Copy { “plugins”: [ [“transform-runtime”, { “helpers”: false, “polyfill”: false, “regenerator”: true, “moduleName”: “babel-runtime” }] ] } 选项# 1.辅助(helpers)

默认值是:true

表示是否开启内联的 babel helpers(即 babel 或者环境本来的存在的垫片或者某些对象方法函数)(clasCallCheck,extends,etc)在调用模块名字(moduleName)时将被替换名字。

2.垫片/polyfill

默认值是:`true’

表示是否把内置的东西(Promise,Set,Map,tec)转换成非全局污染垫片。

3.重新生成/regenerator

默认值是:true

是否开启 generator 函数转换成使用 regenerator runtime 来避免污染全局域。

4.模块名字/moduleName

默认值:babel-runtime

当调用辅助(内置垫片)设置模块(module)名字/路径.

例子:

Copy { “moduleName”: “flavortown/runtime” } Copy import extends from ‘flavortown/runtime/helpers/extends’; 优点# 不会污染全局变量

多次使用只会打包一次

依赖统一按需引入,无重复引入,无多余引入

缺点# 不支持实例化的方法,例 Array.includes(x) 就不能转化

如果使用的 API 用的次数不是很多,那么 transform-runtime 引入 polyfill 的包会比不是 transform-runtime 时大

随着应用的增大,相同的 polyfill 每个模块都要做重复的工作(检测,替换),虽然 polyfill 只是引用,编译效率不够高效。

参考链接# Babel 用法 | usages transform-runtime

小毛蛋_对 babel-transform-runtime,babel-polyfill 的一些理解

zackxizi babel-runtime 和 babel-polyfill 的作用介绍和使用

babel-polyfill、babel-runtime 的选择

Top
Foot