私は最近npm @ 5にアップグレードしました。私は今package.jsonからのすべてを含むpackage-lock.jsonファイルを持っています。 npm install
を実行すると、依存関係のバージョンがロックファイルから取得され、node_modulesディレクトリに何をインストールする必要があるのかが判断されます。奇妙なことに、実際に私のpackage-lock.jsonファイルを修正して書き換えることになります。
たとえば、ロックファイルのTypeScriptはバージョン2.1.6に指定されています。それから、npm install
コマンドの後、バージョンは2.4.1に変更されました。これはロックファイルの目的全体を無効にするようです。
何が足りないの?ロックファイルを実際に尊重するにはどうすればよいですか。
Update 3: 他の回答でも指摘されているように、CIコンテキストで高速で再現可能なビルドを実現するための追加の方法としてnpm ci
コマンドがnpm 5.7.0で導入されました。詳しくは ドキュメント と npm blog をご覧ください。
更新2: ドキュメントを更新し、明確にするための問題は GitHub issue#18103 です。
更新1: npm 5.4.2で以下に記述された動作が修正されました。現在意図されている動作は GitHub issue#17979 で概説されています。
元の回答: issue#16866 で説明しているように、 npm 5.1.0 でpackage-lock.json
の動作が変更されました。あなたが観察する振舞いは明らかにバージョン5.1.0のnpmによって意図されています。
つまり、package.json
の依存関係について新しいバージョンが見つかった場合は、package-lock.json
がpackage.json
よりも優先されます。依存関係を効果的に固定したい場合は、プレフィックスを付けずにバージョンを指定する必要があります。たとえば、それらを1.2.0
または~1.2.0
ではなく^1.2.0
として記述する必要があります。それからpackage.json
とpackage-lock.json
の組み合わせは再現可能なビルドを生成します。明確にすると、package-lock.json
だけではルートレベルの依存関係がロックされなくなりました。
この設計上の決定が良かったかどうかは議論の余地がありますが、 issue#17979 でのGitHubでのこの混乱から生じる継続的な議論があります。 (私の目では、それは疑わしい決定です。少なくともlock
という名前はもはや当てはまりません。)
もう1つ注意が必要です。npmjs.orgではなくGitHubから直接パッケージを取得する場合など、不変パッケージをサポートしていないレジストリに対する制限もあります。さらなる説明は このパッケージロックのドキュメント を参照してください。
私は新しいバージョンのnpm 5.7.1 が新しいコマンドnpm ci
と共にあることを発見しました、それはpackage-lock.json
だけからインストールするでしょう
新しいnpm ciコマンドは、ロックファイルからのみインストールされます。あなたのpackage.jsonとあなたのロックファイルが同期していないなら、それはエラーを報告するでしょう。
それはあなたのnode_modulesを捨てそしてそれを最初から作り直すことによって働きます。
あなたがあなたのロックファイルにあるものだけを手に入れることを保証することを越えてそれはあなたがnode_modulesで始めないときnpmインストールよりもはるかに速い(2x-10x!)。
その名前からわかるように、継続的インテグレーション環境にとって大きな恩恵になると私たちは予想しています。また、gitタグからプロダクションを展開する人々が大きな利益を得ることを期待しています。
新しく導入されたものを使う
npm ci
npm ciは、大規模チームにとって最大の利益を約束します。パッケージロックに「サインオフ」する機能を開発者に与えることで、大規模チーム間でより効率的なコラボレーションが促進され、ロックファイルにあるものを正確にインストールできることで、毎月数百時間ではないにせよより多くの時間を費やして素晴らしいものを作り上げ、出荷すること。
短い答え:
これは物事を説明するかもしれないシナリオです(NPM 6.3.0で検証済み)
次のようにpackage.jsonで依存関係を宣言します。
"depA": "^1.0.0"
その後、npm install
を実行して、package-lock.jsonを生成します。
"depA": "1.0.0"
数日後、 "depA"の新しいマイナーバージョンがリリースされます。 "1.1.0"と言うと、次のようになります。
npm ci # respects only package-lock.json and installs 1.0.0
npm install # also, respects the package-lock version and keeps 1.0.0 installed
# (i.e. when package-lock.json exists, it overrules package.json)
次に、package.jsonを手動で次のように更新します。
"depA": "^1.1.0"
その後、再実行してください。
npm ci # will try to honor package-lock which says 1.0.0
# but that does not satisfy package.json requirement of "^1.1.0"
# so it would throw an error
npm install # installs "1.1.0" (as required by the updated package.json)
# also rewrites package-lock.json version to "1.1.0"
# (i.e. when package.json is modified, it overrules the package-lock.json)
あなたはおそらく次のようなものを持っています:
"TypeScript":"~2.1.6"
npmが最新のマイナーバージョンに更新するpackage.json
で、あなたの場合は2.4.1
編集:OPからの質問
しかし、「npm install」がロックファイルを変更する理由は説明されていません。ロックファイルは、再現可能なビルドを作成するためのものではありませんか?その場合、semver値に関係なく、同じ2.1.6バージョンを使用する必要があります。
回答:
これは、完全な依存関係ツリーをロックダウンすることを目的としています。
TypeScript v2.4.1
にはwidget ~v1.0.0
が必要だとしましょう。 npmをインストールすると、widget v1.0.0
が取得されます。後日、仲間の開発者(またはCIビルド)がnpmインストールを行い、TypeScript v2.4.1
を取得しますが、widget
はwidget v1.0.1
に更新されました。これで、ノードモジュールが同期しなくなりました。これは、package-lock.json
が防止するものです。またはより一般的に:
例として、考えてみましょう
パッケージA:
{"名前": "A"、 "バージョン": "0.1.0"、 "依存関係":{"B": "<0.1.0"}}
パッケージB:
{"名前": "B"、 "バージョン": "0.0.1"、 "依存関係":{"C": "<0.1.0"}}
およびパッケージC:
{「名前」:「C」、「バージョン」:「0.0.1」}
これらがレジストリで使用可能なA、B、およびCの唯一のバージョンである場合、通常のnpmインストールAがインストールされます。
[email protected]@[email protected]
ただし、B @ 0.0.2が公開されている場合、新しいnpmインストールAがインストールされます。
[email protected]@[email protected]は、新しいバージョンがBの依存関係を変更しなかったと仮定しています。もちろん、Bの新しいバージョンには、Cの新しいバージョンと任意の数の新しい依存関係を含めることができます。そのような変更が望ましくない場合、Aの作成者は[email protected]への依存関係を指定できます。ただし、Aの作者とBの作者が同じ人物でない場合、Aの作者が、Bがまったく変更されていないときにCの新しく公開されたバージョンをプルしたくないと言う方法はありません。
OP質問2:だから、私が正しく理解しているかどうかを見てみましょう。あなたが言っているのは、ロックファイルが二次依存関係のバージョンを指定しているが、依然としてトップレベルの依存関係を決定するためにpackage.jsonのファジーマッチングに依存しているということです。それは正確ですか?
回答:いいえ。package-lockは、
package.json
で説明されているルートパッケージを含むパッケージツリー全体をロックします。TypeScript
が2.4.1
のpackage-lock.json
でロックされている場合、変更されるまでそのままです。そして明日TypeScript
リリースバージョン2.4.2
と言いましょう。ブランチをチェックアウトしてnpm install
を実行すると、npmはロックファイルを尊重して2.4.1
をインストールします。
package-lock.json
の詳細:
package-lock.jsonは、npmがnode_modulesツリーまたはpackage.jsonを変更するすべての操作に対して自動的に生成されます。中間の依存関係の更新に関係なく、後続のインストールで同一のツリーを生成できるように、生成された正確なツリーを記述します。
このファイルは、ソースリポジトリにコミットされることを目的としており、さまざまな目的に使用されます。
チームメイト、デプロイメント、および継続的インテグレーションがまったく同じ依存関係をインストールすることが保証されるように、依存関係ツリーの単一の表現を記述します。
ユーザーがディレクトリ自体をコミットせずに、node_modulesの以前の状態に「タイムトラベル」する機能を提供します。
読み取り可能なソース管理差分によってツリーの変更の可視性を高めるため。
また、npmが以前にインストールされたパッケージのメタデータ解決の繰り返しをスキップできるようにすることで、インストールプロセスを最適化します。
npm ci
の代わりにnpm install
コマンドを使用してください。
「ci」は「クリーンインストール」を表します。 lenientのpackage.jsonファイルの依存関係ではなく、package-lock.jsonファイルに基づいてプロジェクトの依存関係がインストールされます。
それはあなたの他のチームメイトと同じビルドを作り出すでしょう、そしてそれはまたはるかに速いです。
将来的には、--from-lock-file
(または類似の)フラグを使用して、変更せずにpackage-lock.json
から only をインストールすることができます。
これは、再現可能なビルドが重要なCIなどの環境で役立ちます。
機能の追跡については https://github.com/npm/npm/issues/18286 を参照してください。
この問題はnpm v5.4.2で修正されているようです。
https://github.com/npm/npm/issues/17979
(スレッドの最後のコメントまでスクロールダウン)
更新
実際には5.6.0で修正されました。 5.4.2にはクロスプラットフォームのバグがあり、それが問題の原因となっていました。
https://github.com/npm/npm/issues/18712
更新2
ここで私の答えを参照してください: https://stackoverflow.com/a/53680257/1611058
npm ci
は、既存のプロジェクトを今すぐインストールするときに使用するコマンドです。
これに関する未解決の問題が彼らのgithubページにあります: https://github.com/npm/npm/issues/18712
開発者が異なるオペレーティングシステムを使用している場合、この問題は最も深刻です。
編集: "ロック"という名前はトリッキーな、そのNPMは糸に追いつこうとしています。ロックされたファイルではありません。 package.json
はユーザーが固定したファイルで、「インストール」するとnode_modulesフォルダツリーが生成され、そのツリーはpackage-lock.json
で書き込まれます。つまり、その逆のことです - 依存関係のバージョンはいつものようにpackage.json
から引き出され、package-lock.json
はpackage-tree.json
と呼ばれるべきです。
(これが私の答えをより明確にしてくれたことを願っています。
単純化した答え:package.json
はいつものように依存関係を持ちますが、package-lock.json
は「正確で、より重要な点で再現可能なnode_modulesツリー」です( npm docs自体 から取り出されます)。
トリッキーな名前に関しては、そのNPMは糸に追いつこうとしています。