これまで npm shrinkwrap 使っていなかったんだけど、プライベートでやっているプロダクトで使うようにしたのでメモ。
3行まとめ
npm shrinkwrapするとnpm-shrinkwrap.jsonが生成される- npm 3系では
npm-shrinkwrap.jsonにdeependenciesのパッケージは記載されているが、devDependenciesのパッケージは記載されないのがデフォルトの挙動。devDependenciesを含めるには--devオプションを付ける - npm@4.0.1 からは
npm-shrinkwrap.jsonにdevDeependenciesのパッケージを含めるのがデフォルトの挙動。除外するには--productionオプションを付ける
きっかけ
サーバーを移設した際に新しいサーバーで npm install したらパッケージ間の依存関係が壊れた。同様のことはこれまでにたしか 2回ほどあって、3回目のときにはカイゼンしようと心に決めていたのでやった。
$ npm install ... npm WARN xxx requires a peer of yyy but none was installed.
どうして Yarn ではないのか?
Yarn を使ってもパッケージのバージョンを固定してくれるので、今回の問題に対してそれでも解決できたのだけれど。
しかし Yarn は別のプロジェクトで使っていて、つまり経験があるので、経験が無いほうの npm shrinkwrap という手段を選んだ。何かしらのヒントが得られるかもしれないと思って。
環境
手元の Mac の環境。ただし、後述するが npm のバージョンは途中で上げた。
$ node --version v6.9.5 $ npm --version 3.10.10
ドキュメント
公式ドキュメント にざっと目を通した。日本語訳 もあったが、内容が古かったため。
事始め
node_modules を一旦真っ新にしてから npm shrinkwrap した。
$ rm -rf node_modules $ npm install $ npm shrinkwrap wrote npm-shrinkwrap.json
npm-shrinkwrap.json が生成されたので git commit した。
ただし、この時点では npm-shrinkwrap.json に deependencies のパッケージは記載されているが、devDependencies のパッケージは記載されていない(重要)
devDependencies も含めてバージョン固定する
どうして npm-shrinkwrap.json に devDependencies のパッケージに含めないのがデフォルトの仕様なんだろう?複数の開発環境や CI の間で devDependencies パッケージのバージョンを揃えたいというのが自分の考えるフツウなのだが(Ruby の Bundler もそうだし)
ともあれ --dev オプションを付ければ devDependencies のパッケージも含められるとのことなので実行。
$ npm shrinkwrap --dev
npm@4.0.1 からは devDependencies のパッケージも含めるのがデフォルト
なお 公式ドキュメント や リリースノート にもあるように、npm のバージョン 4.0.1 からは npm-shrinkwrap.json に devDependencies のパッケージに含めるのがデフォルトの挙動になった(含めたくない場合は --production オプションを付ける)
ついでなので npm のバージョンを 4系に上げた。
$ npm install --global npm@4 $ npm --version 4.5.0
おまけ)npm 4系で npm-shrinkwrap.json を作り直した
npm のバージョンを 4系に上げて、何か挙動が変わっただろうかという確認のため、やり直してみた。
$ rm -rf node_modules $ rm npm-shrinkwrap.json $ npm install $ npm shrinkwrap wrote npm-shrinkwrap.json
差分を見る。
[@ANGELINA.local maskedgirl-ui]$ git diff diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 167b0e76..b136f399 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -6015,7 +6015,7 @@ }, "sinon": { "version": "2.2.0", - "from": "sinon@latest", + "from": "sinon@>=2.2.0 <3.0.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-2.2.0.tgz", "dev": true, "dependencies": {
なんだこれ。まさに、という記事を見つけた。
詳しくは上の記事の通りだが、今回 npm-shrinkwrap.json の差分が出たのは npm のバージョンを上げた影響ではなかった(記事を見ながら、ソースを追ってみたが、from の出力に関する箇所は npm@3.10.10 と npm@4.5.0 に差異はなかった)
まとめ
Yarn と較べて。Yarn は yarn install すれば yarn.lock も自動で生成されるのに対し、npm install と npm shrinkwrap が分かれている点が少し馴染めない。コマンドを打つのが面倒というより npm-shrinkwrap.json を意識せずに過ごしたいんだよなあ。
ともあれ npm パッケージのバージョン固定に成功した。めでたい。