问题描述
- Babel 默认只转换新的 JavaScript语法,比如箭头函数,而不转换新的API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法都不会转译。
- 如果想使用这些新的对象和方法,必须使用 polyfill。提供polyfill的有2个插件:babel-runtime和babel-polyill。
- babel 转译语法需要一些plugin,如 react,es2015,stage-0,stage-1等等
stage-0 表示的是什么呢?
stage 系列集合了一些对 es7 的草案支持的插件,由于是草案,所以作为插件的形式提供。
* stage-0 - Strawman: just an idea, possible Babel plugin.
* stage-1 - Proposal: this is worth working on.
* stage-2 - Draft: initial spec.
* stage-3 - Candidate: complete spec and initial browser implementations.
* stage-4 - Finished: will be added to the next yearly release.
stage 是向下兼容 0>1>2>3>4 所包含的插件数量依次减少
babel polyfill 有三种
- babel-runtime
- babel-plugin-transform-runtime
- babel-polyfill
几个包的包含关系?
- babel-polyfill仅仅是引用core-js、regenerator-runtime这两个npm包。
- @babel/runtime包含两个文件夹:helpers(定义了一些处理新的语法关键字的帮助函数)、regenerator(仅仅是引用regenerator-runtime这个npm包)。
- @babel/runtime-corejs2包含三个文件夹:core-js(引用core-js这个npm包)、helpers(定义了一些处理新的语法关键字的帮助函数)、regenerator(仅仅是引用regenerator-runtime这个npm包)。
- 可以看出,@babel/runtime-corejs2≈@babel/runtime + babel-polyfill:
- @babel/runtime只能处理语法关键字,而@babel/runtime-corejs2还能处理新的全局变量(例如,Promise)、新的原生方法(例如,String.padStart );
- 使用了@babel/runtime-corejs2,就无需再使用@babel/runtime了。
babel-polyfill vs babel-runtime vs babel-plugin-transform-runtime
原理说明
-
babel-polyfill,它不会将代码编译成低版本的ECMAScript,他的原理是当运行环境中并没有实现的一些方法,babel-polyfill中会给做兼容
-
babel-runtime,将es6编译成es5去运行,前端可以使用es6的语法来写,最终浏览器上运行的是es5
作用范围
-
babel-polyfill:通过向全局对象和内置对象的prototype上添加方法来实现
,比如运行环境中不支持Array-prototype.find,引入polyfill,前端就可以放心的在代码里用es6的语法来写;
-
babel-runtime:不会污染全局对象和内置的对象原型。比如当前运行环境不支持promise,可以通过引入babel-runtime/core-js/promise来获取promise,或者通过babel-plugin-transform-runtime自动重写你的promise。但是它不会模拟内置对象原型上的方法,比如Array-prototype.find,就没法支持了,如果运行环境不支持es6,代码里又使用了find方法,就会出错,因为es5并没有这个方法
The main difference between the two is that the polyfill pollutes global scope, and works with instance methods, while the runtime does not pollute global scope and does not work with instance methods.
优缺点
-
babel-polyfill:
- 打包后代码冗余量比较大,
- 对于现代的浏览器,有些不需要polyfill,造成流量浪费
- 污染了全局对象
- babel-polyfill则是通过改写全局prototype的方式实现,比较适合单独运行的项目。
- 开启babel-polyfill的方式,可以直接在代码中require,或者在webpack的entry中添加,也可以在babel的env中设置useBuildins为true来开启。
- 但是babel-polyfill会有近100K
-
babel-runtime:
- 提高代码重用性,缩小编译后的代码体积。(只引用需要使用的)
- 防止污染全局作用域。
- 不会污染全局变量
- 多次使用只会打包一次
- 依赖统一按需引入,无重复引入,无多余引入
- 不支持实例化的方法Array.includes(x) 就不能转化
- 如果使用的API用的次数不是很多,那么transform-runtime 引入polyfill的包会比不是transform-runtime 时大
runtime transformer plugin做3件事:
- 当使用generators/async功能时,自动添加babel-runtime/regenerator
- 自动添加babel-runtime/core-js并且映射ES6静态方法和内置方法
- 移除内联的babel帮助代码并使用babel-runtime/helpers模块来替代 简单来说,基本上你可以使用内置函数如Promise,Set,Symbol等;也可以无缝地使用需要polyfill的所有Babel特性,而不会污染全局,对于库来说很实用。 一定要把babel-runtime作为依赖引入!
transform-runtime在.babelrc
文件中的配置说明
{
"plugins": [
["transform-runtime", {
"helpers": false,
"polyfill": false,
"regenerator": true,
"moduleName": "babel-runtime"
}]
]
}
- transform-runtime 会有几个配置项,不表标注默认为true
- 在webpack中,babel-plugin-transform-runtime 实际上是依赖babel-runtime
- babel编译es6到es5的过程中,babel-plugin-transform-runtime这个插件会自动polyfill es5不支持的特性,
这些polyfill包就是在babel-runtime这个包里core-js 、regenerator等 poiiyfill
babel-plugin-transform-runtime 的作用?
babel-plugin-transform-runtime主要做了一下三件事:
- 当你使用 generators/async 函数时,自动引入 babel-runtime/regenerator (使用 regenerator 运行时而不会污染当前环境) 。
- 自动引入 babel-runtime/core-js 并映射 ES6 静态方法和内置插件(实现polyfill的功能且无全局污染,但是实例方法无法正常使用,如 “foobar”.includes(“foo”) )。
- 移除内联的 Babel helper 并使用模块 babel-runtime/helpers 代替(提取babel转换语法的代码)。
{
"plugins": [
["transform-runtime", {
"helpers": true, // default
"polyfill": true, // default
"regenerator": true, // defalut
"moduleName": "babel-runtime" // default
}]
]
}
babel-runtime和 babel-plugin-transform-runtime的区别?
- babel-plugin-transform-runtime 和 transform-runtime 会自动应用 polyfill,即便没有使用 babel-polyfill
- babel-runtime是手动挡而babel-plugin-transform-runtime是自动挡,每当要转译一个api时都要手动加上require(‘babel-runtime’)
- 而babel-plugin-transform-runtime会由工具自动添加,主要的功能是为api提供沙箱的垫片方案,不会污染全局的api,因此适合用在第三方的开发产品中。