這篇小教程裏演示使用 TypeScript 構建命令行工具,利用 async/await 進行非阻塞操做,利用 mocha 自動化測試以及 travis-ci 進行持續集成。html
最近 TJ 發佈了 node-prune 進行對 node_modules
裏冗餘文件的清理,但項目由 Go 寫成,因而我移植了一個 JavaScript 版本。能夠搭配源碼配合繼續閱讀文章。項目由 TypeScript 構建,npm 發佈時自動轉譯成 JavaScript,所以能夠隨意使用 async/await 等等最新語法和類型檢測。同時利用 ts-node直接在 TypeScript 環境下進行調試。項目代碼量不多,適合做爲相似小工具的模版~node
項目最終的結構以下,源碼放在 src/
目錄下,最終轉碼到 lib/
目錄發佈到 npm,test/
目錄下是測試代碼。git
.
├── src/
├── test/
├── lib/
├── node_modules/
├── LICENSE
├── README.md
├── package-lock.json
├── package.json
└── tsconfig.json複製代碼
首先使用 npm init
進行項目的初始化並安裝 TypeScriptgithub
npm i typescript -D複製代碼
輸入完畢後打開 package.json
添加:typescript
{
"scripts": {
"build": "tsc",
"dev": "tsc -w",
"prepare": "npm run build",
}
},複製代碼
tsc
是 TypeScript 轉譯的命令,-w
參數能夠觀察源碼的變化持續轉譯,prepare
指令會在 npm install
和 npm publish
以前執行,用來保證發佈時是最新轉譯的代碼。npm
爲了告訴 tsc
如何進行轉譯,須要一個配置文件 tsconfig.json,在命令行 tsc --init
能夠生成一個默認的模版。若是要支持 Node6.x, 7.x,修改 "target": "ES2015"
,對於 Node 項目。模塊生成須要 "module": "commonjs"
,以後指定如下包含的 ts 文件便可。json
{
"compilerOptions": {
"target": "ES2015",
"module": "commonjs",
"outDir": "./lib",
"strict": true
},
"exclude": [
"node_modules",
"lib"
],
"include":[
"src/**/*.ts"
]
}複製代碼
如今咱們就能夠愉快地寫 TS 代碼啦,試驗一下寫一個 walk 全部文件和文件夾的函數,bash
import * as fs from 'fs-extra';
import * as path from 'path';
export async function walk(dir: string, prunerF: (p: string, s: fs.Stats) => void): Promise<void> {
let s = await fs.lstat(dir);
if (!s.isDirectory()) return;
const items = await fs.readdir(dir);
for (let item of items) {
const itemPath = path.join(dir, item);
const s = await fs.lstat(itemPath);
const pruned = await prunerF(itemPath, s);
if (!pruned && s.isDirectory()) {
await walk(itemPath, prunerF);
}
}
}複製代碼
注意這裏咱們能夠直接使用 async/await,並對傳入參數進行類型標記,若是你使用有插件支持的編輯器,這時能夠感覺到智能補全帶來的愉快體驗了。app
npm build
一下能夠在 lib/
裏面看到轉譯出來的 ES2015 代碼,稍微看一眼,能夠發現 async 是經過定義了一個 __awaiter
函數來進行的,感興趣的同窗能夠自行研究。異步
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};複製代碼
經過 node file.js
能夠運行一個腳本,但要怎樣安裝一個 npm 的可執行文件呢,根據 npmjs.com 的描述,在 package.json
中添加
{
"bin": {
"prune": "lib/cli.js"
}
}複製代碼
以後就能夠安裝一個 prune
到系統路徑中,而執行的文件頂部須要添加 #!/usr/bin/env node
,不然不會被識別爲 Node 腳本。
爲了讀取命令行傳入的參數,可使用 args,在 src/cli.ts
中這段代碼
const argv = yargs
.usage('Prune node_modules files and dependencies\n\nUsage: node-prune <path>')
.option('config', {
alias: 'c',
description: '<filename> config file name',
default: '.prune.json',
type: 'string'
})
.option('dryrun', {
alias: 'd',
description: 'dry run',
default: 'false',
type: 'boolean'
})
.option('verbose', {
description: 'log pruned file info',
default: 'false',
type: 'boolean'
})
.help('help').alias('help', 'h')
.version('version', '0.1.0').alias('version', 'v')
.argv;
const path = argv._[0] || 'node_modules';
const configs = {
config: argv.config,
dryrun: argv.dryrun,
verbose: argv.verbose
};複製代碼
能夠生成這樣的結果:
$ prune -h
Prune node_modules files and dependencies
Usage: node-prune <path>
Options:
--config, -c <filename> config file name [string] [default: ".prune.json"]
--dryrun, -d dry run [boolean] [default: "false"]
--verbose log pruned file info [boolean] [default: "false"]
--help, -h Show help [boolean]
--version, -v Show version number [boolean]複製代碼
獲取參數後就能夠 import 你寫的業務代碼進行操做,這裏略去,能夠在 Github 看一下例子。
以後咱們能夠經過 npm publis
發佈後 npm install -g pruner-cli
下載安裝工具以後執行 prune
直接調用。
測試代碼一樣須要使用 TypeScript 以及 async/await。選用 mocha 進行 BDD 風格的測試。chai 是一個 assertions 庫,搭配使用效果佳。
$ npm install mocha ts-node -g
$ npm install mocha chai ts-node --save-dev複製代碼
正常使用 mocha 會在 test/
目錄下執行 JavaScript,爲了跳過轉譯直接測試 TS 代碼,咱們能夠綁定 ts-node
直接執行測試代碼,在 package.json
中加入:
{
"scripts": {
"test": "mocha -r ts-node/register test/**/*.spec.ts"
},
}複製代碼
因而 test/
下全部的 *.spec.ts
都會被測試,而且可使用 await 異步,expect 實現 BDD。一個例子。
在項目下添加 .travis.yml
後添加項目語言的配置
language: node_js
node_js:
- "6"
- "7"
- "8"
- "9"複製代碼
而後在 travis-ci.org/ 添加本身開源的項目就能夠在每次 push 時自動測試編譯和 test。
點擊 build|passing
後將圖片的連接貼到項目的 README 中就能夠在 Github 上顯示 CI 的狀態了!