« 回到博客列表

每天一点ES6(4):Babel

Tags: es6, babel

打脸

好吧,这个系列已经从一开始的日更变成现在周更都未必做得到了,啪!啪!啪!打脸呐!!!

好,打脸完毕,下面我们来说正事儿。

ES6无限好,就是用不了

尽管ES6发布有一阵子了,但各大浏览器的兼容工作才刚刚开始,最新版的 Chrome、Firefox、Safari 对 ES6 的支持度还处于起步阶段,而谁又能想到,Microsoft Edge 这次竟成黑马,现阶段的支持度已有80%左右,实战能力仅次于 Node.js 平台。

但相信大部分开发者的信仰归属依然是 Chrome 和 Firefox,现阶段要想在这些环境下试用 ES6,最好的办法就是借助一些转码器,将 ES6 的代码转换成 ES5 的等效实现。目前最靠谱的转码器非Babel莫属。

《圣经》的力量

第一眼看到这货的名字,就想到《圣经》(Bible),两者的拼写是何其的相似,果不其然,Babel 的英文释义是“巴别塔”,是《圣经》中提到的一座通天塔。

Babel 是目前支持度最高,同时也是使用最广泛的 ES6 转码器,Facebook、Mozilla、Yahoo、npm、MongoDB 等国内外上百家科技公司都在使用它。该项目最初的名称叫 6to5,用意非常明显。

Babel5 和 Babel6

Babel 有两个比较重要的大版本,Babel5 和 Babel6,后面的章节都以 Babel6 为例。

对新手而言 Babel 5 更加友好,因为只有 babel 一个命令行工具。Babel 6 将整套工具拆分为几个单独的工具和插件,更灵活,但上手也更麻烦。现在 Babel 5 虽然还能够安装,但已经没有什么卵用,命令行会提示你安装 Babel 6 的包。

Babel 的安装和配置

Babel 通过 npm 进行安装,这就需要你预先安装好 Node.js 的环境,前端发展到现在,不管你是否看好 Node.js 都免不了要和它打交道了。

Babel 官方推荐将 Babel 安装在本地,因为 Babel 的不同版本以及不同转码规则会起到不同的效果。当然全局和本地的版本并不冲突,在项目中会优先使用本地安装的,但如果是在项目之外有测试需要,全局安装过就会方便许多。

npm install --save-dev babel-cli
npm install -g babel-cli

光有一个 babel-cli 什么也做不了,我们还要为 Babel 安装语法插件。官方提供了几套预设的插件集合,分别适用于标准的 ES2015+、React 和 Flow 等。只是为了学习 ES6 的语法的话,选 env 就好了。

npm install --save-dev babel-preset-env

现在 ES 的发布周期确定为一年一个大版本,Babel 为每个年度的标准提供了单独的预设包,但如果每次出新特性都要改预设太麻烦(虽然基本上也就一年一次的样子),为此 Babel 官方推出了 env 预设(之前叫 latest,现在已经 deprecated 了),把从 ES2015 开始到当年的所有用于标准 ECMAScript 转码工具全部打包到一起,后续只需要升级这个包就好了。开发者还可以在.babelrc中设置要支持的环境范围,类似 auto-prefixer,以减少转码的工作量。

在项目根目录下创建一个.babelrc文件,注意这是个配置文件,以点号开头,没有后缀。Windows 系统是不允许直接创建这样格式的文件的,需要借助代码编辑器来新建文件。创建好后写入以下内容来启用预设:

{
  "presets": ["env"]
}

当然这段配置也可以写到package.json里,或是在构建工具的脚本中直接传入,但使用.babelrc配置文件的方式更加符合关注点分离的思想,必要时还能够满足代码复用的需求,推荐这种方法。

至此,我们就完成了 Babel 的安装,可以开始使用了。

通过命令行使用 Babel

对于全局安装了的用户,打开 Terminal 并切换到 JS 文件所在位置,就可以开始用了。下面的命令会将转码结果输出到 Terminal 的标准输出中:

babel es6.js

当然更多的时候我们是希望把结果放入文件中的:

babel es6.js -o es6-babeled.js

Babel 支持对文件进行监测,文件内容有改动,会自动执行转码,无需人工再干预。(通过 Ctrl/Command + C 结束)

babel es6.js --watch -o es6-babeled.js

Babel 还能批量处理整个路径下的 JS 文件,下面的代码把 src 目录下的文件批量转码,并放到 lib 目录下:

babel src -d lib

还可以从 Terminal 的标准输入中读取文件进行转码:

babel -o es6-babeled.js < es6.js

通过 npm 使用 Babel

全局安装的 Babel 适合偶尔测试一些代码片段,如果是在项目中使用,还是推荐本地安装,然后在package.json中的scripts属性中添加相关命令:"build": "babel src -d build",之后只要在项目根目录执行npm run build,就会自动调用本地版本的 Babel 对src目录下的 js 文件转码并将转码后的文件放到build目录下。

如果你使用了其他的构建/打包工具,如 Grunt、Gulp、Webpack、Rollup 等,也都有各自适用的 Babel 插件可以使用。

关于 npm 包的全局安装和本地安装

npm 的包分全局安装和本地安装,只有全局安装的包才能直接使用其命令行(如果有的话),因为全局安装过程会把命令行工具添加进环境变量,因而系统能够查找到。本地安装由于项目根目录不属于环境变量中,因此无法直接通过全局命令访问,但可以通过package.json中的scripts属性进行调用。

对于全局安装:

  • mac 和 linux 下是通过在/usr/local/bin目录下(环境变量中默认包含)创建软连接指向 npm 全局安装目录下对应的文件。
  • Windows 是在 Node 安装目录下的node_global目录中创建*.cmd后缀的脚本(Node 安装配置过程已将该目录添加至环境变量),通过脚本调用 npm 全局安装目录下对应的文件。

本地安装的命令行工具会在项目根目录下的 /node_modules/.bin 目录中创建一个软连接,指向本地安装目录下对应的入口文件,该目录下的命令都可以在package.json中的scripts属性中直接使用,node 会优先到 /node_modules/.bin目录查找,找不到再到父级node_modules目录找,直到全局目录。

本地安装的包也可以手动执行node_modules/package_name/bin/index.js来运行命令行工具(一般都是这么个套路,有“bin”目录就找“bin”目录,没有就具体看包的package.jsonmain字段的描述),package.json里的scripts属性里也可以这么写,尽管没有必要。

babel-node

babel-node 是随 babel-cli 一起安装的另一款命令行工具,是一个模拟 Node.js 环境的 REPL(Read-Evel-Print Loop,一种循环执行“读取-执行-输出”的程序)。执行babel-node会进入一个类似 Node.js 的环境,在这里你可以直接运行 ES6 的代码。你也可以用形如babel-node es6.js的命令来直接运行用 ES6 编写的文件,babel-node 会在运行代码之前先将其编译成 ES5 的等效代码,然后执行。

甚至可以改写package.json文件,用 babel-node 替代 node 命令来直接运行。

{
  "scripts": {
    "run-node": "babel-node app.js"    // 需替换成实际文件名
  }
}

此时执行npm run script就等同于执行babel-node script.js

babel-doctor(新版中已移除)

看名字就知道,这个工具大概是排错用的。没错,如果在命令行中执行babel命令有问题的,可以用它来检查一下环境配置是否正确。babel-doctor主要检查以下几项内容:

在 Node.js 中使用 Babel

在 Node.js 环境中,可以直接在 js 文件里调用 Babel 的转码功能。

babel-register

该模块给require()加上一个钩子,加载它之后,每当再 require 其他 js、jsx、es、es6 类型的文件,就会先用 Babel 进行转码。需要注意的是,使用该模块的文件本身并不会被转码,需要从外部执行转码。另外由于是实时转码,从效率上考虑不适用与生产环境,仅供学习研究使用。

babel-core

这是 Babel 的核心 API 所在,在项目中加载该模块var babel = require("babel-core");,然后就可以通过babel.transform(code, options)方法来执行转码,code是待转码的 ES6 代码字符串,options提供了一些转码说明,例如指定语法规则、启用一些插件、设定编码等,具体用法可以参考这里

babel-polyfill

Babel 默认只转码 ES6 的新语法(syntax),而不转换新的API,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign、Array.from)都不会转码。如果想让这写方法运行,必须require("babel-polyfill")

在浏览器中使用 Babel

在命令行中使用 Babel 虽然在功能性上没得挑,但毕竟还有各种配置,多少有点麻烦。Babel 提供了一种可以在浏览器中使用的方法,只需两步就能一劳永逸。这个方法唯一的缺点就是实时转码需要时间,性能上不及预先转换的方案,因此生产环境中不推荐使用,仅供学习研究使用。

首先我们需要下载browser.js,注意,这是 Babel 5 的版本,Babel 6 开始不再直接提供该文件,需要自行构建。

除了从上面的链接下载,你也可以用 npm 下载:

npm install babel-core@5

下载后在node_modules/babel-core子目录中就能找到browser.js文件。

使用方法如下:

<script src="node_modules/babel-core/browser.js"></script>
<script type="text/babel" src="your_own_es6_file.js"></script>

有两点需要注意

  1. browser.js 文件必须放在你自己的 js 文件之前
  2. 你自己的文件的类型要写成type="text/babel"

在线试用 Babel

有时候我们并不需要在项目中操作什么,纯粹就想看看 Babel 到底做了什么。为此 Babel 官方提供了一套在线的REPL (Read-Eval-Print-Loop),可以方便的试用 Babel。

路由查询命令的近亲 —— Traceur

除了 Babel 之外,还有一款不错的 ES6 转码器叫做Traceur,是由科技巨头 Google 开发的,支持度虽然差 Babel 一大截,但使用非常简单,可以作为备用方案。Traceur 同样支持浏览器、在线 REPL、命令行、Node.js 四种环境下的使用。

学过计算机网络的同学,或多或少都应该听说过 Linux 下的 tracerouter 命令,和 Windows 下的 tracert命令。这两个命令都是用来追踪数据包从起点到终点所经过的路由的。而 Traceur 的名字,和它们实在是太像了,科技圈的命名方式真是一道风景。

该系列的其他文章

上一篇:每天一点ES6(3):解构赋值

下一篇:每天一点ES6(5):字符串的扩展