【编者按】本文主要介绍通过 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 官方博客。
原文地址: https://blog.jscrambler.com/creating-modules-javascript-es7-babel/