babelrc配置

Author: Necfol

Babel简介

Babel 是一个 JavaScript 编译器

即Babel是将ES6+代码转换为ES5代码的工具。

经常在一些Vue或者React相关项目中见到Babel的痕迹,使用时,也只是网上搜罗一通,囫囵吞枣的copy了一些配置。今天下定决心搞通它。由于Babel所有的配置都是「可插拔」的,😭即没有配置Babel是不会工作的。好记性不如烂笔头,下面开始对Babel的一些配置做一个简单的remark。

presets

「presets设定转码规则」通俗一点来讲,presets就是许多plugins的集合,打个比方,我们如果要在B端使用React,babelrc中没有配置presets,那么我们就可能需要配置许多plugins:

  • preset-flow
  • syntax-jsx
  • transform-react-jsx
  • transform-react-display-name
  • transform-react-constant-elements
  • transform-react-jsx-self
  • transform-react-jsx-source

所以presets就是我们的全家桶。我们需要注意的是presets数组里执行的顺序是倒序即react->stage-2->env

1
2
3
4
5
6
7
{
"presets": [
"env",
"stage-2",
"react"
]
}

官网介绍的常用的presets有:

  • env
  • react
  • flow

经常还看到stage-xxx类似这种presets,官网上有介绍每个stage对应的意义,很晦涩。我们通俗一点介绍一下。

stage-xxx

stage-xxx代表了TC39(负责JavaScript进化的委员会)每个草案标明的成熟度,数值越大越成熟,果然是越大越好😂。

草案成熟度 含义/阶段
stage-0 一些idea,提交给TC39,并且TC39认为有一定意义的提案
stage-1 TC39讨论,指定参与人,规定语法之类
stage-2 TC39讨论阶段,验证可能存在的语法或者语义问题
stage-3 实现阶段,有浏览器厂商实现,进入这个阶段9成可能性都会进入变成下一阶段标准
stage-4 实现完成,等待进入标准

stage-4不需要在babel中设置。

babel-preset-env

官网解释很完美:

  • 每年每个 preset 只编译当年批准的内容。 而 babel-preset-env 相当于 es2015 ,es2016 ,es2017 及最新版本。
  • 在没有任何配置选项的情况下,babel-preset-env 与 babel-preset-latest(或者babel-preset-es2015,babel-preset-es2016和babel-preset-es2017一起)的行为完全相同

babel-preset-env可以配置项目所支持浏览器所需的polyfill和transform。只编译所需的代码,会使你的代码包更小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"presets": [
["env", {
"targets": {// 配支持的环境
"browsers": [// 浏览器
"last 2 versions",
"safari >= 7"
],
"node": "current"
},
"modules": false, //启用将ES6模块语法转换为另一种模块类型。将其设置为 false 就不会转换模块。默认"commonjs"
"include": [], // 总是启用哪些 plugins
"exclude": [] // 强制不启用哪些 plugins,用来防止某些插件被启用
}]
]
}

plugins

  • plugins 优先于 presets进行编译
  • plugins 按照数组的 index 增序

plugins 数组里是单独的插件,也就是一份一份的工具,例如:

1
2
3
4
5
6
{
"presets": [],
"plugins": [
"transform-react-jsx"
]
}

该插件能够将jsx进行转译

babel-plugin-transform-runtime

babel-plugin-transform-runtime可以在发现代码中使用到Symbol、Promise、Map等新类型时,自动且按需进行polyfill。即该插件只是动态判断是否需要进行polyfill,如果需要,则在module中引入相应的polyfill,比如:

1
const Promise = require('babel-runtime/core-js/promise');

babel-plugin-transform-runtime在文件中侦测到使用promise了,就会相应的新增这一行代码,即引用babel-runtime包中包含的polyfill。

1
2
3
4
5
6
7
8
{
"plugins": [
["transform-runtime", {
"polyfill": true,
"regenerator": true
}]
]
}

如果不需要使用非全局污染的polyfill将Symbol、Promise、Map转换,则polyfill设置为false;如果不需要使用非全局污染的polyfill将generator/yeild, async/await转换,则regenerator设置为false。

使用该插件时需要安装babel-runtime。

babel-runtime

「babel-runtime是由Babel提供的polyfill库,它本身就是由core-js与regenerator-runtime库组成,除了做简单的合并与映射外,并没有做任何额外的加工」

core-js 标准库提供了ES5、ES6的polyfills,包括promises、symbols、collections、iterators、typed arrays、ECMAScript 7+ proposals、setImmediate 等等。但是core-js库并不污染原生构造函数的prototype!

regenerator-runtime库用来实现 ES6/ES7 中 generators、yield、async 及 await 等相关的 polyfills。

babel-polyfill

babel-polyfill是一整套ES2015+运行时环境,包括一些挂载在原型的方法。

babel-polyfill与babel-plugin-transform-runtime

之前我们已经了解了babel-plugin-transform-runtime和babel-runtime关系。

「babel-polyfill:需要在你自己的代码中手工引入(最好放在 vendor 里),它会以全局变量污染的方式 polyfill 内建类(如 Map、Set、Promise 等),同时也会通过修改 Array、String、Object 等原型的方式添加实例方法(如 Array.prototype.includes()、String.prototype.padStart() 等),内建类的静态方法(如 Array.from() 等)也会被 polyfill。babel-polyfill 适合于开发独立的业务应用,及时全局污染、prototype 被修改也不会受到太大的影响,babel-polyfill 不适合开发第三方类库。

babel-plugin-transform-runtime:需要你在 .babelrc 或 Babel 编译选项中将该插件添加到 plugins 中,插件只会 polyfill 你用到的类或方法,由于采用了沙盒(Sandbox)机制,它不会污染全局变量,同时也不会去修改内建类的原型,带来的坏处是它不会 polyfill 原型上的扩展(例如 Array.prototype.includes() 不会被 polyfill,Array.from() 则会被 polyfill)。插件的方式适合于开发第三方类库,不适合开发需要大量使用 Array 等原型链扩展方法的应用。」

最后

总结babelrc的配置花去了我一个下午的时间,终于大概清楚了babel的一些配置,现在仅仅是使用它,有空自己还得尝试着写一下babel的plugins,万一哪天常用到的语法被TC39否了呢…😂

本文部分章节引用Henry的 《前端零栈》

分享到