web-dev-qa-db-ja.com

"npm install"がpackage-lock.jsonを書き換えるのはなぜですか?

私は最近npm @ 5にアップグレードしました。私は今package.jsonからのすべてを含むpackage-lock.jsonファイルを持っています。 npm installを実行すると、依存関係のバージョンがロックファイルから取得され、node_modulesディレクトリに何をインストールする必要があるのか​​が判断されます。奇妙なことに、実際に私のpackage-lock.jsonファイルを修正して書き換えることになります。

たとえば、ロックファイルのTypeScriptはバージョン2.1.6に指定されています。それから、npm installコマンドの後、バージョンは2.4.1に変更されました。これはロックファイルの目的全体を無効にするようです。

何が足りないの?ロックファイルを実際に尊重するにはどうすればよいですか。

440
Viper Bailey

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.0package-lock.jsonの動作が変更されました。あなたが観察する振舞いは明らかにバージョン5.1.0のnpmによって意図されています。

つまり、package.jsonの依存関係について新しいバージョンが見つかった場合は、package-lock.jsonpackage.jsonよりも優先されます。依存関係を効果的に固定したい場合は、プレフィックスを付けずにバージョンを指定する必要があります。たとえば、それらを1.2.0または~1.2.0ではなく^1.2.0として記述する必要があります。それからpackage.jsonpackage-lock.jsonの組み合わせは再現可能なビルドを生成します。明確にすると、package-lock.jsonだけではルートレベルの依存関係がロックされなくなりました。

この設計上の決定が良かったかどうかは議論の余地がありますが、 issue#17979 でのGitHubでのこの混乱から生じる継続的な議論があります。 (私の目では、それは疑わしい決定です。少なくともlockという名前はもはや当てはまりません。)

もう1つ注意が必要です。npmjs.orgではなくGitHubから直接パッケージを取得する場合など、不変パッケージをサポートしていないレジストリに対する制限もあります。さらなる説明は このパッケージロックのドキュメント を参照してください。

280
jotaen

私は新しいバージョンのnpm 5.7.1 が新しいコマンドnpm ciと共にあることを発見しました、それはpackage-lock.jsonだけからインストールするでしょう

新しいnpm ciコマンドは、ロックファイルからのみインストールされます。あなたのpackage.jsonとあなたのロックファイルが同期していないなら、それはエラーを報告するでしょう。

それはあなたのnode_modulesを捨てそしてそれを最初から作り直すことによって働きます。

あなたがあなたのロックファイルにあるものだけを手に入れることを保証することを越えてそれはあなたがnode_modulesで始めないときnpmインストールよりもはるかに速い(2x-10x!)。

その名前からわかるように、継続的インテグレーション環境にとって大きな恩恵になると私たちは予想しています。また、gitタグからプロダクションを展開する人々が大きな利益を得ることを期待しています。

102

新しく導入されたものを使う

npm ci

npm ciは、大規模チームにとって最大の利益を約束します。パッケージロックに「サインオフ」する機能を開発者に与えることで、大規模チーム間でより効率的なコラボレーションが促進され、ロックファイルにあるものを正確にインストールできることで、毎月数百時間ではないにせよより多くの時間を費やして素晴らしいものを作り上げ、出荷すること。

より速く、より信頼性の高いビルドのためのnpm ciの導入

59
Gal Margalit

短い答え:

  • Package-lock.jsonが存在する場合は、package.jsonをオーバーライドします。
  • Package.jsonが変更されると、package-lock.jsonを無効にします。

これは物事を説明するかもしれないシナリオです(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)
9

あなたはおそらく次のようなものを持っています:

"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を取得しますが、widgetwidget 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で説明されているルートパッケージを含むパッケージツリー全体をロックします。 TypeScript2.4.1package-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が以前にインストールされたパッケージのメタデータ解決の繰り返しをスキップできるようにすることで、インストールプロセスを最適化します。

https://docs.npmjs.com/files/package-lock.json

6
Matt

npm ciの代わりにnpm installコマンドを使用してください。

「ci」は「クリーンインストール」を表します。 lenientのpackage.jsonファイルの依存関係ではなく、package-lock.jsonファイルに基づいてプロジェクトの依存関係がインストールされます。

それはあなたの他のチームメイトと同じビルドを作り出すでしょう、そしてそれはまたはるかに速いです。

5
Daniel Tonon

将来的には、--from-lock-file(または類似の)フラグを使用して、変更せずにpackage-lock.jsonから only をインストールすることができます。 

これは、再現可能なビルドが重要なCIなどの環境で役立ちます。

機能の追跡については https://github.com/npm/npm/issues/18286 を参照してください。

5

この問題は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は、既存のプロジェクトを今すぐインストールするときに使用するコマンドです。

3
Daniel Tonon

これに関する未解決の問題が彼らのgithubページにあります: https://github.com/npm/npm/issues/18712

開発者が異なるオペレーティングシステムを使用している場合、この問題は最も深刻です。

1
hrdwdmrbl

編集: "ロック"という名前はトリッキーな、そのNPMは糸に追いつこうとしています。ロックされたファイルではありません。 package.jsonはユーザーが固定したファイルで、「インストール」するとnode_modulesフォルダツリーが生成され、そのツリーはpackage-lock.jsonで書き込まれます。つまり、その逆のことです - 依存関係のバージョンはいつものようにpackage.jsonから引き出され、package-lock.jsonpackage-tree.jsonと呼ばれるべきです。

(これが私の答えをより明確にしてくれたことを願っています。


単純化した答え:package.jsonはいつものように依存関係を持ちますが、package-lock.jsonは「正確で、より重要な点で再現可能なnode_modulesツリー」です( npm docs自体 から取り出されます)。

トリッキーな名前に関しては、そのNPMは糸に追いつこうとしています。

0
Z. Khullah