这个文档涵盖了所有你想知道的关于 Babel 及其相关工具使用的所有内容。
Babel 是一个用于 JavaScript 的通用多用途编译器,使用 Babel 可以使用(或创建)下一代 的JavaScript,以及下一代 JavaScript 工具。 作为一门语言,JavaScript 不断发展,带来了很多新的规范和建议,使用 Babel 可以让你在这些新的规范和建议全面普及之前就提前使用它们。 Babel 通过将最新标准的 JavaScript 代码编译为已经在目前可以工作的代码来实现上一段提到的内容。这个过程被称为 “源代码到源代码” 的编译,这也被成为 “转换”。
例如,Babel 可以将最新的 ES2015 的箭头函数语法从:
代码语言:javascript复制const square = n => n * n;
复制代码
转换成下面的内容:
代码语言:javascript复制const square = function square(n) {
return n * n;
};
复制代码
然而,Babel 可以胜任更多的工作,因为Babel 支持语法扩展,例如 React 的 JSX 语法或者静态类型检查的 Flow 语法。 更近一步,在 Babel 中一切皆插件,而每个人都可以充分利用 Babel 的强大能力来创建属于自己的插件。且 Babel 被组织成几个核心的模块,允许用户利用这些模块来构建下一代 JavaScript 工具链。 许多人也是这样去做的,Babel 的生态系统正在茁长的成长。在这本 Babel 手册中,我将讲解 Babel 内建的一些工具以及社区里的一些拥有的工具。
Babel模块介绍
因为 JavaScript 社区没有标准的构建工具,框架或平台等,Babel 官方性与其他所有的主要工具进行了集成。无论是来自 Gulp、Browserify,或者是 Ember、Meteor,亦或是 Webpack 等,无论你的启动工具是什么,Babel 都存在一些官方性的集成。 就本手册而言,我们将介绍设置Babel的内置方法,但是您也可以访问交互式设置页面[1] 以了解所有集成。
babel-cli
Babel的CLI是从命令行使用Babel编译文件的简单方法。 让我们首先在全局安装它以学习基础知识。
代码语言:javascript复制npm install --global babel-cli
我们可以像这样编译我们的第一个文件:
代码语言:javascript复制 babel my-file.js
这会将编译后的输出直接转储到您的终端中。要将其写入文件,我们将指定 --out-file 或 -o
代码语言:javascript复制 babel example.js --out-file compiled.js
#or
babel example.js -o compiled.js
如果我们想将整个目录编译成一个新目录,可以使用 --out-dir 或 -d 来完成。
代码语言:javascript复制babel src --out-dir lib
#or
babel src -d lib
从项目中运行Babel CLI
虽然您可以在计算机上全局安装Babel CLI,但最好逐个项目在本地安装它。 这有两个主要原因。
- 同一台计算机上的不同项目可能取决于Babel的不同版本,从而允许您一次更新一个版本。
- 这意味着您对工作的环境没有隐式依赖。使您的项目更加可移植且易于设置。
我们可以通过运行以下命令在本地安装Babel CLI:
代码语言:javascript复制npm install --save-dev babel-cli
代码语言:javascript复制注意:由于在全局范围内运行 Babel 通常是一个坏主意,因此您可能需要通过运行以下命令来卸载全局副本:
npm uninstall --global babel-cli
完成安装后,您的 package.json 文件应如下所示:
代码语言:javascript复制{
"name": "my-project",
"version": "1.0.0",
"devDependencies": {
"babel-cli": "^6.0.0"
}
}
现在,与其直接从命令行运行 Babel,不如将命令放入使用本地版本的 npm 脚本中。只需在您的 package.json 中添加一个 “script” 字段,然后将 babel 命令放入其中即可进行构建。
代码语言:javascript复制{
"name": "my-project",
"version": "1.0.0",
"scripts": {
"build": "babel src -d lib"
},
"devDependencies": {
"babel-cli": "^6.0.0"
}
}
现在,从我们的终端我们可以运行:
代码语言:javascript复制npm run build
这将以与以前相同的方式运行Babel,只是现在我们正在使用本地副本。
babel-register
运行Babel的下一个最常见的方法是通过 babel-register 。通过此选项,您仅需要文件即可运行 Babel,这可能会更好地与您的设置集成。
请注意,这并非供生产使用。部署以这种方式编译的代码被认为是不好的做法。最好在部署之前提前进行编译。但是,这对于构建脚本或您在本地运行的其他事情非常有效。 首先让我们在项目中创建一个 index.js 文件。
代码语言:javascript复制console.log("Hello world!");
如果我们使用 node index.js
来运行它,那么 Babel 不会编译它。因此,我们需要先设置 babel-register 。 首先安装 babel-register
。
npm install --save-dev babel-register
接下来,在项目中创建一个 register.js 文件,并编写以下代码:
代码语言:javascript复制require("babel-register");
require("./index.js");
这是在 Node 的模块系统中注册 Babel 并开始编译每个 require 的文件。 现在,我们可以使用 node egister.js 代替运行 node index.js 。
代码语言:javascript复制 node register.js
注意:您不能在要编译的文件中注册 Babel。在 Babel 有机会编译文件之前,Node 正在执行文件。
代码语言:javascript复制require("babel-register");
// not compiled:
console.log("Hello world!");
babel-node
如果您只是通过 node CLI
运行某些代码,则集成 Babel 的最简单方法可能是使用 babel-node CLI,
这在很大程度上只是对 node CLI 的替代。 请注意,这并非供生产使用。部署以这种方式编译的代码被认为是不好的做法。最好在部署之前提前进行编译。但是,这对于构建脚本或您在本地运行的其他事情非常有效。 首先,请确保您已安装 babel-cli 。
npm install --save-dev babel-cli
**注意:**如果您想知道为什么要在本地安装此软件,请在上面的项目部分中阅读 “从项目中运行 Babel CLI”。 然后,将运行 node 的任何位置替换为 babel-node 。 如果您使用的是 npm script ,则只需执行以下操作:
代码语言:javascript复制{
"scripts": {
- "script-name": "node script.js"
"script-name": "babel-node script.js"
}
}
否则,您将需要写出通向 babel-node 本身的路径。
代码语言:javascript复制- node script.js
./node_modules/.bin/babel-node script.js
babel-core
如果出于某种原因需要在代码中使用 Babel,则可以使用 babel-core 软件包本身。 首先安装 babel-core 。
代码语言:javascript复制npm install babel-core
代码语言:javascript复制var babel = require("babel-core");
如果您具有 JavaScript 字符串,则可以直接使用 babel.transform 对其进行编译。
代码语言:javascript复制babel.transform("code();", options);
// => { code, map, ast }
如果使用文件,则可以使用异步api:
代码语言:javascript复制babel.transformFile("filename.js", options, function(err, result) {
result; // => { code, map, ast }
});
如果您出于任何原因已经拥有Babel AST,则可以直接从AST转换。
代码语言:javascript复制babel.transformFromAst(ast, code, options);
对于上述所有方法, options 可以传递指南可以从这里了解 babeljs.io/docs/usage/…
配置 Babel
您现在可能已经注意到,仅运行 Babel 似乎除了将 JavaScript 文件从一个位置复制到另一个位置之外没有执行任何其他操作。 这是因为我们尚未告诉 Babel 该做什么事情。
由于Babel是通用编译器,它以多种不同的方式使用,因此默认情况下它不会执行任何操作。您必须明确告诉Babel 它应该做什么。
您可以通过安装 plugins 或 presets (plugins 组)为Babel提供操作说明。
.babelrc
在我们开始告诉 Babel 怎么做之前。我们需要创建一个配置文件。您需要做的就是在项目的根目录下创建一个 .babelrc 文件。从这样开始:
代码语言:javascript复制{
"presets": [],
"plugins": []
}
该文件是您配置 Babel 以执行所需操作的方式。
注意:虽然您还可以通过其他方式将选项传递给 Babel,但 .babelrc 文件是约定俗成的,也是最好的方法。
babel-preset-es2015
让我们首先告诉 Babel 将 ES2015(JavaScript标准的最新版本,也称为ES6)编译为ES5(当今大多数JavaScript环境中可用的版本)。 我们将通过安装“ es2015” Babel预设来做到这一点(当然目前浏览器支持了绝大部分 ES2015 的特性了,这里是用作演示,使用形式是一致的):
代码语言:javascript复制 npm install --save-dev babel-preset-es2015
接下来,我们将修改 .babelrc 以包括该预设。
代码语言:javascript复制 {
"presets": [
"es2015"
],
"plugins": []
}
babel-preset-react 设置 React 同样简单。只需安装预设:
代码语言:javascript复制$ npm install --save-dev babel-preset-react
然后将预设添加到您的 .babelrc 文件中:
代码语言:javascript复制{
"presets": [
"es2015",
"react"
],
"plugins": []
}
babel-preset-stage-x
JavaScript还提出了一些建议,这些建议正在通过TC39(ECMAScript标准背后的技术委员会)流程纳入标准。 此过程分为5个阶段(0-4)。随着提案获得更大的吸引力,并更有可能被采纳为标准,它们经历了各个阶段,最终在阶段4被接纳为标准。 这些以babel的形式捆绑为4种不同的预设:
- babel-preset-stage-0
- babel-preset-stage-1
- babel-preset-stage-2
- babel-preset-stage-3
请注意,没有阶段 4 的 preset ,因为它只是上面的 es2015 预设。 这些预设中的每个预设都需要用于后续阶段的预设。即 babel-preset-stage-1 需要 **babel-preset-stage-2 ** ,而 babel-preset-stage-3 也需要。
安装您感兴趣的 stage 很简单:
代码语言:javascript复制npm install --save-dev babel-preset-stage-2
然后,您可以将其添加到您的 .babelrc 配置中。
代码语言:javascript复制{
"presets": [
"es2015",
"react",
"stage-2"
],
"plugins": []
}
执行 Babel 生成的代码
目前,您已经使用Babel编译了代码,但这还不是故事的结局。
babel-polyfill
几乎所有未来 JavaScript 语法都可以使用 Babel 进行编译,但 API 并非如此。 例如,以下代码具有需要编译的箭头函数功能:
代码语言:javascript复制function addAll() {
return Array.from(arguments).reduce((a, b) => a b);
}
在编译之后会变成如下这样:
代码语言:javascript复制function addAll() {
return Array.from(arguments).reduce(function(a, b) {
return a b;
});
}
但是,由于 Array.from 并非在每个JavaScript环境中都存在,因此在编译之后它仍然无法使用:
代码语言:javascript复制Uncaught TypeError: Array.from is not a function
为了解决这个问题,我们使用一种叫做 Polyfill[3] 的东西。简而言之,Polyfill 是一段代码,该代码复制当前运行时中不存在的 API,允许您在当前环境可用之前能提前使用 Array.from 等 API。 Babel使用出色的 core-js[4] 作为其polyfill,以及定制的 regenerator[5] 运行时,以使生成器和异步函数正常工作。 要包含 Babel polyfill,请首先使用npm安装它:
代码语言:javascript复制npm install --save babel-polyfill
然后只需将 polyfill 包含在任何需要它的文件的顶部:
代码语言:javascript复制import "babel-polyfill";
babel-runtime
为了实现 ECMAScript 规范的详细信息,Babel将使用 “helper” 方法来保持生成的代码干净。 由于这些 “helper” 方法会变得很长,而且它们被添加到每个文件的顶部,因此您可以将它们移动到 require 的单个“运行时”中。
首先安装 babel-plugin-transform-runtime 和 babel-runtime :
代码语言:javascript复制 npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime
然后更新您的 .babelrc :
代码语言:javascript复制{
"plugins": [
"transform-runtime",
"transform-es2015-classes"
]
}
现在,Babel 将如下代码:
代码语言:javascript复制class Foo {
method() {}
}
编译成这样:
代码语言:javascript复制import _classCallCheck from "babel-runtime/helpers/classCallCheck";
import _createClass from "babel-runtime/helpers/createClass";
let Foo = function () {
function Foo() {
_classCallCheck(this, Foo);
}
_createClass(Foo, [{
key: "method",
value: function method() {}
}]);
return Foo;
}();
而不是将 _classCallCheck 和 _createClass helper 函数放在需要的每个文件中。
配置 Babel(进阶版)
大多数人都可以通过仅使用内置预设来使用 Babel,但是 Babel 所展现的功能远不止于此
手动指定插件
Babel 预设只是预配置插件的集合,如果您想做不同的事情,可以手动指定插件。这几乎与预设完全相同。 首先安装一个插件:
代码语言:javascript复制npm install --save-dev babel-plugin-transform-es2015-classes
然后将 plugins 字段添加到您的 .babelrc 中。
代码语言:javascript复制 {
"plugins": [
"transform-es2015-classes"
]
}
插件选项
许多插件还具有将其配置为不同行为的 option 。例如,许多 transform 都具有 loose 模式,该模式会放弃某些规范行为,而倾向于使用更简单,性能更高的代码。 要将选项添加到插件,只需进行以下更改:
代码语言:javascript复制{
"plugins": [
- "transform-es2015-classes"
["transform-es2015-classes", { "loose": true }]
]
}
根据环境定制 Babel
Babel插件解决了许多不同的任务。其中许多是开发工具,可以帮助您调试代码或与工具集成。还有许多用于优化生产中代码的插件。 因此,通常需要基于环境的 Babel 配置。您可以使用 .babelrc 文件轻松完成此操作。
代码语言:javascript复制 {
"presets": ["es2015"],
"plugins": [],
"env": {
"development": {
"plugins": [...]
},
"production": {
"plugins": [...]
}
}
}
Babel将根据当前环境在 env 内部启用配置。 当前环境将使用 process.env.BABEL_ENV 。当 BABEL_ENV 不可用时,它将回退到 NODE_ENV ,如果不可用,则默认为“ development ”。
构建自己的预设
手动指定插件?插件选项?基于环境的设置?对于所有项目,所有这些配置似乎都需要重复很多次。 因此,我们鼓励社区创建自己的预设。这可以是您整个公司[10]的预设。 创建预设很容易。假设您有以下 .babelrc 文件:
代码语言:javascript复制{
"presets": [
"es2015",
"react"
],
"plugins": [
"transform-flow-strip-types"
]
}
您需要做的就是按照命名约定 babel-preset-* 创建一个新项目(请对此命名空间负责!),并创建两个文件。 首先,创建一个新的 package.json 文件,该文件具有您的预设所需的 dependencies 关系。
代码语言:javascript复制{
"name": "babel-preset-my-awesome-preset",
"version": "1.0.0",
"author": "James Kyle ",
"dependencies": {
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-plugin-transform-flow-strip-types": "^6.3.15"
}
}
然后创建一个 index.js 文件,该文件导出 .babelrc 文件的内容,并用 require 调用替换插件/预设字符串。
代码语言:javascript复制module.exports = {
presets: [
require("babel-preset-es2015"),
require("babel-preset-react")
],
plugins: [
require("babel-plugin-transform-flow-strip-types")
]
};
Babel 和其他工具结合
一旦掌握了 Babel,Babel 便会很直接地进行设置,但是使用其他工具进行设置可能非常困难。但是,我们尝试与其他项目紧密合作,以使体验尽可能轻松。
静态分析工具
较新的标准为语言带来了许多新语法,而静态分析工具才刚刚开始利用它。
Linting
ESLint 是最受欢迎的 Lint 工具之一,因此,我们维护了官方的 babel-eslint[11] 集成。首先安装 eslint 和 babel-eslint 。
代码语言:javascript复制npm install --save-dev eslint babel-eslint
接下来,在项目中创建或使用现有的 .eslintrc 文件,并将解析器设置为 babel-eslint 。
代码语言:javascript复制 {
"parser": "babel-eslint",
"rules": {
...
}
}
现在将一个 lint 任务添加到您的 npm package.json 脚本中:
代码语言:javascript复制 {
"name": "my-module",
"scripts": {
"lint": "eslint my-files.js"
},
"devDependencies": {
"babel-eslint": "...",
"eslint": "..."
}
}
然后只需运行任务即可完成所有设置。
代码语言:javascript复制npm run lint