babel 一个可以让你自由使用下一代 javascript 语法的编译工具。

这篇文章主要阐述 babel 及相关工具的使用,以及我个人对一些工具的认识。

Babel

javascript 以及发布到 es2017 的版本了,但是因为浏览器的支持,只能使用使用某些语法,或者只能使用 es5 的语法,若在开发中使用 es6,7 的语法,可以大大简化开发中 javascript 本身的一些语法缺点,更加方便。

这时就需要使用一个工具将 es6,7 的js文件转换为 es5 文件(这一过程叫做“源码到源码”编译, 也被称为转换编译),从而被浏览器正常解析。so babel 出现了!

Babel config

Babel 的配置文件是 .babelrc (可以是 jsjsonymal 文件),存放在项目的根目录下。使用 Babel 的第一步,就是配置这个文件。

该文件用来设置转码规则和插件,基本格式如下。

1
2
3
4
{
"presets": [],
"plugins": []
}

presets 字段设定转码规则,官方提供以下的规则集,你可以根据需要安装。

1
2
3
4
5
6
7
8
9
10
11
# ES2015转码规则
$ npm install --save-dev babel-preset-es2015
# react转码规则
$ npm install --save-dev babel-preset-react
# ES7不同阶段语法提案的转码规则(共有4个阶段),选装一个
$ npm install --save-dev babel-preset-stage-0
$ npm install --save-dev babel-preset-stage-1
$ npm install --save-dev babel-preset-stage-2
$ npm install --save-dev babel-preset-stage-3

然后,将这些规则加入.babelrc

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

注意,以下所有Babel工具和模块的使用,都必须先写好 .babelrc

Use babel

babel-cli 是一个命令工具,转换编译文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ npm install --global babel-cli
# 转码结果输出到标准输出
$ babel example.js
# 转码结果写入一个文件
# --out-file 或 -o 参数指定输出文件
$ babel example.js --out-file compiled.js
# 或者
$ babel example.js -o compiled.js
# 整个目录转码
# --out-dir 或 -d 参数指定输出目录
$ babel src --out-dir lib
# 或者
$ babel src -d lib
# -s 参数生成source map文件
$ babel src -d lib -s

这时全局安装,一般不建议全局安装,建议项目内安装,使用 script 来操作。

因为 babel-cli 仅是在命令行进行的文件转换,可以使用命令行参数来设置转换,也可以使用配置文件。但在开发中 babel-cli 使用较少。

babel-node: 工具自带一个 babel-node命令,提供一个支持 ES6 的 REPL 环境。它支持 Node 的 REPL 环境的所有功能,而且可以直接运行 ES6 代码。

babel-core: 提供 babel 的核心 API。如果某些代码需要调用 babel 的 API 进行转码,就要使用 babel-core 模块。具体 API 参考官网

babel-polyfill: Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的API,比如 IteratorGeneratorSetMapsProxyReflectSymbolPromise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign )都不会转码。

举例来说,ES6在Array对象上新增了 Array.from 方法。Babel就不会转码这个方法。如果想让这个方法运行,必须使用 babel-polyfill ,为当前环境提供一个垫片。

安装命令如下。

1
$ npm install --save babel-polyfill

然后,在脚本头部,加入如下一行代码。

1
2
3
import 'babel-polyfill';
// 或者
require('babel-polyfill');

Babel默认不转码的API非常多,详细清单可以查看 babel-plugin-transform-runtime 模块的definitions.js文件

Babel more

babel 官方的包很多 介绍

这里对这篇文档做些解释:

Core Packages

  • babel-core
  • babylon
  • babel-traverse
  • babel-generator

AST:Abstract Syntax Tree, 抽象语法树
DI: Dependency Injection, 依赖注入

babel-core 上面说了用来提供babel的核心解析,具体使用参照API

babylon Babel使用的引擎是babylonbabylon并非由babel团队自己开发的,而是fork的acorn项目,不过acorn引擎只提供基本的解析AST的能力,遍历还需要配套的acorn-travesal, 替换节点需要使用acorn-,而这些开发,在Babel的插件体系开发下,变得一体化了。

Babel将源码转换AST之后,通过遍历AST树(其实就是一个js对象),对树做一些修改,然后再将AST转成code,即成源码。

将js源码转换为AST用到的模块叫:babylon
对树进行遍历并做修改用到的模块叫:babel-traverse
将修改后的AST再生成js代码用到的模块则是:babel-generator

babel-core模块则是将三者结合使得对外提供的API做了一个简化,使用babel-core只需要执行以下的简单代码即可:

1
2
3
4
5
6
7
import { transform } from 'babel-core';
var result = babel.transform("code();", options);
result.code;
result.map;
result.ast;

我们在Node中使用的时候一般都是使用的三步转换的方式,方便做更多的配置及操作。所以整个的难点主要就在对AST的操作上,为了能对AST做一些操作后进而能对js代码做到修改,babel对js代码语法提供了各种类型,比如:箭头函数类型ArrowFunctionExpressionfor循环里的continue语句类型:ContinueStatement等等,我们主要就是根据这些不同的语法类型来对AST做操作(生成/替换/增加/删除节点),具体有哪些类型全部在:babel-types).

具体可以参考Babel从入门到插件开发

Other

babel-cli: 上面说了,这是cli工具,内部包含了babel-node,会运行babel-core来解析代码。

babel-types: 用于验证,构建和更改AST节点。

babel-polyfill: 上面介绍了。

babel-runtime: 与 babel-polyfill 一样,babel-runtime 的作用也是模拟 ES2015 环境。只不过,babel-polyfill 是针对全局环境的,引入它,我们的浏览器就好像具备了规范里定义的完整的特性 – 虽然原生并未实现。

babel-register: 是通过绑定到Node.js,通过Babel自动编译文件的方法require。

babel-template: 是一个帮助函数,允许从代码的字符串表示中构建AST节点; 这消除了babel-types用于构建AST节点的细节。

babel-helpers: 是babel-template一些在Babel插件中使用的预制功能。

babel-code-frame: 是一个独立的包,用于生成打印源代码并指向错误位置的错误。

Preset

这里官方推荐使用babel-preset-env,其实还有 preset-2015,2016,2017,latest,stage-x 什么的。但env更好用。

一个项目中需要引入预设,但不知道该引入那个,或者是引入的预设功能不可能全用,即包含了过多在某些情况下不需要的功能. 比如, 现代的浏览器大多支持ES6的generator, 但是如果你使用babel-preset-es2015, 它会将generator函数编译为复杂的ES5代码, 这是没有必要的。但使用babel-preset-env, 我们可以声明环境, 然后该preset就会只编译包含我们所声明环境缺少的特性的代码,因此也是比较推荐的方式。

目前官方以及将env提出一个新的项目了,可见env很不错,项目

Plugin

transform,sytanx 均是功能性的转换插件,具体列表参考官方的吧
helper 是插件内部使用用于插件的开发

Babel config

因为我目前使用 react 所以还是推荐使用 create-react-app 的 babel config

Reference