使用Babel和ES7創(chuàng)建JavaScript模塊
去年,新版的JavaScript發(fā)布了,它有很多新的優(yōu)點(diǎn)。其中之一就是導(dǎo)入導(dǎo)出模塊的語法被整理為JavaScript模塊處理的“唯一方法”。好吧,終于等到了。另一樁好事兒是,它的編排方式使你可以靜態(tài)分析整棵模塊依賴樹。真是相當(dāng)厲害。
讓我們來掃一眼這些語法:
- import v from "mod";
- import * as obj from "mod";
- import {x} from "mod";
- import {x as v} from "mod";
- import "mod";
- export var v;
- export default function f(){};
- export default function(){};
- export default 42;
- export {x};
- export {x as v};
- export {x} from "mod";
- export {x as v} from "mod";
- export * from "mod";
所以,基本上你可以導(dǎo)入一個(gè)模塊(“default”)的主要值,或者導(dǎo)入從顯式導(dǎo)出(explicit exports)而來的一個(gè)特定屬性,或者這二者的組合,或者是任何東西。相對應(yīng)的,你也可以為默認(rèn)模塊導(dǎo)出一個(gè)值,或者帶有多個(gè)屬性的對象。你也可以逐個(gè)導(dǎo)出這些屬性。***風(fēng)格還是請參考風(fēng)格指南吧;)
ES7中還加入了一些對這類語法的小補(bǔ)充。
- export * as ns from "mod";
- export v from "mod";
沒啥特別的,但我們什么時(shí)候能使用它們呢?擇日不如撞日吧。就像對待很多ES6的語法特性,如果你目前不打算支持它們,可以用一種叫Babel的工具把它們轉(zhuǎn)譯回ES5。一旦你準(zhǔn)備支持它們了,就可以讓Babel停止轉(zhuǎn)譯。
讓我們來看一眼具體如何操作。我們將在Node.js與NPM中實(shí)現(xiàn)它。試試看執(zhí)行這個(gè)文件;
src/letter_keys.js
- // you would have a constant for each key
- // (I would normally uppercase all constants)
- const a = 119;
- const d = 100;
- const s = 115;
- const w = 119;
- // you would export all keys here
- // note: you can't say `w: 119` here. It just isn't valid.
- // This destructures to `w: w, a: a, ...`
- export {
- w,
- a,
- d,
- s,
- }
src/arrow_keys.js
- const UP = 38;
- const RIGHT = 39;
- const DOWN = 40;
- const LEFT = 37;
- export {
- UP,
- RIGHT,
- DOWN,
- LEFT,
- }
src/move.js
- export {a, w, s, d} from './letter_keys';
- export * as ARROWS from './arrow_keys';
我們的設(shè)想是,index.js 主文件用于內(nèi)部模塊內(nèi)容的導(dǎo)出,它假設(shè)這些鍵是從其它文件中導(dǎo)出的。這個(gè)例子有點(diǎn)費(fèi)解,但是這并無大礙。
src/index.js
- import * as keys from './move';
- console.log(keys);
這可以作為依賴這個(gè)模塊的某個(gè)項(xiàng)目的一部分。它應(yīng)當(dāng)打印awsd鍵以及箭頭對象。讓我們先從npm開始吧。創(chuàng)建repo dir并初始化:
- ~$ mkdir foo
- ~$ cd foo
- ~/foo$ mkdir src
- # put src files above in ~/foo/src
- ~/foo$ npm init -yes
- ~/foo$ npm install babel-cli babel-preset-es2015 babel-preset-stage-1 -D
這得花點(diǎn)時(shí)間。你可能已經(jīng)猜到了, babel-cli 支持從命令行運(yùn)行Babel (6),并且, babel-preset-stage-1 包提供了相關(guān)的ES7模塊轉(zhuǎn)譯工具(在撰寫本文之時(shí))。 -yes 標(biāo)記會(huì)讓npm創(chuàng)建一個(gè)默認(rèn)的 package.json ,而不會(huì)詢問用戶。 -D 標(biāo)記是 --save-dev 的縮寫,它會(huì)在 package.json 中把包添加到 devDependency 條目下。現(xiàn)在,把預(yù)設(shè)參數(shù)添加入到默認(rèn)的babel配置文件中:
.babelrc
- {
- "presets": ["es2015", "stage-1"]
- }
如果這能順利運(yùn)行,那就太好了,擁抱未來吧!但是,在筆者寫本文時(shí),這些示例在ES6中都無法運(yùn)行,更不用說Node.js了。經(jīng)過這些轉(zhuǎn)譯步驟,不管怎樣,它們可以被執(zhí)行了。
現(xiàn)在還應(yīng)該有一個(gè)幾乎為空的package.json文件,它包含了我們添加的那三個(gè)dev 依賴。讓我們給這個(gè)package.json 文件加一段腳本,來實(shí)現(xiàn)轉(zhuǎn)譯:
- ...
- "scripts": {
- "test": "echo "Error: no test specified" && exit 1",
- "translate": "node_modules/babel-cli/bin/babel-node.js src/index.js"
- },
- ...
(僅在“test”那行之后添加“translate”行及逗號)。
這段轉(zhuǎn)譯腳本是一個(gè)編譯步驟。在文章的結(jié)尾處,你可以找到本文(正式版本)使用的最終版package.json文件?,F(xiàn)在,只剩下調(diào)用npm指令來運(yùn)行腳本,以實(shí)現(xiàn)轉(zhuǎn)譯,并運(yùn)行我們的代碼了。
- ~/foo$ npm run translate --silent
- { A: [Getter],
- W: [Getter],
- S: [Getter],
- D: [Getter],
- ARROWS: { UP: 38, RIGHT: 39, DOWN: 40, LEFT: 37 } }
加油!現(xiàn)在,作為額外獎(jiǎng)勵(lì),我們可以使用Jscrambler來“混淆”一下代碼。我們可以傳遞Babel轉(zhuǎn)譯后的代碼,所以干嘛不這么做呢?
我們(最終的)package.json文件是這樣的:
package.json
- {
- "name": "foo",
- "version": "1.0.0",
- "description": "",
- "main": "index.js",
- "scripts": {
- "test": "echo "Error: no test specified" && exit 1",
- "translate": "node_modules/babel-cli/bin/babel-node.js src/index.js"
- },
- "keywords": [],
- "author": "Your Name <some@mail.local> (http://localhost/)",
- "license": "ISC",
- "devDependencies": {
- "babel-cli": "6.6.5",
- "babel-preset-es2015": "6.6.0",
- "babel-preset-stage-1": "6.5.0",
- "jscrambler": "0.7.5"
- }
- }
像往常一樣完成配置(如果使用的是Node.js,則需要一個(gè)專業(yè)版賬號)。以下是筆者所用的文件
.jscramblerrc
- {
- "keys": {
- "accessKey": "See https://jscrambler.com/en/account/api_access",
- "secretKey": "See https://jscrambler.com/en/account/api_access"
- },
- "params": {
- "constant_folding": "%DEFAULT%",
- "dead_code": "%DEFAULT%",
- "dead_code_elimination": "%DEFAULT%",
- "dictionary_compression": "%DEFAULT%",
- "dot_notation_elimination": "%DEFAULT%",
- "function_outlining": "%DEFAULT%",
- "function-reorder": "%DEFAULT%",
- "literal_duplicates": "%DEFAULT%",
- "literal_hooking": "2;8",
- "member_enumeration": "%DEFAULT%",
- "mode": "nodejs",
- "rename_local": "%DEFAULT%",
- "string_splitting":"0.3",
- "whitespace": "%DEFAULT%"
- }
- }
我們用一段腳本來匯總一下。這段腳本將會(huì)用Babel翻譯源文件,輸出到/build文件夾,接著用Jscrambler混淆代碼,再將結(jié)果放入/dist文件夾。/dist里的內(nèi)容可以被正常運(yùn)行,而不必用到ES7的任何特性。
run.sh
- #!/bin/sh
- echo "Babelifying src/*.js"
- node_modules/babel-cli/bin/babel.js -d build src/*.js
- echo "Scrambling build/*.js"
- node_modules/jscrambler/bin/jscrambler -o dist build/src/**
- echo "Clean up artifacts"
- mv dist/build/src/* dist/
- rmdir dist/build/src
- rmdir dist/build
- echo "Done! See dist/scrambled.js"
- echo "Running:"
- node dist/index.js
使之準(zhǔn)備就緒:
- chmod +x run.sh
接著,運(yùn)行:
- ~/foo$ ./run.sh
- Babelifying src/*.js
- src/arrow_keys.js -> build/src/arrow_keys.js
- src/index.js -> build/src/index.js
- src/letter_keys.js -> build/src/letter_keys.js
- src/move.js -> build/src/move.js
- Scrambling build/*.js
- Clean up artifacts
- Done! See dist/ for your scrambled files
- Running:
- { a: [Getter],
- w: [Getter],
- s: [Getter],
- d: [Getter],
- ARROWS: { UP: 38, RIGHT: 39, DOWN: 40, LEFT: 37 } }
你可以去/dist文件夾查看結(jié)果。你會(huì)看到,結(jié)果和原文件相去甚遠(yuǎn),這是因?yàn)槲覀兺ㄟ^Jscrambler來保護(hù)它,但是結(jié)果還是可以運(yùn)行的。
教程到此結(jié)束,祝ES7用得開心!
OneAPM 助您輕松鎖定Node.js 應(yīng)用性能瓶頸,通過強(qiáng)大的Trace 記錄逐層分析,直至鎖定行級問題代碼。以用戶角度展示系統(tǒng)響應(yīng)速度,以地域和瀏覽器維度統(tǒng)計(jì)用戶使用情況。