※ 書きかけです
パッケージ依存管理ツール npm
npm は、今や Web 開発には欠かすことのできないパッケージ依存管理ツールです。
Browserify, Babel, Gulp, LESS のようなツール、Koa, Express のようなサーバー側のライブラリ、 React, AngularJS のようなクライアント側のライブラリまで揃っています。
サーバー側はもちろん、クライアント側の依存管理も Browserify を併用することでスマートに実現できます。
そんな npm ですが、実はタスク ランナーの機能も持ち合わせています。
Grunt や Gulp の影に隠れて目立たない存在でしたが、Substack の記事からこっち、注目を集め始めています (たぶん)。
タスク ランナー npm
タスク ランナーといえば、Web 界隈では Grunt や Gulp が有名です。
これらは環境構築・ビルド・デプロイ等、目的に応じた定形処理(タスク)を登録しておき、コマンドひとつで実行できるようにしておくツールです。
それに加えて、ツールたちはタスクを定義しやすくする様々な工夫を競っています。
さて、タスク ランナーとしての npm はとてもシンプルです。
package.json
(パッケージの情報や依存関係が書かれるファイル) の scripts
フィールドに、タスク名とコマンドのペアを記述します。
{
"scripts": {
"hello": "echo \"Hello World!\""
}
}
定義したタスクはnpm run タスク名
で実行できます。
$ npm run hello
> echo "Hello World!"
Hello World!
コマンドの内容は単なる Shell です。
Linux では /bin/sh
, Windows では cmd.exe
で実行されます。
npm ではたくさんの小さなコマンドライン プログラムが公開されているので、それらを活用して書いていきます。
パッケージ管理ツールとしての側面を活かしたシンプルな作り、というわけですね。
具体例
こんなにシンプルで、果たして使えるのか?
もちろん、プロダクトの方針にも依ると思いますが、私が試してみた感じでは、じゅうぶんに使えると思えました。
いくつか例を見て行きましょう。
※ 以下で紹介するスクリプト群は、基本的に Windows で動作確認しています。
単発テストに関しては Travis CI 上の Linux でも動作確認しています。
ツールやサーバー側ライブラリの開発
{
"scripts": {
"clean": "rimraf lib",
"lint": "eslint src",
"build": "npm-run-all clean lint build:babel",
"build:babel": "babel src --out-dir lib",
"test": "npm-run-all build test:mocha",
"test:mocha": "mocha test/*.js --compilers js:espower-babel/guess --colors",
"testing": "npm-run-all clean --parallel testing:*",
"testing:build": "npm run build:babel -- --watch --source-maps-inline",
"testing:mocha": "npm run test:mocha -- --watch --growl",
}
}
$ npm i --save-dev babel eslint espower-babel mocha npm-run-all power-assert rimraf
このスクリプト構成例は、clean
, lint
, build
, test
, testing
タスクを定義します。
- clean -- ビルド結果のディレクトリを削除します。
- lint -- ESLint を用いて、ソースコードを静的検証します。
-
build -- Babel を用いて、ES2015 で書かれたソースコードを ES5 にトランスパイルします (その直前に
clean
,lint
を実行します)。 -
test -- Mocha + PowerAssert を用いた自動テストを実行します (その直前に
build
を実行します)。 -
testing --
test
をウォッチ モードで実行します。コードを編集して保存すると即座にビルドされ、テストが再実行され、結果がデスクトップ通知で報告されます。- Windows では Growl for Windows を予めインストールしておく必要があります。
- インストールしなくても、テスト自体は動作します。
もちろん、依存パッケージを --save-dev
で保存しておくことで、他の環境では npm i
コマンド一発ですべてダウンロードされて使えるようになります。
クライアント側ライブラリの開発
{
"scripts": {
"clean": "rimraf lib dist",
"lint": "eslint src",
"build": "npm-run-all clean lint build:*",
"build:lib": "babel src --out-dir lib --source-maps-inline",
"build:dist": "mkdirp dist && browserify lib/index.js --debug -t babelify --standalone __LIBRARY_NAME__ > dist/__LIBRARY_NAME__.js",
"build:dist-min": "mkdirp dist && browserify lib/index.js -t babelify --standalone __LIBRARY_NAME__ | uglifyjs - --compress --mangle > dist/__LIBRARY_NAME__.min.js",
"test": "npm-run-all clean lint build:lib test:karma",
"test:karma": "karma start karma.conf.js --single-run",
"testing": "npm-run-all clean --parallel testing:*",
"testing:build": "babel src --out-dir lib --watch",
"testing:karma": "karma start karma.conf.js --auto-watch --reporters growl,progress"
}
}
module.exports = function(config) {
config.set({
basePath: "",
frameworks: ["browserify", "mocha"],
files: [
"node_modules/babel/node_modules/babel-core/browser-polyfill.js",
"test/*.js"
],
browsers: ["Chrome", "Firefox", "IE"],
preprocessors: {
"test/*.js": ["browserify"]
},
browserify: {
debug: true,
extensions: [".js"],
transform: [
"babelify",
"espowerify"
]
}
});
};
$ npm i --save-dev babel babelify browserify eslint espowerify karma karma-browserify karma-chrome-launcher karma-firefox-launcher karma-ie-launcher karma-mocha mkdirp mocha npm-run-all power-assert rimraf uglify-js
※
__LIBRARY_NAME__
には、実際の名前を入れてください。
一気に長くなってしまいました。
だいたい Browserify と Karma のせい。
このスクリプト構成例は、clean
, lint
, build
, test
, testing
タスクを定義します (前項と同じです)。
- clean -- ビルド結果のディレクトリを削除します。
- lint -- ESLint を用いて、ソースコードを静的検証します。
-
build -- この工程は少し複雑です。
- ふたつのディレクトリ
lib
,dist
を生成します。 -
lib
には、Babel を利用して、ライブラリ利用者が Browserify で依存管理をする場合のための成果物を生成します。 -
dist
には、Browserify, Babel, UglifyJS を利用して、ブラウザから直接読み込んだり、RequireJS で依存管理をする場合のための成果物を生成します。
- ふたつのディレクトリ
-
test -- Karma + Mocha + PowerAssert を用いた自動テストを実行します (その直前に
build:lib
を実行します)。 -
testing --
test
をウォッチ モードで実行します。コードを編集して保存すると即座にビルドされ、テストが再実行され、結果がデスクトップ通知で報告されます。
TODO
- Travis CI でテストできない
- testling 試したい
- 他のランナー (TestemとかProtractorとか) も試したい
- Isomophicのテスト (ブラウザと Node で同時実行するランナー無いか?)
Webアプリケーション開発
TODO
検証中です。
上記2つの内容と大きくは変わらず、cpx を利用した単純コピーと [node-dev][node-dev] あたりを利用したサーバー実行が入ると予測。
あと API テストの方針とか...
まとめ
TODO
- ツールはまず CLI を持っている事が多いので、他のタスク ランナーと比較して、専用ラッパーへの依存を減らせる場合がある。
-
npm
で単一責務の小さなツールを探して or 作って公開して、パズルのように組み合わせて使うのは楽しい。一部だけ交換するのが楽なので、進化ペースを上昇させられる。 - Shell は stdin/out による Streams ベースのプラットフォームで、Gulp に似ている。
[おまけ] この記事に登場したパッケージ紹介
npm 一般
- npm-run-all -- 拙作。複数の npm-scripts を順番 or 並列に実行する CLI.
ファイル操作系
-
mkdirp -- Substack (Browserifyのオーナー) 作。クロスプラットフォームの
mkdir -p
. ディレクトリが既存の場合は何もしない。 -
rimraf -- Isaacs (npmのオーナー) 作。クロスプラットフォームの
rm -rf
. -
cpx -- 拙作。変更監視できる
cp
コマンド。Glob記法で指定したファイルの変更監視をして、変更時に指定ディレクトリへコピーする (ディレクトリ ツリー構造を保ったまま)。Browserify 互換の変換モジュールを噛ませられる。 -
catw -- Substack 作。変更監視できる
cat
コマンド。Browserify 互換の変換モジュールを噛ませられる。 - watch -- Isaacs 作。指定ディレクトリでファイル更新があった際に任意の Shell コマンドを実行させられる。
JavaScript 変換系
- babel -- 超人 sebmck 作。EcmaScript の標準委員会で検討されている新仕様を ES5 で動くコードに変換してくれるツール。
-
Browserify -- Substack 作。Node.js の
require
の Lookup の仕様をフロントエンドに持ち込めるツール。 - UglifyJS -- 有名なミニファイ ツール。未使用コードの削除も行ってくれる (重要)。
テスト系
- ESLint -- 静的検証ツール。ESTree 仕様に則った抽象構文木を対象とした、さまざまな検証ルールをプラグインできる。組み込みのルールもきめ細やかな設定が可能。ES2015 や JSX にも対応している。
- Karma -- テストランナー。複数のブラウザを立ち上げてその中でテストを実行し、結果をコンソールに出力してくれる。
- Mocha -- 人気のテストハーネス。
- PowerAssert -- twada 作。アサーション ライブラリ。事前の変換によって、アサート式が失敗した時に詳細な情報を出力してくれる。便利。
- espower-babel -- azu 作。Mocha プラグイン。テストコードに対して Babel + PowerAssert の変換をしてくれる。
- espowerify -- twada 作。Browserify の変換モジュール。PowerAssert の変換をしてくれる。