ES6 才剛被標準化,人們就在開始談論 ES7 將提供哪些閃亮的新特性了。作為 Web 開發人員,我們更想知道如何使用這些新特性。在之前的文章中,作者鼓勵我們在一些工具的幫助下開始使用 ES6:
如果你想使用這些新語法,你可以使用 Babel 或 Google 的 Traceur 將 ES6 程式碼轉換為友好的 ES5 程式碼。
本文的主題就是這些工具的使用,上面這些工具被統稱為 transpiler,transpiler 也被稱為原始碼到原始碼的編譯器,用於在抽象級別進行程式語言之間的相互轉換。使用 transpiler 可以讓我們用 ES6 語法來編寫程式碼,同時保證這些程式碼能在所有瀏覽器上執行。
Transpiler
使用 transpiler 非常簡單,只需要下面兩步:
1.用 ES6 語法編寫程式碼:
1 2 |
let q = 99; let myVariable = `${q} bottles of beer on the wall, ${q} bottles of beer.`; |
2.將上面程式碼作為 transpiler 的輸入,經 transpiler 處理後將得到下面的程式碼:
1 2 3 4 |
"use strict"; var q = 99; var myVariable = "" + q + " bottles of beer on the wall, " + q + " bottles of beer." |
得到的程式碼是老式的 JavaScript 語法,可以在任何瀏覽器中執行。
transpiler 的內部工作原理相當複雜,超出了本文的討論範圍。這裡我們僅僅將 transpiler 作為一個黑盒來處理我們的程式碼,正如你會開車,但並不需要知道發動機的工作原理一樣。
Babel 實踐
使用 Babel 有幾種不同的方式。Babel 提供了一個命令列工具,你可以在終端中使用:
1 |
babel script.js --out-file script-compiled.js |
還有一個瀏覽器端庫。首先,將 Babel 嵌入到頁面中,然後將你的 ES6 程式碼放在 type
屬性值為 text/babel
的 script
標籤中:
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 程式碼的編寫和執行。示例的完整程式碼放在這裡,一共包含三個示例:
- es6-fruits
- es6-website
- es6-modules
每個例子都是建立在前個例子的基礎上,我們可以先從最簡單的例子入手,然後進階到一個通用的解決方案,最終可以作為一個龐大專案的起點。本文將詳細討論前面兩個例子,之後你將能自行閱讀和理解第三個例子中的程式碼。
如果你還在猶豫,那就等到瀏覽器相容這些新特性吧,這樣你也會被甩在時代的後面。瀏覽器完全相容這些新特性需要很長的時間,而且每年都將釋出一些新的 ECMAScript 標準,我們將看到新標準將比瀏覽器廠商的釋出更加頻繁。所以,別猶豫了,讓我們開始使用這些新特性吧。
小試牛刀
Broccoli 是一個快速構建工具,不僅可以用來混淆和壓縮檔案,藉助 Broccoli 外掛還可以做很多構建相關的工作,為我們節省了在處理檔案、目錄和執行命令上的時間。
準備工作
首先,我們需要安裝 Node 0.11 或更新的版本。
如果你使用的是 unix 系統,那麼請避免使用 package manager (apt, yum) 來安裝,這可以避免在安裝過程中使用 root 許可權。最好只為當前使用者使用連結中提供的二進位制檔案安裝。在 這篇文章中介紹了為什麼不推薦使用 root 許可權,同時文章中還提供了一些其他安裝方式。
專案初始化
使用下面命令初始化我們的專案:
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 13 |
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}`); |
上面程式碼中使用了 ES6 的三個新特性:
- 用
let
宣告區域性變數 - for-of 迴圈
- template strings
儲存檔案,然後嘗試執行一下:
1 |
node src/fruits.js |
我們看到執行報錯了,但我們的目標是使這段程式碼可以在 Node 和任何瀏覽器上都能被執行:
1 2 3 |
let fruits = [ ^^^^^^ SyntaxError: Unexpected identifier |
Transpilation
接下來我們將使用 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.exports = fruits; |
broccoli-babel-transpiler
這個包是 Broccoli 的一個外掛,使用前需要安裝:
1 |
npm install --save-dev broccoli-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 生成的程式碼可讀性是非常強的。
在 Web 開發中的使用
接下來我們來看一個稍複雜的例子。首先,退出 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: 1rem; 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 generator,目前該特性還沒有被所有瀏覽器相容,為了使用這個特性,我們需要一個 polyfill,Babel 為我們提供了這個 polyfill。
下一步就是合併 JS 檔案,難點在於 Brocfile.js
檔案的編寫,這次我們需要安裝 4 個外掛:
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 |
Brocfile.js
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 |
// 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]); |
構建:
1 |
broccoli build dist |
構建結果,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/ |
你將看到如下結果: