Help us understand the problem. What is going on with this article?

[WIP] npm-scripts を使い倒そう!

More than 3 years have passed since last update.

※ 書きかけです

パッケージ依存管理ツール npm

npm は、今や Web 開発には欠かすことのできないパッケージ依存管理ツールです。
Browserify, Babel, Gulp, LESS のようなツール、Koa, Express のようなサーバー側のライブラリ、 React, AngularJS のようなクライアント側のライブラリまで揃っています。
サーバー側はもちろん、クライアント側の依存管理も Browserify を併用することでスマートに実現できます。

そんな npm ですが、実はタスク ランナーの機能も持ち合わせています。
Grunt や Gulp の影に隠れて目立たない存在でしたが、Substack の記事からこっち、注目を集め始めています (たぶん)。

タスク ランナー npm

タスク ランナーといえば、Web 界隈では Grunt や Gulp が有名です。

これらは環境構築・ビルド・デプロイ等、目的に応じた定形処理(タスク)を登録しておき、コマンドひとつで実行できるようにしておくツールです。
それに加えて、ツールたちはタスクを定義しやすくする様々な工夫を競っています。

さて、タスク ランナーとしての npm はとてもシンプルです。
package.json (パッケージの情報や依存関係が書かれるファイル) の scripts フィールドに、タスク名とコマンドのペアを記述します。

package.json
{
    "scripts": {
        "hello": "echo \"Hello World!\""
    }
}

定義したタスクはnpm run タスク名で実行できます。

shell
$ npm run hello

> echo "Hello World!"
Hello World!

コマンドの内容は単なる Shell です。
Linux では /bin/sh, Windows では cmd.exe で実行されます。
npm ではたくさんの小さなコマンドライン プログラムが公開されているので、それらを活用して書いていきます。
パッケージ管理ツールとしての側面を活かしたシンプルな作り、というわけですね。

具体例

こんなにシンプルで、果たして使えるのか?

もちろん、プロダクトの方針にも依ると思いますが、私が試してみた感じでは、じゅうぶんに使えると思えました。
いくつか例を見て行きましょう。

※ 以下で紹介するスクリプト群は、基本的に Windows で動作確認しています。
  単発テストに関しては Travis CI 上の Linux でも動作確認しています。

ツールやサーバー側ライブラリの開発

package.json
{
  "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",
  }
}
shell
$ 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 コマンド一発ですべてダウンロードされて使えるようになります。

クライアント側ライブラリの開発

package.json
{
  "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"
  }
}
karma.conf.js
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"
      ]
    }
  });
};
shell
$ 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__ には、実際の名前を入れてください。

一気に長くなってしまいました。
だいたい BrowserifyKarma のせい。

このスクリプト構成例は、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 の変換をしてくれる。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした