Modern JavaScript - Startup with Babel

  1. 1. plugin
    1. 1.1. ECMAScript 2015
    2. 1.2. ECMAScript 2016
    3. 1.3. ECMAScript 2017
  2. 2. preset
  3. 3. runtime
  4. 4. build
  5. 5. babel-register
  6. 6. 实战

Babel 对 Modern JavaScript 的推动功不可没,它使得开发者可以愉悦的享受新的语法带来的快感,然后再翻译成生产环境需要支持的旧的代码集。

JavaScript 的功能和版本之争吵了很多年,Babel 是个用行动来代替争吵的勇士。

当然更好的消息是,越来越多的功能被 node/浏览器 原生给实现,这意味着,越来越少的东西需要被编译。


## 概念入门

Babel 是一个转码器,它可以将 JavaScript 中的一个新语法进行转换,让旧的引擎支持。

翻译中的两个概念是 plugin & preset。

plugin

每个 plugin 对应的是一个 feature,可以在这里看到各个版本中对应的更新和 node 的支持度:http://node.green/

下面列出了 ECMA 近期版本中的一些变化点。每个点都是一个 plugin。

ECMAScript 2015

ES2015 确实是一个很大的改变,光看这个列表就能知道。使用该这些 plugins 可以将代码编译为 ES5 环境能执行的。

  • es2015-template-literals
  • es2015-literals
  • es2015-function-name
  • es2015-arrow-functions
  • es2015-block-scoped-functions
  • es2015-classes
  • es2015-object-super
  • es2015-shorthand-properties
  • es2015-duplicate-keys
  • es2015-computed-properties
  • es2015-for-of
  • es2015-sticky-regex
  • es2015-unicode-regex
  • es2015-constants
  • es2015-spread
  • es2015-parameters
  • es2015-destructuring
  • es2015-block-scoping
  • es2015-typeof-symbol
  • es2015-modules-commonjs

ECMAScript 2016

  • transform-exponentiation-operator

ECMAScript 2017

  • syntax-trailing-function-commas
  • transform-async-to-generator

preset

preset 就是一组 plugin 的集合,可以让开发都不用一个个的单独配置 plugin。

es2015, es2016, es2017 是目前三个主要的版本。

这三个版本中,相互没有包含关系,里面的 plugin 都是 ecma 所对应的 features.

最近加了一个 latest,它其实就是将上面三个 preset 再次包装了一次,使用起来更方便了。

1
2
3
4
5
presets: [
opts.es2015 !== false && [buildPreset, opts.es2015],
opts.es2016 !== false && require("babel-preset-es2016"),
opts.es2017 !== false && require("babel-preset-es2017")
]

除了 上面说的 ECMAScript 标准的集合,也会有一些自定义的集合可用。像

  • babel-preset-react

## Babel 上手速成
  • .babelrc
  • babel-cli
  • babel-register

Babel 常有两种使用方式,一个是即时的,常用在开发环境使用,快速,方便。
另一个是编译用的,用在线上发布使用。

runtime

在开发模式中,我们会用 babel-register 来做时时支持。但这样的效率不高,不适合用于 production 环境。

一个标准的 babel 配置如下,开发环境可以 require 这个配置,就能正常运行新的 feature 了。

1
2
3
4
require("babel-core/register")({
presets: ["es2017"],
plugins: ["transform-es2015-modules-commonjs"]
});

build

线上发布会使用 build 后的代码,.babelrc 是一个 build 所需要的配置文件,它的配置内容和 runtime 是一样的,只是写法有所不同。

1
2
3
4
5
{
"presets": ["es2017"],
"plugins": ["transform-es2015-modules-commonjs"],
"sourceMaps": "both"
}

babel-register

babel-register 模块改写 require 命令,为它加上一个钩子。此后,每当使用 require 加载 .js、.jsx、.es和 .es6 后缀名的文件,就会先用 Babel 进行转码。

需要注意的是,babel-register 只会对 require 命令加载的文件转码,而不会对当前文件转码。另外,由于它是实时转码,所以只适合在开发环境使用。

1
2
3
4
5
require("babel-core/register")({
presets: ['es2017']
});

require("./src/index.js");

entry.js 中是不能使用新语法的。一定要定义在另一个新文件中。


## 最佳实践

Babel 可以 javascript 翻译成任何一个你想到的旧版本。但如果环境已经支持的一些 feature 再被 transpile,就不够优雅了。

所以,更好的作法是,根据具体需求,来选择 preset/plugin,就翻译哪些。

Node 7 对这些语法的支持,已经接近完美了。(只差 async/esm),如果用到了这两个 feature,就直接加这些 plugin 好了。

实战

关于代码的组织结构,参考了 Rails,而不是 node/web 常用的 src 方案,因为我们相信很快,代码就不用再 build,而且直接上线。

Server 端用 Node.js 6.4.0,开发中用到的 feature 列表中,只有两项还暂不支持:

  • es2015 module-commonjs
  • es2017 async-functions

所以在配置 babel 时,根据自己的需求,只需要单独引入就可以了,这样,编译出来的代码几乎相同了,.babelrc 配置如下:

1
2
3
4
5
{
"presets": ["es2017"],
"plugins": ["transform-es2015-modules-commonjs"],
"sourceMaps": "both"
}

## REF::