- 文档
- 教程
【免费下载链接】babel-handbook
:blue_book: A guided handbook on how to use Babel and how to create plugins for Babel.
本指南以本仓库内 translations/vi/user-handbook.md(Babel User Handbook 的越南语译本)为完整骨架展开。Babel 是一个通用的 JavaScript 编译器(即 transpiler),本文将从"为什么要编译"讲起,系统覆盖 Babel 的四种接入方式(
babel-cli、babel-register、babel-node、babel-core)、.babelrc与官方 Preset 配置、编译产物运行所需的 Polyfill 与 Runtime、进阶的插件细粒度控制与环境化配置,以及 Babel 与 ESLint、React、编辑器等周边工具的集成方案。读完本文,你将能够独立完成 Babel 项目的接入、编译与配置,并理解其源码到源码编译的核心原理。需要提醒的是,文中包名与命令基于文档所描述的经典工具链(示例中版本号为^6.0.0),如使用其他版本的 Babel,请以对应版本的官方文档为准。
认识 Babel:为什么需要它
JavaScript 语言本身在持续演进,新规范和新提案不断带来新特性。Babel 的核心价值在于:它可以把使用最新标准书写的 JavaScript 代码,编译成当前各种环境都能运行的版本。这一过程被称为 source-to-source compiling(源码到源码编译),也就是我们常说的 transpiling(转译)。
文档给出了最经典的例子——把 ES2015 的箭头函数:
const square = n => n * n;转译成 ES5 的普通函数:
const square = function square(n) { return n * n; };但这只是 Babel 能力的冰山一角:
- 语法扩展:Babel 还支持 JSX(React 的模板语法)与 Flow(静态类型检查语法)等语法扩展;
- 一切皆插件:Babel 中几乎所有能力都以插件(plugin)形式存在,任何人都可以利用 Babel 的完整能力编写自己的插件;
- 核心模块化:Babel 被拆分为若干核心模块,这些模块可以被单独拿来构建"下一代 JavaScript 工具"。
理解这一点非常重要:Babel 默认不会对代码做任何转换。它是一个被广泛复用、用途各异的通用编译器,你必须显式告诉它"要做什么"——通过安装插件(plugins)或Preset(预设,即一组插件的集合)来下达指令。
安装与运行 Babel:四种官方接入方式
由于 JavaScript 社区没有统一的构建工具,Babel 为各大主流工具链都提供了官方集成(从 Gulp 到 Browserify,从 Ember 到 Meteor)。本文只覆盖 Babel 内置的四种接入方式,它们适用于不同场景。
前置要求:下文命令依赖
node与npm,请确保你已熟悉这两个命令行工具。
babel-cli:命令行编译
Babel 的 CLI 是从命令行编译文件最简单的方式。先全局安装以学习基本用法:
$ npm install --global babel-cli编译单个文件:
$ babel my-file.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在项目内运行 Babel CLI
虽然可以全局安装 Babel CLI,但更推荐在每个项目内本地安装,原因有两个:
- 同一台机器上的不同项目可以依赖不同版本的 Babel,从而逐个升级互不影响;
- 项目不再隐式依赖所在环境,可移植性更强、更易搭建。
本地安装:
$ npm install --save-dev babel-cli注:全局运行 Babel 通常不是好主意,可以通过
npm uninstall --global babel-cli卸载全局副本。
安装完成后,package.json应包含如下内容:
{ "name": "my-project", "version": "1.0.0", "devDependencies": { "babel-cli": "^6.0.0" } }接着,把命令写进npm scripts,让脚本使用本地版本而不是直接调用命令行。为package.json添加"scripts"字段,并把 Babel 命令作为build任务:
{ "name": "my-project", "version": "1.0.0", + "scripts": { + "build": "babel src -d lib" + }, "devDependencies": { "babel-cli": "^6.0.0" } }然后从终端运行:
$ npm run build效果与之前一致,区别在于现在使用的是项目内的本地副本。
babel-register:通过 require 即时编译
第二种常见方式是通过babel-register:只需require文件即可触发 Babel 编译,与现有项目结构集成度更高。
注意:
babel-register不适合生产环境。以这种方式编译后部署被视为不良实践,更好的做法是部署前预先编译完成。但它非常适合本地运行的构建脚本等场景。
首先在项目中创建index.js:
console.log("Hello world!");直接运行node index.js不会经过 Babel 编译,因此我们改用babel-register。先安装:
$ npm install --save-dev babel-register再创建register.js:
require("babel-register"); require("./index.js");这段代码的作用是把 Babel注册进 Node 的模块系统,此后所有被require的文件都会先经过 Babel 编译。
现在用register.js代替node index.js:
$ node register.js注意:不能在你希望被编译的同一个文件里注册 Babel,因为 Node 执行该文件时 Babel 还没来得及编译它:
require("babel-register"); // 不会编译: console.log("Hello world!");
babel-node:node 的直接替代品
如果只是通过nodeCLI 运行一些代码,最简单的集成方式是用babel-nodeCLI——它基本是nodeCLI 的即插即用替代品。
注意:同样不适合生产环境,理由与
babel-register一致;但非常适合本地构建脚本。
先确保安装了babel-cli:
$ npm install --save-dev babel-cli关于为何要本地安装,可回顾上文 在项目内运行 Babel CLI 一节。
然后把所有运行node的地方替换为babel-node。如果使用 npmscripts,只需:
{ "scripts": { - "script-name": "node script.js" + "script-name": "babel-node script.js" } }否则需要写出babel-node的完整路径:
- node script.js + ./node_modules/.bin/babel-node script.js提示:也可以借助
npm-run这类工具来简化本地二进制调用。
babel-core:以编程方式调用 Babel
如果你需要在代码中程序化地使用 Babel,可以直接使用babel-core包。先安装:
$ npm install babel-corevar babel = require("babel-core");如果有一段 JavaScript 字符串,可直接用babel.transform编译:
babel.transform("code();", options); // => { code, map, ast }如果处理的是文件,可以使用异步 API:
babel.transformFile("filename.js", options, function(err, result) { result; // => { code, map, ast } });或同步 API:
babel.transformFileSync("filename.js", options); // => { code, map, ast }如果你手中已经有一个 Babel 的 AST(抽象语法树),也可以直接从 AST 转换:
babel.transformFromAst(ast, code, options); // => { code, map, ast }以上所有方法都会返回{ code, map, ast }三件套:code是编译后的代码字符串,map是 source map(便于调试时映射回源码),ast是转换后的抽象语法树。其中transformFromAst的存在也印证了 Babel 的流水线本质:解析(parse)→ 遍历与转换(transform)→ 生成(generate),任何一环都可以被单独接管。关于 AST 与各核心模块(babylon、babel-traverse、babel-types、babel-generator等)的深入内容,可参考本仓库的姊妹篇 Babel Plugin Handbook。
配置 Babel:.babelrc与官方 Preset
你可能已经注意到:单独运行 Babel 时,它似乎只是把 JS 文件从一个位置复制到另一个位置,什么都没做。原因正如前文所说——Babel 默认不做任何事,必须通过安装插件或 Preset 来明确指示行为。
.babelrc配置文件
首先需要在项目根目录创建.babelrc配置文件,初始内容如下:
{ "presets": [], "plugins": [] }这个文件就是你配置 Babel 行为的入口。
注:虽然也可以通过其他方式向 Babel 传参,但
.babelrc是社区约定俗成、也是最推荐的配置方式。
babel-preset-es2015:编译 ES2015
先让 Babel 把 ES2015(最新版 JavaScript 标准,即 ES6)编译成 ES5(当时绝大多数环境可用的版本)。安装 "es2015" Preset:
$ npm install --save-dev babel-preset-es2015然后修改.babelrc,加入该 Preset:
{ "presets": [ + "es2015" ], "plugins": [] }babel-preset-react:支持 JSX 与 React
接入 React 同样简单。安装 Preset:
$ npm install --save-dev babel-preset-react然后把它加入.babelrc:
{ "presets": [ "es2015", + "react" ], "plugins": [] }babel-preset-stage-x:TC39 提案阶段
JavaScript 中还有一些正在进入标准的提案,它们经由 TC39(负责 ECMAScript 标准的技术委员会)流程推进。该流程分为 5 个阶段(0–4):提案获得的关注越多、越可能被纳入标准,就会逐级前进,最终在阶段 4 被正式纳入标准。
这些提案在 Babel 中以 4 个 Preset 打包提供:
babel-preset-stage-0babel-preset-stage-1babel-preset-stage-2babel-preset-stage-3
注意:不存在 stage-4 Preset,因为阶段 4 的提案就是上面提到的
es2015Preset 所覆盖的内容。
这些 Preset 之间存在依赖链:babel-preset-stage-1依赖babel-preset-stage-2,而babel-preset-stage-2又依赖babel-preset-stage-3(即后阶段 Preset 自动包含更早期提案的转换能力,安装一个即可获得完整链路)。
按需安装感兴趣的阶段:
$ npm install --save-dev babel-preset-stage-2然后加入.babelrc:
{ "presets": [ "es2015", "react", + "stage-2" ], "plugins": [] }运行 Babel 生成的代码:Polyfill 与 Runtime
代码编译完成并不意味着大功告成——编译后的代码在目标环境中能否真正运行,是另一个问题。
babel-polyfill:补齐缺失的 API
几乎所有的"未来语法"都可以被 Babel 编译,但API 不行。语法可以转译,运行时缺失的内建方法却无法靠转译凭空造出来。
文档给出了一个典型例子。下面的代码含有一个需要编译的箭头函数:
function addAll() { return Array.from(arguments).reduce((a, b) => a + b); }编译后变成:
function addAll() { return Array.from(arguments).reduce(function(a, b) { return a + b; }); }然而它在某些环境仍然无法运行,因为Array.from并非在所有 JavaScript 环境中都存在:
Uncaught TypeError: Array.from is not a function解决这个问题需要用到Polyfill(垫片)。简单说,polyfill 是一段模拟当前运行时中不存在之原生 API 的代码,让你能在Array.from等 API 正式普及之前就使用它们。
Babel 使用优秀的 core-js 作为其 polyfill 基础,并配合定制化的 regenerator runtime 来让 generator 和 async 函数正常工作。
引入方式:先用 npm 安装:
$ npm install --save babel-polyfill然后在任何需要它的文件顶部引入:
import "babel-polyfill";注意安装参数是--save(运行时依赖),因为 polyfill 是随应用运行的代码,而不是构建期工具。
babel-runtime:抽取公共 helper 代码
为了按 ECMAScript 规范实现某些细节,Babel 会使用一些 "helper" 方法以保证生成代码的整洁。这些 helper 通常较长,且会被追加到每个文件的顶部,造成大量重复。解决办法是把它们集中到一个统一的 "runtime" 中,通过require按需引入。
先安装babel-plugin-transform-runtime(构建期插件)和babel-runtime(运行时依赖):
$ npm install --save-dev babel-plugin-transform-runtime $ npm install --save babel-runtime然后更新.babelrc:
{ "plugins": [ + "transform-runtime", "transform-es2015-classes" ] }现在 Babel 会把如下代码:
class Foo { method() {} }编译成:
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-runtime与babel-polyfill的分工差异:前者管"编译期抽出的 helper 共享",后者管"运行时缺失 API 的补齐"。
进阶配置:细粒度控制
对大多数项目而言,使用内置 Preset 就够了。但 Babel 暴露了远比这精细的控制能力。
手动指定插件
Preset 本质上就是一组预先配置好的插件集合。如果你想自定义组合,可以手动指定插件,用法与 Preset 几乎一致。
先安装插件:
$ npm install --save-dev babel-plugin-transform-es2015-classes再把plugins字段加入.babelrc:
{ + "plugins": [ + "transform-es2015-classes" + ] }这让你对具体执行的转换拥有更细粒度的控制。官方插件的完整列表、以及社区构建的各类babel-plugin-*包,都是值得检索的资源;如果你希望学习如何编写自己的插件,请阅读本仓库的 Babel Plugin Handbook。
插件选项(Plugin Options)
许多插件还提供选项以改变行为。例如,大量转换插件都有 "loose" 模式:以牺牲部分规范行为为代价,换取更简单、性能更好的生成代码。
给插件添加选项只需把字符串形式的插件名改为数组形式:
{ "plugins": [ - "transform-es2015-classes" + ["transform-es2015-classes", { "loose": true }] ] }数组的第一个元素是插件名,第二个元素是选项对象。loose: true是最常见的一个选项,此外不同插件还有各自的专属选项,具体以对应插件文档为准。
基于环境定制配置(env)
Babel 插件解决的问题多种多样:很多是辅助调试或对接工具的开发期插件,也有很多是用于生产环境代码优化的插件。因此,按环境切换 Babel 配置是常见需求,.babelrc原生支持:
{ "presets": ["es2015"], "plugins": [], + "env": { + "development": { + "plugins": [...] + }, + "production": { + "plugins": [...] + } } }Babel 会根据当前环境启用env中对应的配置。环境判定顺序如下:
- 优先使用
process.env.BABEL_ENV; - 若
BABEL_ENV不可用,回退到NODE_ENV; - 若两者都不可用,默认值取
"development"。
在命令行中设置环境变量的方式因平台而异:
Unix
$ BABEL_ENV=production [COMMAND] $ NODE_ENV=production [COMMAND]Windows
$ SET BABEL_ENV=production $ [COMMAND]注:
[COMMAND]指你运行 Babel 所使用的任意命令(如babel、babel-node,若使用 register 钩子也可能是node)。提示:如果希望命令在 Unix 和 Windows 上都可运行,可以借助
cross-env这类工具跨平台地设置环境变量。
制作自己的 Preset
手动指定插件、插件选项、按环境配置……所有这些配置如果要在每个项目中重复书写,显然是巨大的重复劳动。为此,社区被鼓励创建自己的 Preset——可以是为特定 Node 版本定制的 Preset,也可以是覆盖整个公司规范的 Preset。
创建 Preset 很容易。假设你有这样一份.babelrc:
{ "presets": [ "es2015", "react" ], "plugins": [ "transform-flow-strip-types" ] }你只需创建一个遵循babel-preset-*命名规范的新项目(请对babel-preset-命名空间保持责任感),并创建两个文件。
第一个是package.json,声明 Preset 所需的dependencies:
{ "name": "babel-preset-my-awesome-preset", "version": "1.0.0", "author": "James Kyle <me@thejameskyle.com>", "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的内容导出,并将插件/Preset 字符串替换为require调用:
module.exports = { presets: [ require("babel-preset-es2015"), require("babel-preset-react") ], plugins: [ require("babel-plugin-transform-flow-strip-types") ] };最后发布到 npm,就能像使用任何内置 Preset 一样使用它了。
Babel 与周边工具生态
Babel 本身配置起来并不复杂,但如何与其他工具协同,往往是新手最困惑的地方。Babel 团队与众多项目保持紧密合作,以尽量降低集成难度。
静态分析:ESLint +babel-eslint
新标准为语言带来大量新语法,静态分析工具也在逐步跟进。ESLint 是最流行的 lint 工具之一,Babel 官方维护了babel-eslint集成。
安装eslint和babel-eslint:
$ npm install --save-dev eslint babel-eslint在项目现有的.eslintrc中把parser设为babel-eslint:
{ + "parser": "babel-eslint", "rules": { ... } }再往 npmpackage.jsonscripts 中添加lint任务:
{ "name": "my-module", "scripts": { + "lint": "eslint my-files.js" }, "devDependencies": { "babel-eslint": "...", "eslint": "..." } }然后运行任务即可:
$ npm run lint更多细节可查阅babel-eslint与eslint各自的官方文档。
代码风格检查(Code Style)
注:JSCS 已并入 ESLint,因此代码风格检查也可以直接使用 ESLint 实现。
JSCS 曾是把 lint 推进到"检查代码风格本身"的流行工具,Babel 与 JSCS 两个项目的核心维护者提供了官方集成。更棒的是,该集成后来直接内置于 JSCS 的--esnext选项中,因此接入 Babel 只需一行:
$ jscs . --esnext或者在.jscsrc文件中加上esnext选项:
{ "preset": "airbnb", + "esnext": true }文档生成(Documentation)
借助 Babel、ES2015 与 Flow,你可以从代码中推断出大量信息。使用documentation.js可以非常轻松地生成详尽的 API 文档——它在幕后正是利用 Babel 来支持包括 Flow 类型注解在内的最新语法,从而在文档中声明代码中的类型。
框架集成:React 与 JSX
各大主流 JavaScript 框架都在围绕语言的未来调整 API,这带来大量工具链投入。框架不仅可以使用 Babel,还能以扩展 Babel 的方式改善用户体验。
React 是典型代表:它大幅调整 API 以对齐 ES2015 的 class 写法,并且依赖 Babel 来编译其 JSX 语法,逐步废弃了自己的定制工具链。你可以按照前文 babel-preset-react 一节的步骤直接开始。
React 社区还基于 Babel 构建了众多转换插件,其中最具代表性的是babel-plugin-react-transform,它与一系列 React 专属 transform 组合,可以实现hot module reloading(热模块替换)以及其他调试工具。
文本编辑器与 IDE
引入 ES2015、JSX 和 Flow 语法后,如果编辑器不支持这些语法,开发体验会非常糟糕。为此,主流编辑器都有对应的 Babel 插件可供配置:
- Sublime Text
- Atom
- Vim
- WebStorm
获取支持:社区渠道与高质量 Bug 报告
Babel 拥有庞大且快速增长的社区。在所有社区渠道中,都执行着一份行为准则(Code of Conduct),违反准则会招致相应处理,因此与他人交流时请遵守并保持自律。同时,社区也在培养"自助互助"文化:如果看到自己会解答的问题,花几分钟帮一把,并尽量保持友善与理解。
官方支持渠道主要包括:
- Babel Forum:基于 Discourse 论坛软件托管的讨论社区,适合发帖提问;
- Babel Chat:Slack 频道,适合寻求即时帮助;
- Babel Issues:使用 GitHub Issue 跟踪器管理,可查看全部打开/关闭的 issue,也可以新建 bug 报告或功能请求。
如何撰写一份高质量的 Bug 报告
Babel 的问题有时很难远程调试,所以高质量的 bug 报告能显著加快问题解决速度。第一步永远是隔离问题:你的整套环境配置几乎不可能都是问题来源;如果问题出在某段输入代码上,就尽可能删减代码,直到得到一份"仍能复现问题的最小样本"。带着最小复现样本去提问,维护者才能快速定位并修复。
本手册在仓库中的位置
本指南的原始素材位于本仓库的 translations/vi/user-handbook.md,它是 Babel User Handbook 的越南语译本;英文原文(作为翻译基准的 master 版本)位于 translations/en/user-handbook.md。整个仓库围绕《Babel Handbook》组织,分为两大部分:本指南所属的User Handbook(如何安装、配置和使用 Babel),以及Plugin Handbook(如何为 Babel 编写插件,见 translations/vi/plugin-handbook.md)。多语言翻译通过 crowdin.yaml 配置的 Crowdin 项目协作完成,具体贡献流程见 CONTRIBUTING.md;仓库元信息(项目名babel-handbook、许可证cc-by-4.0等)可在 package.json 中查看。
回到本文的主题脉络:安装接入 → 配置 Preset → 处理编译产物运行 → 细粒度进阶控制 → 生态工具协同,这就是一份完整的 Babel 使用闭环。从babel-cli的第一条命令开始,到自定义 Preset 发布 npm 结束,你可以把这份指南当作项目接入 Babel 时的逐节对照手册;而当你想更进一步、亲手编写属于自己的 Babel 转换插件时,直接翻开仓库中的 Plugin Handbook 即可无缝衔接。
- 文档
- 教程
【免费下载链接】babel-handbook
:blue_book: A guided handbook on how to use Babel and how to create plugins for Babel.
相关推荐
Babel Handbook 安装和配置指南
Babel Handbook 安装和配置指南 1. 项目基础介绍和主要的编程语言 项目基础介绍 Babel Handbook 是一个指导手册,旨在帮助开发者了解
文档教程如何快速翻译英文PDF论文且保留原版式:PDFMathTranslate 完全指南
如何快速翻译英文PDF论文且保留原版式:PDFMathTranslate 完全指南 PDFMathTranslate 是一款开源的 AI PDF 翻译工具,能把
前端开发工具Babel Handbook终极指南:掌握JavaScript编译器生态系统与插件开发 🚀
Babel Handbook终极指南:掌握JavaScript编译器生态系统与插件开发 🚀 Babel Handbook 是每个现代JavaScript开发者
文档教程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考