使用Babel和ES7建立JavaScript模組

OneAPM官方技術部落格發表於2016-05-11

【編者按】本文主要介紹通過 ES7 與 Babel 建立 JavaScript 模組。文章系國內 ITOM 管理平臺 OneAPM 工程師編譯呈現,以下為正文。

去年,新版的JavaScript釋出了,它有很多新的優點。其中之一就是匯入匯出模組的語法被整理為JavaScript模組處理的“唯一方法”。好吧,終於等到了。另一樁好事兒是,它的編排方式使你可以靜態分析整棵模組依賴樹。真是相當厲害。

讓我們來掃一眼這些語法:

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";

所以,基本上你可以匯入一個模組(“default”)的主要值,或者匯入從顯式匯出(explicit exports)而來的一個特定屬性,或者這二者的組合,或者是任何東西。相對應的,你也可以為預設模組匯出一個值,或者帶有多個屬性的物件。你也可以逐個匯出這些屬性。最佳風格還是請參考風格指南吧;)

ES7中還加入了一些對這類語法的小補充。

export * as ns from "mod";
export v from "mod";

沒啥特別的,但我們什麼時候能使用它們呢?擇日不如撞日吧。就像對待很多ES6的語法特性,如果你目前不打算支援它們,可以用一種叫Babel的工具把它們轉譯回ES5。一旦你準備支援它們了,就可以讓Babel停止轉譯。

讓我們來看一眼具體如何操作。我們將在Node.js與NPM中實現它。試試看執行這個檔案;

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';

我們的設想是,index.js 主檔案用於內部模組內容的匯出,它假設這些鍵是從其它檔案中匯出的。這個例子有點費解,但是這並無大礙。

src/index.js

import * as keys from './move';
console.log(keys);

這可以作為依賴這個模組的某個專案的一部分。它應當列印awsd鍵以及箭頭物件。讓我們先從npm開始吧。建立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

這得花點時間。你可能已經猜到了,babel-cli支援從命令列執行Babel (6),並且,babel-preset-stage-1包提供了相關的ES7模組轉譯工具(在撰寫本文之時)。-yes標記會讓npm建立一個預設的package.json,而不會詢問使用者。-D標記是--save-dev的縮寫,它會在package.json中把包新增到devDependency條目下。現在,把預設引數新增入到預設的babel配置檔案中:

.babelrc

{
  "presets": ["es2015", "stage-1"]
}

如果這能順利執行,那就太好了,擁抱未來吧!但是,在筆者寫本文時,這些示例在ES6中都無法執行,更不用說Node.js了。經過這些轉譯步驟,不管怎樣,它們可以被執行了。

現在還應該有一個幾乎為空的package.json檔案,它包含了我們新增的那三個dev 依賴。讓我們給這個package.json 檔案加一段指令碼,來實現轉譯:

  ...
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1",
    "translate": "node_modules/babel-cli/bin/babel-node.js src/index.js"
  },
  ...

(僅在“test”那行之後新增“translate”行及逗號)。

這段轉譯指令碼是一個編譯步驟。在文章的結尾處,你可以找到本文(正式版本)使用的最終版package.json檔案。現在,只剩下呼叫npm指令來執行指令碼,以實現轉譯,並執行我們的程式碼了。

~/foo$ npm run translate --silent

{ A: [Getter],
  W: [Getter],
  S: [Getter],
  D: [Getter],
  ARROWS: { UP: 38, RIGHT: 39, DOWN: 40, LEFT: 37 } }

加油!現在,作為額外獎勵,我們可以使用Jscrambler來“混淆”一下程式碼。我們可以傳遞Babel轉譯後的程式碼,所以幹嘛不這麼做呢?

我們(最終的)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,則需要一個專業版賬號)。以下是筆者所用的檔案(想深入瞭解這個檔案是如何建立的,可以此為例,點此獲得更多關於NPM的文件):

.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%"
  }
}

我們用一段指令碼來彙總一下。這段指令碼將會用Babel翻譯原始檔,輸出到/build資料夾,接著用Jscrambler混淆程式碼,再將結果放入/dist資料夾。/dist裡的內容可以被正常執行,而不必用到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

使之準備就緒:

chmod +x run.sh

接著,執行:

~/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資料夾檢視結果。你會看到,結果和原檔案相去甚遠,這是因為我們通過Jscrambler來保護它,但是結果還是可以執行的。

教程到此結束,祝ES7用得開心!

OneAPM 助您輕鬆鎖定 Node.js 應用效能瓶頸,通過強大的 Trace 記錄逐層分析,直至鎖定行級問題程式碼。以使用者角度展示系統響應速度,以地域和瀏覽器維度統計使用者使用情況。想閱讀更多技術文章,請訪問 OneAPM 官方部落格

本文轉自 OneAPM 官方部落格

原文地址:https://blog.jscrambler.com/creating-modules-javascript-es7-babel/

相關文章