Modern JavaScript - Startup with Babel

  1. 1. 概念入门
    1. 1.1. plugin
      1. 1.1.1. ECMAScript 2015
      2. 1.1.2. ECMAScript 2016
      3. 1.1.3. ECMAScript 2017
    2. 1.2. preset
  2. 2. Babel 上手速成
    1. 2.1. runtime
    2. 2.2. build
    3. 2.3. babel-register
  3. 3. 最佳实践
    1. 3.1. 实战
  4. 4. REF::

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::