写点什么

深入浅出 ES6(九):学习 Babel 和 Broccoli,马上就用 ES6

2015 年 9 月 07 日

编者按:ECMAScript 6 已经正式发布了,作为它最重要的方言,Javascript 也即将迎来语法上的重大变革,InfoQ 特开设“深入浅出ES6 ”专栏,来看一下ES6 将给我们带来哪些新内容。本专栏文章来自 Mozilla Web 开发者博客,由作者授权翻译并发布。

自 ES6 正式发布,人们已经开始讨论 ES7:未来版本会保留哪些特性,新标准可能提供什么样的新特性。作为 Web 开发者,我们想知道如何发挥这一切的巨大能量。在深入浅出 ES6 系列之前的文章中,我们不断鼓励你开始在编码中加入 ES6 新特性,辅以一些有趣的工具,你完全可以从现在开始使用 ES6:

如果你想在 Web 端使用这种新语法,你可以通过 Babel 或 Google 的 Traceur 将你的 ES6 代码转译为 Web 友好的 ES5 代码。

现在,我们将向你分步展示如何做到的这一切。上面提及的工具被称为 _ 转译器 _,你可以将它理解为源代码到源代码的编译器——一个在可比较的抽象层上操作不同编程语言相互转换的编译器。转译器允许我们用 ES6 编写代码,同时保证这些代码能在每一个浏览器中执行。

转译技术拯救了我们

转译器使用起来非常简单,只需两步即可描述它所做的事情:

  1. 用 ES6 的语法编写代码。
复制代码
let q = 99;
let myVariable = `${q} bottles of beer on the wall, ${q} bottles of beer.`;
  1. 用上面那段代码作为转译器的输入,经过处理后得到以下这段输出:
复制代码
"use strict";
var q = 99;
var myVariable = "" + q + " bottles of beer on the wall, " + q + " bottles of beer."

这正是我们熟知的老式 JavaScript,这段代码可以在任意浏览器中运行。

转译器内部从输入到输出的逻辑高度复杂,完全超出本篇文章的讲解范围。正如我们无须知道所有的内部引擎结构就可以驾驶一辆汽车,现在,我们同样可以将转译器视为一个能够处理我们代码的黑盒。

实际体验 Babel

你可以通过几种不同的方法在项目中使用 Babel,有一个命令行工具,在这个工具中可以使用如下形式的指令:

babel script.js --out-file script-compiled.jsBabel 也提供支持在浏览器中使用的版本。你可以将 Babel 作为一个普通的库引入,然后将你的 ES6 代码放置在类型为text/babel的 script 标签中。

复制代码
<script src="node_modules/babel-core/browser.js"></script>
<script type="text/babel">
// 你的 ES6 代码
</script>
复制代码
随着代码库爆炸式增长,你开始将所有代码划分为多个文件和文件夹,但是这些方法并不能随之扩展。到那时,你将需要一个构建工具以及一种将 Babel 与构建管道整合在一起的方法。

在接下来的章节中,我们将要把 Babel 整合到构建工具 Broccoli.js 中,我们将在两个示例中编写并执行第一行 ES6 代码。如果你的代码无法正常运行,可以在这里( broccoli-babel-examples )查看完整的源代码。在这个仓库中你可以找到三个示例项目:

  1. es6-fruits
  2. es6-website
  3. es6-modules

每一个项目都构建于前一个示例的基础之上,我们会从最小的项目开始,逐步得出一个一般的解决方案,为日后每一个雄心壮志的项目打下良好的开端。这篇文章只包含前两个示例,阅读文章后,你完全可以自行阅读第三个示例中的代码并加以理解。

如果你在想——我坐等浏览器支持这些新特性就好了啦——那么你一定会落后的!实现所有功能要花费很长时间,况且现在有成熟的转译器,而且 ECMAScript 加快了发布新版本的周期(每年一版),我们将会看到新标准比统一的浏览器平台更新得更频繁。所以赶快加入我们,一起发挥新特性的巨大威力吧!

我们的首个 Broccoli 与 Babel 项目

Broccoli 是一个用来快速构建项目的工具,你可以用它对文件进行混淆与压缩,还可以通过众多的 Broccoli 插件实现许多其它功能。它帮助我们处理文件和目录,每当项目变更时自动执行指令,很大程度上减轻了我们的负担。你不妨将它视为:

类似 Rails 的 asset 管道,但是 Broccoli 运行在 Node 上且可以对接任意后端。

配置项目

NODE

你可能已经猜到了,你需要安装Node 0.11 或更高版本

如果你使用unix 系统,不要从包管理器(apt、yum 等)中安装,这样可以避免在安装过程中使用root 权限,最好使用当前的用户权限,通过上面的链接手动安装。在文章《不要sudo npm 》中可以了解为什么不推荐使用root 权限,文章中也给出了其它安装方案

BROCCOLI

首先,我们要配置好 Broccoli 项目:

复制代码
mkdir es6-fruits
cd es6-fruits
npm init
# 创建一个名为 Brocfile.js 的空文件
touch Brocfile.js

现在我们安装broccolibroccoli-cli

复制代码
# 安装 broccoli 库
npm install --save-dev broccoli
# 命令行工具
npm install -g broccoli-cli

编写一些 ES6 代码

创建 src 文件夹,在里面置入fruits.js文件。

复制代码
mkdir src
vim src/fruits.js

用 ES6 语法在新文件中写一小段脚本。

复制代码
let fruits = [
{id: 100, name: '草莓'},
{id: 101, name: '柚子'},
{id: 102, name: '李子'}
];
for (let fruit of fruits) {
let message = `ID: ${fruit.id} Name: ${fruit.name}`;
console.log(message);
}
console.log(`List total: ${fruits.length}`);

上面的代码示例使用了三个 ES6 特性:

  1. let进行局部作用域声明(在稍后的文章中讨论)
  2. for-of 循环
  3. 模板字符串

保存文件,尝试执行脚本。

node src/fruits.js目前这段代码不能正常运行,但是我们将会让它运行在 Node 与任何浏览器中。

复制代码
let fruits = [
^^^^^^
SyntaxError: Unexpected identifier

转译时刻

现在,我们用 Broccoli 加载代码,然后用 Babel 处理它。编辑Brocfile.js文件并加入以下这段代码:

复制代码
// 引入 babel 插件
var babel = require('broccoli-babel-transpiler');
// 获取源代码,执行转译指令(仅需 1 步)
fruits = babel('src'); // src/*.js
module.exports = fruits;

注意我们引入了包裹在 Babel 库中的 Broccoli 插件broccoli-babel-transpiler,所以我们一定要安装它:

复制代码
npm install --save-dev broccoli-babel-transpiler

现在我们可以构建项目并执行脚本了:

复制代码
broccoli build dist # 编译
node dist/fruits.js # 执行 ES5

输出结果看起来应当是这样的:

复制代码
ID: 100 Name: 草莓
ID: 101 Name: 柚子
ID: 102 Name: 李子
List total: 3

那很简单!你可以打开dist/fruits.js查看转译后代码。Babel 转译器的一个优秀特性是它能够生产可读的代码。

为网站编写 ES6 代码

在第二个示例中,我们将做进一步提升。首先,退出es6-fruits文件夹,然后使用上述配置项目一章中列出的步骤创建新目录es6-website

在 src 文件夹中创建三个文件:

src/index.html

复制代码
<html>
<head>
<title> 马上使用 ES6</title>
</head>
<style>
body {
border: 2px solid #9a9a9a;
border-radius: 10px;
padding: 6px;
font-family: monospace;
text-align: center;
}
.color {
padding: 1rem;
color: #fff;
}
</style>
<body>
<h1> 马上使用 ES6</h1>
<div id="info"></div>
<hr>
<div id="content"></div>
<script src="//code.jquery.com/jquery-2.1.4.min.js"></script>
<script src="js/my-app.js"></script>
</body>
</html>

src/print-info.js

复制代码
function printInfo() {
$('#info')
.append('<p> 用 Broccoli 和 Babel 构建的' +
'最小网站示例 </p>');
}
$(printInfo);

src/print-colors.js

复制代码
// ES6 生成器
function* hexRange(start, stop, step) {
for (var i = start; i < stop; i += step) {
yield i;
}
}
function printColors() {
var content$ = $('#content');
// 人为的示例
for ( var hex of hexRange(900, 999, 10) ) {
var newDiv = $('<div>')
.attr('class', 'color')
.css({ 'background-color': `#${hex}` })
.append(`hex code: #${hex}`);
content$.append(newDiv);
}
}
$(printColors);

你可能已经注意到function* hexRange,是的,那是 ES6 的生成器。这个特性目前尚未被所有浏览器支持。为了能够使用这个特性,我们需要一个 polyfill,Babel 中已经支持,我们很快将投入使用。

下一步是合并所有 JS 文件然后在网站中使用。最难的部分是编写 Brocfile 文件,这一次我们要安装 4 个插件:

复制代码
npm install --save-dev broccoli-babel-transpiler
npm install --save-dev broccoli-funnel
npm install --save-dev broccoli-concat
npm install --save-dev broccoli-merge-trees

把它们投入使用:

复制代码
// Babel 转译器
var babel = require('broccoli-babel-transpiler');
// 过滤树(文件的子集)
var funnel = require('broccoli-funnel');
// 连结树
var concat = require('broccoli-concat');
// 合并树
var mergeTrees = require('broccoli-merge-trees');
// 转译源文件
var appJs = babel('src');
// 获取 Babel 库提供的 polyfill 文件
var babelPath = require.resolve('broccoli-babel-transpiler');
babelPath = babelPath.replace(/\/index.js$/, '');
babelPath += '/node_modules/babel-core';
var browserPolyfill = funnel(babelPath, {
files: ['browser-polyfill.js']
});
// 给转译后的文件树添加 Babel polyfill
appJs = mergeTrees([browserPolyfill, appJs]);
// 将所有 JS 文件连结为一个单独文件
appJs = concat(appJs, {
// 我们指定一个连结顺序
inputFiles: ['browser-polyfill.js', '**/*.js'],
outputFile: '/js/my-app.js'
});
// 获取入口文件
var index = funnel('src', {files: ['index.html']});
// 获取所有的树
// 并导出最终单一的树
module.exports = mergeTrees([index, appJs]);

现在开始构建并执行我们的代码。

broccoli build dist这次你在 dist 文件夹中应该看到以下结构:

复制代码
$> tree dist/
dist/
├── index.html
└── js
└── my-app.js

那是一个静态网站,你可以用任意服务器伺服来验证那段代码正常运行。举个例子:

复制代码
cd dist/
python -m SimpleHTTPServer
# 访问 http://localhost:8000/

你应该可以看到:

Babel 和 Broccoli 组合还有更多乐趣

上述第二个示例给出了一个通过 Babel 实现功能的思路,它可能足够你用上一阵子了。如果你想要更多有关 ES6、Babel 和 Broccoli 的内容,可以查看 broccoli-babel-boilerplate ,这个仓库中的代码可以提供 Broccoli+Babel 项目的配置,而且高出至少两个层次。这个样板可以文件处理模块、模块导入以及单元测试。

通过这些配置,你可以在示例 es6-modules 中亲自实践。Brocfile 魔力无穷,与我们之前实现的非常类似。


正如你看到的,Babel 和 Broccoli 对于在 Web 网站中应用 ES6 新特性非常实用。感谢 Gastón I. Silva 贡献这篇文章!

下一篇,深入浅出 ES6 将为你带来一些 ES6 中威力更大的特性,届时请加入我们一起探索新世界。

2015 年 9 月 07 日 02:1611142
用户头像

发布了 63 篇内容, 共 124.7 次阅读, 收获喜欢 34 次。

关注

评论

发布
暂无评论
发现更多内容

可伸缩系统架构简介

Rayjun

分布式 可伸缩

硬件产品管理(2):产品QA检测

老壳有点爽

硬件产品 智能硬件 QA 产品管理

《我在一线做用户增长》读书笔记及感想

王新涵

用户增长

键盘敲入 A 字母时,期间发生了什么....

小林coding

操作系统 计算机基础 键盘

ARTS Week13

时之虫

ARTS 打卡计划

程序员什么时候该考虑辞职

看山

随笔杂谈 辞职

(2.6w字)网络知识点灵魂拷问——前端面试必问

执鸢者

面试 前端 网络 HTTP

ARTS打卡 第13周

引花眠

微服务 ARTS 打卡计划

架构师训练营 - 第 8 周学习总结

红了哟

商业计划书制作(5):业务发展的历史与未来

老壳有点爽

创业 财富自由 商业计划书 业务发展的历史与未来

如何做好项目时间管理?

石云升

项目管理 需求 项目排期

什么是产品以及如何将一个开源软件项目产品化

常平

架构模式 架构设计 架构师 产品思维

商业计划书制作(7):编写规范及常见内容

老壳有点爽

创业 财富自由 商业计划书

硬件产品管理(5):硬件产品工作流程管理及案例分析

老壳有点爽

创业 硬件产品 智能硬件 产品管理

Java中的一些限制

xiaoxi666

disruptor 高性能队列最佳选择

柿子

队列 disruptoer 高性能队列

硬件产品管理(4):人体工程学验证

老壳有点爽

硬件产品 智能硬件 产品管理 人体工程学

高并发系统三大利器之限流

java金融

架构 高并发 分布式限流 限流 单机限流

设计模式:建造者模式

看山

设计模式 建造者模式

商业计划书制作(6):商业模式

老壳有点爽

创业 商业模式 财富自由 商业计划书

Java ForEach语句判断是否为空

引花眠

bug

商业计划书制作(8):财务分析部分

老壳有点爽

创业 财富自由 商业计划书 财务分析

硬件产品管理(1):手板管理流程

老壳有点爽

创业 硬件产品 智能硬件 手板

面试的时候不能做捧哏

escray

学习 面试 面试现场

高并发系统三大利器之缓存

java金融

Java 缓存 高并发 本地缓存 分布式缓存

Java中的单例模式(完整篇)

看山

Java 设计模式 单例模式

编程的乐趣与苦恼

看山

随笔杂谈 人月神话

硬件产品管理(3):产品问题整理-举例

老壳有点爽

创业 硬件产品 智能硬件

ARTS-WEEK11

一周思进

ARTS 打卡计划

【Elasticsearch 技术分享】—— ES 常用名词及结构

程序员小航

Java 搜索引擎 elastic ES Lucene Elastic Search

顺时针遍历矩阵,提高系统高并发350倍,React Native原理浅析 组件设计原则 安全架构 防火墙ModSecurity John 易筋 ARTS 打卡 Week 14

John(易筋)

ARTS 打卡计划 组件设计原则 React Native 高并发优化

InfoQ 极客传媒开发者生态共创计划线上发布会

InfoQ 极客传媒开发者生态共创计划线上发布会

深入浅出ES6(九):学习Babel和Broccoli,马上就用ES6-InfoQ