今まで知らずにいたnpmスクリプトでできる3つのこと
読む所要時間: 12 分
Node.jsエコシステムには便利なCLIツールが多く含まれ、その多くで設定を変更でき目的に応じた調整ができます。ただし、時には非常にカスタマイズされた構成やスクリプトが必要になります。このような時に役立つのが、「npmスクリプト」です。これを使用し、「build」、「dev」、または「start」スクリプトを設定したことがあるかもしれませんが、他にも多くのことができます。このブログ記事では、非常に便利な隠れた機能についてお話します。
作業に入る前に、最新バージョンのnpm
がインストールされていることを確認してください。これらの多くは、yarn
、berry
、pnpm
でも機能しますが、この記事ではnpm
に焦点を置きます。この記事の内容はすべてnpm
バージョン6.10でテスト済みです。
npmスクリプトとは?
「npmスクリプト」について話すということは、package.json
のscripts
フィールドのエントリについて話すことを意味します。scripts
フィールドには、さまざまなコマンドやスクリプトを指定するオブジェクトを保持します。これらのスクリプトはnpm run <script-name>
を使用し実行できます。
例えば、package.json
が以下のような場合:
以下を実行できます。
多くの引数をCLIコマンドに渡したいが、毎回入力し直したくはない、という場合に、この方法は特に便利です。さらに、依存関係により公開されたスクリプトにアクセスすることもできます。この場合、グローバルに依存関係をインストールする必要はありません。
例えば、TypeScriptを使用する場合、全員にnpm install -g typescript
を使用してグローバルにインストールしてもらう代わりに、npm install --save-dev typescript
を使用してdev依存関係としてインストールし、そのあとで"scripts"
セクションにbuild
スクリプトを追加できます。
このプロジェクトを使用する人はTypeScriptをグローバルでインストールする必要がありません。代わりに、npm install
を実行した後にnpm run build
を実行できます。これはインストールされた同じコマンドのさまざまなバージョンを持つ複数のプロジェクトを使用できることも意味します。
このようなコマンドのエイリアスは、npmスクリプトの最も有名な部分でしょう。しかし、npmスクリプトを活用する方法はその他にも多数あります。
pre-/post-が付いたスクリプト
このブログで取り扱うヒントやトリックの中でも、これが一番よく知られているかもしれませんが、非常に強力であるためここで取り扱います。
以下のスクリプトセクションがあるとします。
ここでnpm run build
を実行すると、以下のものが自動的にトリガされます。
prebuild
が呼び出され、rimraf
ツールを実行し、dist
フォルダを削除build
が実行され、TypeScriptコンパイラが実行されるpostbuild
が呼び出され、npm run test
が実行されるtest
が実行され、jest
test runnerが実行される
これが機能するのは、npm
が、スクリプトに、同じ形式で名前が付けられていて、pre
またはpost
が前に付いた他のスクリプトがないかを自動的に検出し、その順序で実行するためです。これは、スクリプトを複雑にすることなくコマンドを繋げる便利な方法です。以下は、これに適したユースケースです。
- ビルドのアーティファクトを削除する
- テスト前にリンターを実行する
- アプリケーションの構築前にデータをダウンロードする
同じ動作がビルトインコマンドにも適用されます。例えば、preinstall
、prepack
です。ここで変則的なのは、version
です。これはpreversion
、version
、postversion
を提供します。version
とpostversion
の違いは、npmがpreversion
とversion
で実行された変更がコミットされた後でpostversion呼び出されることです。これらのライフサイクルスクリプトの詳細については、npmドキュメントをご覧ください。
環境変数
次に、私がこの事実を初めて発見したときに、嬉しい驚きを感じたことについてお話します。npm run…
を通じてコマンドやスクリプトを実行する際、環境変数はnpm
からの変数を使用し自動的に拡張されます。
すべての環境変数にはnpm_
のプレフィックスが付き、これらは2つのタイプにグループ分けできます。
npm_config_
で始まるものは、グローバルnpm構成またはプロジェクト特有の.npmrc
ファイルからの一般的なnpm構成npm_package_
で始まるものは、プロジェクト特有のもの
プロジェクトでスクリプトに渡される値に興味がある場合には、以下のエントリをスクリプトに追加します。
次に、npm run check-env
をコマンドラインで実行すると、npm
により設定されたすべての環境変数がリスト形式で表示されます。以下は、私が特に注目した点です。
package.json
のすべてのシングルエントリを環境変数として検索できる。JSONでのプロパティへのアクセスに類似しているが、セパレータとして「_
」を使用する点が異なる。例えば、npm_package_dependencies_twilio
は、インストールされたtwilio
のバージョンを提供し、npm_package_author_email
は、author
プロパティのメールフィールドを提供する。配列の値にアクセスするには、「_
」を前に付けたインデックス値(npm_package_keywords_0
など)を使用し、最初のキーワードを取得する。npm
バージョン、node
バージョン、オペレーティングシステムは、npm_config_user_agent
で取得できる。形式は、npm/6.10.0 node/v10.19.0 darwin x64
のようになる。darwin
はmacOS、x64
はプロセッサアーキテクチャである。- HEADのハッシュは、
npm_package_gitHead
で取得できる。
便利な変数が多数あるため、皆さんもご確認ください。特にオートメーションスクリプトを作成する際に便利です。
また、一般的なNode.jsの環境変数の詳細についてもご覧ください。
引数を渡し、解析する
ここまでは、スクリプトの作成方法、設定される環境変数、スクリプトの呼び出し方について話してきました。ただし、時には、引数をスクリプトに渡し、より動的に処理できるようにしたい場合があります。npmスクリプトに引数を渡す方法は2通りあります。
第1の方法は、実際のコマンドに直接引数を渡す方法です。例:
これは以下のように実行されます。
ここで重要なのは、「--
」とその後に続く1個のスペースです。それ以降の部分は、スクリプトの実際のコマンドに一対一で渡されます。これは、例えば上記の例のように、tsc
のようなベースコマンドを公開し、コマンドに追加の引数を渡す場合に便利です。
第2の方法は、npmのビルトインの引数パーサーを使用することです。これは、あまり知られていないnpmスクリプトの機能だと思います。私は初見のときにとても感激しました。基本的に、npmは、スクリプトに渡されたあらゆる引数を解析します(引数が「--
」とそれに続く1個のスペースに続いて渡された場合を除く)。npmが解析を終えると、それらは環境変数のなかのnpm_config_
の下で使用できるようになります。
これをテストするため、新しいscripts
エントリを作成します。
そして、次を実行します。
これは、Hello Dominik Kundel
を出力します。ただし、私達がこの引数パーサーを構成しているのではないため、引数の構文はあまり柔軟ではないことに注意してください。例えば、「=
」記号を削除し、同じコマンドをもう一度実行します。
この場合、出力はHello true true Kundel Dominik
になります。これは、--last
と--first
がブール値フラグとして解釈され、値がtrue
に設定され、残りの引数が未解析の引数としてスクリプトに渡されるためです。その結果、echo "Hello $npm_config_first $npm_config_last" "Kundel" "Dominik"
が呼びだされます。
上記のように引数パーサーが非常に厳格だとしても、シンプルなスクリプトをいくつか作成し、引数の解析に労力を割かない場合、これは非常に強力なツールとなります。
便利なツール
npmスクリプトを使用し、その力を解放する方法をいくつか見てきましたが、npmスクリプトを次のレベルへと導く、私のお気に入りのツールをご紹介します。
rimraf
: Windows環境においてもrm -rf
を実行できるncp
:cp
の代わりに使用できる、優れたクロスプラットフォームツールnpm-run-all
: さまざまなnpmスクリプトを順次実行するrun-s
と並行実行するrun-p
という2つの便利なコマンドを公開(ReactアプリケーションとExpressサービスを同時に実行する場合に便利)cross-env
: さまざまなプラットフォームにおいて、npmスクリプトで環境変数を使用する場合に便利なツール
これはほんの数例であり、他にも多くの便利なツールがあると思います。他の便利なツールをご存知の場合には、お気軽にdkundel@twilio.comまでメールで、またはTwitterでダイレクトメッセージを送信してください。ここに追加させていただきます。
まとめ
npmスクリプトは、プロジェクトの作業をしているあらゆる人を支援し、開発経験を向上させる便利な方法です。npmスクリプトを使用すれば、簡単なコマンド作成によるコマンドタスクの再実行や、明確なインターフェイスの作成による内部実装の抽象化が可能になり、また、簡単なスクリプトインターフェイスとして機能させることもできます。
皆さんが構築したスクリプトや、npmスクリプトを構築中に発見した他のヒントなどについてお聞かせください。
- Twitter: @dkundel
- Email: dkundel@twilio.com
- GitHub: dkundel
- dkundel.com