ES6 In Depth: Using ES6 today with Babel and Broccoli
ES6已经存在了,还有些人已经开始谈论 ES7了。新的标准中有哪些特性会被保留,又有哪些闪亮的特性提供?作为一位网络开发人员,我们会对怎么使用它产生疑问。不仅一次,在之前的 深入ES6系列 中,我们一直在鼓励你们开始使用 ES6 来编码,通过用些有意思的工具来实现,我们之前已经有提到这方法:
If you’d like to use this new syntax on the Web, you can use Babel or Google’s Traceur to translate your ES6 code to web-friendly ES5.
今天,我们将一步步地向你展示它是怎么做的。之前提到的工具都称为是 transpilers(transcompiler暂译为 转换编译器) 。转换编译器是为人熟知的 资源到资源的编译器,这编译器在不同的编程语言之间进行抽象层面中的转换。转换编译器可以让我们编写ES6的代码,同时也保证代码能够在每个浏览器中运行。
转换编译器是我们的救赎
转换编译器十分易用,你可以按以下描述进行,只要两步:
我们用ES6语法编写代码
1
2
let q = 99 ;
let myVariable = ` $ { q } bottles of beer on the wall , $ { q } bottles of beer . ` ;
我们使用上面的代码作为转换编译器的输入,它会处理这代码,并产出下面的代码:
1
2
3
"use strict" ;
var q = 99 ;
var myVariable = "" + q + " bottles of beer on the wall, " + q + " bottles of beer."
我们知道这是旧JS的写法,它能运行于任意的浏览器。
转换编译器内部是怎么从输入到产生,这是是复杂的过程,也超出了这文章的范围。让我们就像开车,而不要去管其所有的内部机械引擎。今天,我们把转换编译器看作是一个黑盒子,来处理我们的代码。
Babel的作用
在项目中使用Bable有不几种不同的方法,首先是命令行工具,你可以通过下面的命令来实现:
1
babel script . js -- out - file script - compiled . js
在浏览器中预置Babel的版本也是可用的,你可以将Babel作为常规的js库文件,然后你可以将ES6的代码中的script标签中的类型修改为”text/babel”。
1
2
3
4
\ < script src = "node_modules/babel-core/browser.js" >< /script>
\ < script type = "text/babel" >
// Your ES6 code
< /script>
但是,这方法不能扩展:你的代码增长时,你会将代码分离成多个文件和目录,这方法是不允许的。这时,你需要一个构建工具,通过管道式来整合Babel。
在下面的部分,我们将Babel整合到一个构建工具中,Broccoli.js ,接着我们将通过几个例子来编写并执行我们的ES6代码。当你运行出现错误时,你可以在这里回头查看完整的资源代码:broccoli-babel-examples 。在这资源库中,你将找到三个例子项目:
es6-fruits
es6-website
es6-modules
每个会建立在之前的例子之上(没发现)。我们开始会代码最小化,并且会是个一般的解决方案,它可以胜任于为个伟大的项目打关阵。在这文章中,我们将详细地讨论前两个例子。在我们做完之后,你自己可以去阅读、去理解第三个例子中的代码。
如果你认为,你可以等待浏览器支持这些特性,你将会被甩到后面。完全的浏览器支持,如果这会实现,那它将是个漫长的过程。转换编译器已经在这里,新的ECMAScript标准也将计划在年内发布。所以 ,我们将继续、经常地看到新的标准发布出来,而这会先于统一的浏览器平台。跳起来吧,利用这些新的ES6特性吧。
我们的第一个Broccoli 和 Babel项目
Broccoli是个被设计为尽量快的速度来构建项目的工具。你可以压缩和最小化文件,通过这些插件 操作的使用,还有其它很多其它的功能。它帮助我们负担了一大堆的事情,包括处理文件、目录,还有当我们每次修改项目时需要执行的命令。可以把它当成为:
在一定范围上,它类似 Rails 的资源文件的管理,只是它运行于Node,也没有纯粹的后端。
开始项目
Node
正如你猜测一样,你将不得不安装 Node 0.11 或者更高版本。
如果你是在unix系统,避免使用包管理工具,如apt, yum。这样可以避免在安装过程中使用root权限。最好的方法是,从刚才提供的链接地址中,使用你当前的用户手动下载二进制文件。你可以在这里 看到为什么不建议使用 root 权限。你也可以在这里 选择其它的安装方式。
Broccoli
我们首先将建立我们的Broccoli的项目:
1
2
3
4
5
mkdir es6-fruits
cd es6-fruits
npm init
# Create an empty file called Brocfile.js
touch Brocfile.js
现在,我们安装 broccoli 和 broccoli-cli
1
2
3
4
# the broccoli library
npm install --save-dev broccoli
# command line tool
npm install -g broccoli-cli
编写些ES6代码
我们创建 src 目录,接着在里面编辑文件 fruits.js:
1
2
mkdir src
vim src/fruits.js
在我们的新文件中,我们使用 ES6 的语法编写些小的脚本:
1
2
3
4
5
6
7
8
9
10
11
12
let fruites = [
{ id : 100 , name : 'strawberry' },
{ id : 101 , name : 'grapefruit' },
{ id ; 102 , name : 'plum' }
];
for ( let fruit fo fruits ) {
let message = ` ID : $ { fruit . id } Name : $ { fruit . name } ` ;
console . log ( message );
}
console . lgo ( ` List total : $ { fruits . length } ` );
上面的代码使用到了 ES6 的三个特性:
let
,用于本作用域内的声明(在之前的文章中已经有讨论过)
for-of 循环
模板字符串
保存文件,并试着执行它。
它还不能运行,但我们希望它可以在Node和任意的浏览器中都能够执行。
1
2
3
let fruits = [
^^^^^
SyntaxError : Unexpected identifier
到转换代码的时间了
现在,我们将使用 Broccoli 来加载我们的代码,并通过Babel来处理。我们将编辑文件 Brocfile.js 并添加以下的代码:
1
2
3
4
5
6
7
// import the babel plugin
var babel = require ( 'broccoli-babel-transpiler' );
// grab the source and transpile it in 1 step
fruits = babel ( src ' ); // src/*.js
module . export = fruits ;
注意到,我们加载了 broccoli-babel-transpiler
,这是个 Broccoli 的插件,它包括了 Babel 的库,所以我们必须安装它:
1
npm install --save-dev broccolli-babel-transpiler
现在我们可以构建我们的项目,并通过下面代码来执行脚本:
1
2
broccoli build dist # compile
node dist/fruits.js # execute ES5
这个输出会看到:
1
2
3
4
ID: 100 Name: strawberry
ID: 101 Name: grapefruit
ID: 102 Name: plum
List total: 3
这十分的简单!你可以打开 dist/fruits.js
来看看,转换后的代码文件是什么样子。Babel转换编译器的其中一个好的特性就是可产生良好可读性的代码。
为网站编写ES6代码
在第二个例子中,我们将提升个等级。首先,退出 es6-fruits 目录,并参照之前的【项目开始】的步骤来创建一个新的目录 es6-website
。
在 src 的目录中,我们创建三个文件:
src/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<!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 : 1 rem ;
color : #fff ;
}
</style>
<body>
<h1> ES6 Today</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
1
2
3
4
5
6
7
function printInfo () {
$ ( '#info' )
. append ( '<p>minimal website example with' +
'Broccoli and Babel</p>' );
}
$ ( printInfo );
src/print-colors.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ES6 Generator
function * hexRange ( start , stop , step ) {
for ( var i = start ; i < stop ; i += step ) {
yield i ;
}
}
function printColors () {
var content$ = $ ( '#content' );
// contrived example
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 的生成器。这一个特性并没有在所有的浏览器得到支持。为了能够使用它(生成器),我们需要个工具。Babel 可以提供,我们也很快地使用到它。
下一步是合并所有的JS文件,并在网站中使用它。这最难的部分是编写我们的Brocfile 文件。这时,我们安装四个插件:
1
2
3
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
然后,使用它们 :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Babel transpiler
var babel = require ( 'broccoli-babel-transpiler' );
// filter trees (subsets of files)
var funnel = require ( 'broccoli-funnel' );
// concatenate trees
var concat = require ( 'broccoli-concat' );
// merge trees
var mergeTrees = require ( 'broccoli-merge-trees' );
// Transpile the source files
var appJs = babel ( 'src' );
// Grab the polyfill file provided by the Babel library
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' ]
});
// Add the Babel polyfill to the tree of transpiled files
appJs = mergeTrees ([ browserPolyfill , appJs ]);
// Concatenate all the JS files into a single file
appJs = concat ( appJs , {
// we specify a concatenation order
inputFiles : [ 'browser-polyfill.js' , '**/*.js' ],
outputFile : '/js/my-app.js'
});
// Grab the index file
var index = funnel ( 'src' , { files : [ 'index.html' ]});
// Grab all our trees and
// export them as a single and final tree
module . exports = mergeTrees ([ index , appJs ]);
是时候构建并执行我们的代码了:
这里,你应该在dist目录中看到如下的结构:
1
2
3
4
5
$> tree dist/
dist/
| --index.html
| --js
| --| -- my-app.js
这是个静态的网站,你可以部署到任意的服务器中,检查这代码是可行的。例如,
1
2
3
cd dist/
python -m SimpleHTTPServer
# visit http://localhost:8000/
你可以看到:
更多乐趣在 Babel 和 Broccoli 中
上面的第二个例子提供我们一方法来怎么使用Babel,从而完成项目。它应该可以让你理解一些时间了,如果你通过Babel、Broccoli更多地使用ES6,你可以查看一下这个项目:broccoli-babel-boilerplate 。它也是用 Broccoli + Babel 开始的,它至少提高了两个点。这模板例子包括了 模块、引入、和单元测试。
你可以试试这里的配置例子:es6-modules ,Brocfile 有很多魔法的地方,其类似与我们上面做的事件。