摘要: IE虽然没落了,Babel还是要用的…
-
原文:
关于Babel配置项的这点事
-
作者:
tonyc726
Fundebug经授权转载,版权归原作者所有。
Babel
作为一个JavaScript的语法编译器,可以将
ES6/7/8
代码转为
ES5
代码,从而在现有环境执行。
但是初次配置
.babelrc
的时候,各种
presets
、
plugins
看的眼花缭乱,不知道如何下手,下面就自己学习Babel时遇到的问题做一下总结:
如果你是初次接触babel,推荐阅读阮一峰的《
Babel 入门教程
》
Plugin、Preset、Stage-X的关系
按照Babel官网的
介绍
,其实Preset和Stage-X都是归属到Plugin里面的,只不过所覆盖的范围不同而已。
举个例子,如果需要转换ES2015(ES6)的语法,那么你可以在
.babelrc
的
plugins
中按需引入
check-es2015-constants
、
es2015-arrow-functions
、
es2015-block-scoped-functions
等等几十个不同作用的plugin:
// .babelrc { "plugins": [ "check-es2015-constants", "es2015-arrow-functions", "es2015-block-scoped-functions", ] }
|
但是Babel团队为了方便,将
同属ES2015的几十个Transform Plugins
集合到
babel-preset-es2015
一个Preset中,这样你只需要在
.babelrc
的
presets
加入
es2015
一个配置就可以完成全部ES2015语法的支持了:
// .babelrc {
"presets": [ "es2015" ] }
|
另外,不论是Plugin还是Preset,有不少都有单独属于自己的配置项,具体如何操作的可以看一下
官网的说明
。
上面介绍了Plugin与Preset,那么Stage-X就很好理解了,
stage-0
、
stage-1
、
stage-2
、
stage-3
、
stage-4
分别对应的就是进入标准之前的5个阶段,不同
stage-x
之间存在依赖关系,数字越小,阶段越靠后,靠后阶段包含前面阶段所有的功能,简单理解就是
stage-0
包含
stage-1/2/3
的内容,所以如果你不知道需要哪个
stage-x
的话,直接引入
stage-0
就好了。
PS:
babel-preset-stage-4
已经整合入Presets不单独发布了。
以上就是一些基础概念,目前,官方推荐使用
babel-preset-env
,它可以根据你的配置结合
compat-table
来帮你自动引入你需要的plugins,它有很多
配置项
,下面介绍几个常用的:
需要支持的环境,可选例如:
chrome
,
edge
,
firefox
,
safari
,
ie
,
ios
,
node
,甚至可以指定版本,如
node: "6.10"
或者
node: "current"
代表使用当前的版本;
指定
node
的版本,例如:
6.10
;
指定需要兼容的浏览器清单,具体参考
browserslist
,例如:
["last 2 versions", "safari >= 7"]
;
例如需要配置兼容
["last 2 versions", "safari >= 7"]
的
babel-preset-env
:
// .babelrc { "presets": [ ["env", { "targets": { "browsers": ["last 2 versions", "safari >= 7"] } }] ] }
|
此外,不同的plugins和presets或许有些功能是重复的,有些存在依赖关系,在配置的时候还有前后顺序的不同,那么Babel在运行的时候是怎么处理的呢?总结一下,规律大概有以下几点:
-
plugins优先于presets进行编译;
-
plugins按照数组的index增序(从数组第一个到最后一个)进行编译;
-
presets按照数组的index倒序(从数组最后一个到第一个)进行编译,因为作者认为大部分会把presets写成
["es2015", "stage-0"]
,具体细节可以看
这个
。
摘自《
如何写好.babelrc?Babel的presets和plugins配置解析
》
babel-polyfill与babel-runtime的选择
Babel默认只转换新的JavaScript语法,而不转换新的API,比如
Iterator
、
Generator
、
Set
、
Maps
、
Promise
等等全局对象,以及一些定义在全局对象上的方法(比如
Object.assign
)都不会转码,具体的可以参考
babel-plugin-transform-runtime
模块的
definitions.js
文件。
babel-polyfill
与
babel-runtime
就是为了解决这种全局对象或者全局对象方法不足的问题,而诞生的2种解决方式。
当然,你还可以用
promise-polyfill
此类Polyfill解决全局对象的问题;
或者用
lodash
此类Utils解决
Object.assign
这种方法扩展的问题。
先说说
babel-polyfill
,它的做法比较暴力,就是将全局对象通通污染一遍,这样做的坏处有几点:
-
可能会增加很多根本没有用到的polyfill;
-
可能会污染子模块的局部作用域,严重的或许会导致冲突;
但是,这样做也有好处,如果你的运行环境比较low,比如说Android一些老机子,而你有需要大量使用
Promise
、
Object.assign
、
Array.find
之类的全局对象或者其所属方法,那么使用
babel-polyfill
,绝对是一劳永逸。
接着,再来说说
babel-runtime
,相对而言,它的处理方式比较温柔,套用步步高的广告词就是哪里需要加哪里,比如说你需要
Promise
,你只需要
import Promise from 'babel-runtime/core-js/promise'
即可,这样不仅避免污染全局对象,而且可以减少不必要的代码。
不过,如果N个文件都需要
Promise
,难道得一个个文件的加
import Promise from 'babel-runtime/core-js/promise'
么,显然不是,Babel已经为这样情况考虑过了,只需要使用
babel-plugin-transform-runtime
就可以轻松的帮你省去手动
import
的痛苦,而且,它还做了公用方法的抽离,哪怕你有100个模块使用了
Promise
,但是promise的polyfill仅仅存在1份,所有要的地方都是引用一地方,具体的配置参考如下:
// .babelrc { "presets": [ "env", "stage-0" ], "plugins": [ "transform-runtime"
|