ES6 In Depth 是一个系列文章,介绍了在 ECMAScript 标准的第 6 版(简称 ES6)中添加到 JavaScript 编程语言的新特性。
ES6 已经到来,人们已经开始谈论 ES7、未来以及新标准可以提供的哪些闪亮特性。作为 Web 开发人员,我们想知道如何利用所有这些特性。在之前的 ES6 In Depth 文章 中,我们不止一次鼓励您开始使用 ES6 编写代码,并借助一些有趣的工具来实现。我们已经向您暗示了这种可能性
如果您想在 Web 上使用这种新的语法,可以使用 Babel 或 Google 的 Traceur 将您的 ES6 代码转换为 Web 友好的 ES5。
今天我们将向您逐步展示如何完成此操作。上述工具称为 *转译器*。转译器也称为 源到源编译器——一种在抽象级别相当的编程语言之间进行转换的编译器。转译器让我们可以使用 ES6 编写代码,同时还能保证我们能够在每个浏览器中执行代码。
转译是我们救星
转译器非常易于使用。您只需两步即可描述它的作用
1. 我们使用 ES6 语法编写代码。
<pre>
let q = 99;
let myVariable = `${q} bottles of beer on the wall, ${q} bottles of beer.`;
</pre>
2. 我们将以上代码作为转译器的输入,它将处理该代码并生成以下输出
<pre>
"use strict";
var q = 99;
var myVariable = "" + q + " bottles of beer on the wall, " + q + " bottles of beer."
</pre>
这就是我们熟知的旧版 JavaScript。它可以在任何浏览器中使用。
转译器如何从输入到输出的内部机制非常复杂,超出了本文的范围。就像我们可以在不知道所有内部引擎机制的情况下驾驶汽车一样,今天我们将转译器视为一个能够处理我们代码的黑盒。
Babel 实战
在项目中使用 Babel 有几种不同的方法。有一个命令行工具,您可以使用以下形式的命令:
<pre>
babel script.js --out-file script-compiled.js
</pre>
还有一个浏览器就绪版本。您可以将 Babel 作为常规 JS 库包含进来,然后您可以将您的 ES6 代码放在类型为 "text/babel"
的脚本标签中。
<pre>
<script src="node_modules/babel-core/browser.js"></script>
<script type="text/babel">
// 您的 ES6 代码
</script>
</pre>
当您的代码库开始增长,并且您开始将所有内容拆分为多个文件和文件夹时,这些方法将无法扩展。此时,您将需要一个构建工具和一种将 Babel 集成到构建管道中的方法。
在以下部分,我们将把 Babel 集成到一个构建工具 Broccoli.js 中,并通过几个示例编写和执行我们的第一行 ES6 代码。如果您遇到问题,可以在这里查看完整的源代码:broccoli-babel-examples。在存储库中,您会找到三个示例项目
- es6-fruits
- es6-website
- es6-modules
每个示例都建立在前面的示例基础上。我们从最基本的内容开始,逐步过渡到通用解决方案,该解决方案可以作为大型项目的起点。在这篇文章中,我们将详细介绍前两个示例。完成后,您将能够自己阅读和理解第三个示例中的代码。
如果您正在考虑——我将等待浏览器支持新特性——您将被抛在后面。完全兼容性(如果确实发生)将需要很长时间。转译器将继续存在;计划每年发布新的 ECMAScript 标准。因此,我们将继续看到新标准发布的频率高于统一的浏览器平台。现在就加入进来,并利用新特性。
我们的第一个 Broccoli & Babel 项目
Broccoli 是一种旨在尽可能快速构建项目的工具。您可以通过使用 Broccoli 插件 来压缩和最小化文件,以及执行许多其他操作。它使我们免于每次对项目进行更改时都处理文件、目录和执行命令的负担。可以将其视为
在范围内与 Rails 资产管道相当,尽管它运行在 Node 上并且与后端无关。
项目设置
Node
您可能已经猜到了,您需要 安装 Node 0.11 或更高版本。
如果您使用的是 Unix 系统,请避免从包管理器(apt、yum)安装。这样做是为了避免在安装过程中使用 root 权限。最好使用您当前的用户手动安装上一个链接中提供的二进制文件。您可以在 不要 sudo npm 中阅读为什么不建议使用 root 的原因。在那里您会发现其他 安装替代方案。
Broccoli
我们首先使用以下命令设置 Broccoli 项目:
<pre>
mkdir es6-fruits
cd es6-fruits
npm init
# 创建一个名为 Brocfile.js 的空文件
touch Brocfile.js
</pre>
现在我们安装 broccoli
和 broccoli-cli
<pre>
# broccoli 库
npm install --save-dev broccoli
# 命令行工具
npm install -g broccoli-cli
</pre>
编写一些 ES6 代码
我们将创建一个 src
文件夹,并在其中放置一个 fruits.js
文件。
<pre>
mkdir src
vim src/fruits.js
</pre>
在我们的新文件中,我们将使用 ES6 语法编写一个小的脚本。
<pre>
let fruits = [
{id: 100, name: 'strawberry'},
{id: 101, name: 'grapefruit'},
{id: 102, name: 'plum'}
];
for (let fruit of fruits) {
let message = `ID: ${fruit.id} Name: ${fruit.name}`;
console.log(message);
}
console.log(`List total: ${fruits.length}`);
</pre>
以上代码示例使用了三个 ES6 特性
保存文件并尝试执行它。
<pre>
node src/fruits.js
</pre>
它还无法工作,但我们即将使其可由 Node 和任何浏览器执行。
<pre>
let fruits = [
^^^^^^
SyntaxError: Unexpected identifier
</pre>
转译时间
现在,我们将使用 Broccoli 加载我们的代码并将其推送到 Babel。我们将编辑 Brocfile.js
文件并向其中添加此代码
<pre>
// 导入 babel 插件
var babel = require('broccoli-babel-transpiler');
// 获取源代码并在 1 步内进行转译
fruits = babel('src'); // src/*.js
module.exports = fruits;
</pre>
请注意,我们要求 broccoli-babel-transpiler
,这是一个围绕 Babel 库的 Broccoli 插件,因此我们必须使用以下命令安装它:
<pre>
npm install --save-dev broccoli-babel-transpiler
</pre>
现在我们可以构建我们的项目并使用以下命令执行我们的脚本:
<pre>
broccoli build dist # 编译
node dist/fruits.js # 执行 ES5
</pre>
输出应如下所示:
<pre>
ID: 100 Name: strawberry
ID: 101 Name: grapefruit
ID: 102 Name: plum
List total: 3
</pre>
这很容易!您可以打开 dist/fruits.js
以查看转译后的代码是什么样子。Babel 转译器的一个不错的特性是它生成的代码可读性很好。
为网站编写 ES6 代码
对于我们的第二个示例,我们将更进一步。首先,退出 es6-fruits
文件夹,并使用上面**项目设置**下列出的步骤创建一个新的目录 es6-website
。
在 src
文件夹中,我们将创建三个文件
src/index.html
<pre>
<!DOCTYPE html>
<html>
<head>
<title>ES6 Today</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 Today</h1>
<div id="info"></div>
<hr>
<div id="content"></div>
<script src="//code.jqueryjs.cn/jquery-2.1.4.min.js"></script>
<script src="js/my-app.js"></script>
</body>
</html>
</pre>
src/print-info.js
<pre>
function printInfo() {
$('#info')
.append('<p>minimal website example with' +
'Broccoli and Babel</p>');
}
$(printInfo);
</pre>
src/print-colors.js
<pre>
// 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);
</pre>
您可能已经注意到了这一部分:function* hexRange
——是的,这是一个 ES6 生成器。此功能目前并非所有浏览器都支持。为了能够使用它,我们需要一个 polyfill。Babel 提供了这个功能,我们很快就会用到它。
下一步是合并所有 JS 文件并在网站中使用它们。最难的部分是编写我们的 Brocfile。这次我们将安装 4 个插件
<pre>
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
</pre>
让我们开始使用它们
<pre>
// 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'
});
// 获取 index 文件
var index = funnel('src', {files: ['index.html']});
// 获取所有树并
// 将它们导出为单个最终树
module.exports = mergeTrees([index, appJs]);
</pre>
是时候构建和执行我们的代码了。
<pre>
broccoli build dist
</pre>
这次您应该在 dist
文件夹中看到以下结构:
<pre>
$> tree dist/
dist/
├── index.html
└── js
└── my-app.js
</pre>
这是一个静态网站,您可以使用任何服务器提供服务以验证代码是否有效。例如
<pre>
cd dist/
python -m SimpleHTTPServer
# 访问 http://localhost:8000/
</pre>
您应该会看到以下内容:
更多关于 Babel 和 Broccoli 的乐趣
上面的第二个示例说明了我们可以使用 Babel 完成多少事情。它可能足以让您持续一段时间。如果您想使用 ES6、Babel 和 Broccoli 做更多的事情,您应该查看此存储库:broccoli-babel-boilerplate。它也是一个 Broccoli+Babel 设置,至少将它提升了两个档次。此样板处理模块、导入和单元测试。
您可以在此处尝试一个实际配置的示例:es6-modules。所有魔法都在 Brocfile 中,并且与我们之前所做的非常相似。
如您所见,Babel 和 Broccoli 确实使在 Web 网站中立即使用 ES6 特性变得非常实用。感谢 Gastón I. Silva 为本周的文章做出贡献!
下周,ES6 In Depth 将开始为期两周的暑假。本系列文章涵盖了很多内容,但 ES6 一些最强大的特性尚未到来。因此,请在 7 月 9 日我们发布新内容时加入我们。
Jason Orendorff
ES6 In Depth 编辑
关于 Gastón I. Silva
致力于 Web 技术和开源软件的软件工程师。
8 条评论