Node.js
npm

npm shrinkwrapで依存モジュールのバージョンを固定

More than 3 years have passed since last update.

Node.jsで作られたアプリケーションをデプロイするときに、npm shrinkwrapを使って依存モジュールのバージョンまで固定した状態でインストールする方法を紹介します。

背景

npm install で依存モジュールをインストールするとき、package.json^1.2.3~1.2.3 といったバージョン指定をしているモジュールが1つでもあると、semver に従って 1.2.5 などのより新しいバージョンがインストールされる可能性があります。

セマンティックバージョンの意味からすれば、1.2.3 が互換性のある 1.2.5 に置き換わっても同じように動作すべきですが、現実問題としてテストしたバージョンと本番にデプロイされるバージョンが意図せず変わってしまうのは気持ちが悪く、依存モジュールを含めてバージョンを固定する方法を調べました。

実現方法

まずは npm install します。すると、package.json に従って依存関係にあるモジュールが node_modules 以下にインストールされます。

$ cd myapp/
$ npm install
...
$ ls
node_modules/  package.json

次に npm shrinkwrap します。すると、node_modules にインストールされている全モジュールのバージョン情報が npm-shrinkwrap.json というファイルに出力されます。直接依存しているモジュールだけでなく、間接的に依存しているモジュールも含まれていることが分かります。

$ npm shrinkwrap
wrote npm-shrinkwrap.json
$ ls
node_modules/  npm-shrinkwrap.json  package.json
$ cat npm-shrinkwrap.json
{
  "name": "myapp",
  "version": "0.0.1",
  "dependencies": {
    "socket.io": {
      "version": "1.1.0",
      "from": "socket.io@^1.1.0",
      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.1.0.tgz",
      "dependencies": {
        "engine.io": {
          "version": "1.4.0",
          "from": "engine.io@1.4.0",
          "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.4.0.tg
z",
          "dependencies": {
            "debug": {
              "version": "1.0.3",
              "from": "debug@1.0.3",
              "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.3.tgz",

...

最後に、npm-shrinkwrap.json がある状態で npm install すると、今度は package.json ではなく npm-shrinkwrap.json に記載されたバージョンに固定されて各モジュールがインストールされます。めでたし、めでたし。

$ cd myapp/
$ ls
npm-shrinkwrap.json  package.json
$ npm install

補足

私は Node.js の素人なので、この方法が一般に推奨される方法なのかが分かっていません。やりたいことは「開発環境で動作確認したバージョンと同じモジュールを本番環境で動かしたい」ということで、いくつかの選択肢のうちこの方法が一番良さそうに思えたというだけです。

  • 開発環境で動作確認した node_modules ごとコミットし、それをそのまま本番環境にデプロイ
    • 以前はこの方法を使っていたが、OSやアーキテクチャも違うので怪しいし、コミットするファイルも大量になってしまう
  • package.json だけコミットし、本番環境で npm install する
    • 動作確認したバージョンとは異なるバージョンがインストールされることがあり、しかもバージョン違いのせいで npm install がコケたことがあった
  • npm-shrinkwrap.json もコミットし、本番環境で npm install する
    • バージョンを固定してインストールできるので良さそう。ただし、リリース時にnpmサーバーがダウンしていたらリリースできない

もっと良い方法やデファクトな方法を知っている方がいましたら、ぜひフィードバックいただけると嬉しいです。