web-dev-qa-db-ja.com

package.jsonが変更された場合のnpmインストール

TL; DR:npm installが変更されている場合、npmスクリプトを実行する前にpackage.jsonを自動的に実行する方法はありますか?

問題のシナリオ

package.jsonを更新したブランチをプルまたはチェックアウトします。 npm run my-scriptを実行します。 my-scriptは、package.jsonに新しく追加されたパッケージに依存しています。 my-scriptは失敗します。なぜだろう。机を裏返す前に、念のためnpm installを実行します。 my-scriptは正常に実行されます。新しい机は必要ありません。

gradleのようなビルド/タスクランナーツールは、タスクを実行する前に依存関係が最新であることを確認します。私は常にnpmがそれを行わない(マイナーな)問題点でした。特に気に入らない2つの解決策を見つけました。

非理想的なソリューション:make

package.jsonのnpmスクリプトに依存してコマンドを実行する代わりに、makeを使用して、次のトリックで統合された依存関係の追跡を利用します。

# Smart install: Only executes if package.json's
# modification date is later than node_module's

node_modules: package.json
    npm install
    @rm -f node_modules/.modified
    @touch -m node_modules/.modified

install: node_modules 

ソース: https://mattandre.ws/2016/05/make-for-hipsters/

問題は、スクリプトを実行するためにmakeに依存する必要があり、他のスクリプトを便利に参照したり、スクリプトを並行して実行したり(npm-run-all)など、npmスクリプトの特定の利点を失う必要があることです。また、makeを知らない、または実行に問題がある場合(Windows)、他のユーザーと一緒に作業することは困難です。これは、node/npmエコシステムの外にある古いツールであり、このスマートインストールの利点だけではコストがかかりすぎます。

非理想的なソリューション:Gitフック

もう1つの方法は、post-merge gitフックを追加することです。

問題は、このソリューションがリポジトリに対してローカルであり、簡単に共有できないことです。 npm installは、gitマージでのみ自動的に実行されます。 package.jsonを他の方法で変更した場合でも、npm installの実行を覚えておく必要があります。確かに、それは実際にはマイナーなポイントです。それでも、スクリプトを実行する場合は、npm installの実行についてまったく考えなくて済むのは素晴らしいことです。

ソース: https://davidwalsh.name/git-hook-npm-install-package-json-modified

理想的なソリューション

次のような方法でpackage.jsonを定義したいと思います。

{
  "scripts": {
    "pre-run": "npm-smart-install",
    "my-script": "…"
  },
  "dependencies": {
    "npm-smart-install": "1.0.0"
  }
}

npm-smart-installは、私が存在したいと思った架空のnpmパッケージです。 pre-runは、架空のnpm-scriptsライフサイクルフックです。 npm run my-scriptを実行し、最後にスクリプトを実行してからpackage.jsonが変更されている場合は、npm installを実行してからmy-scriptを実行してください。

繰り返します:npm installがnpmエコシステム外のツールに依存せずに変更されている場合、npmスクリプトを実行する前にpackage.jsonを自動的に実行する方法はありますか?

22
Eugen

これでパッケージは完了です。 ここ です。理想的なシナリオで指定したのとまったく同じ方法で使用できます。 npm install install-changedを使用して、例のpre-runのようにカスタムスクリプトに追加します。 npm installが必要かどうかを判断し、必要に応じてそうする必要があります。

 {
  "scripts": {
    "pre-run": "install-changed",
    "my-script": "…"
  },

プログラムでこれを行うこともできますが、これが必要になるとは思いません。

let installChanged = require('install-changed')

let isModified = installChanged.watchPackage() 

上記の関数はまったく同じことを行います。さらに、便利なブール値も返します。

3
ninesalt