一、起因
毎日のコードインスペクションで、ライブラリが実際にアップロードされていることがわかりましたpackage-lock.json
。これは、バージョンのすべての依存関係とサブ依存関係を静的に記録するファイルです。このファイルのバージョンが最初に送信され、現在の9か月間に更新されていないため、この期間中に、フロントエンドライブラリは大小のpackage.json
依存ライブラリでpackage-lock.json
アップグレードされましたが、このファイルはアップグレードされていません。そこで、私はMRを作成し、ライブラリのファイルを削除しました。これは、元々は変更された開発バージョンでした。ただし、開発バージョンとビルドバージョンが同じマシン上にあるため、npm clean cache
命令はマシン上のすべてのキャッシュパッケージをクリアし、リリースバージョンのビルドに同時に影響します。これによりnode_modules
、ライブラリのサブ依存関係がアップグレードされ、互換性の問題が発生します。リリース前夜に発見された問題ですので、影響は大きくなります。
2.分析
package.lock.json
正確にはファイルとは何ですか?彼の役割は何ですか?私たちは図書館に行かなければなりませんか?次に、痛みを和らげ、npm install
プロセスの波とpackage.lock.json
効果に力を与えます。
1.セマンティックバージョン
semverpackage-lock.json
を理解する必要がある前にプローブで。それはnpmの背後にある小さなヒーローです。npmがそれをどのように使用するかは、ここから学ぶことができます。要約すると、他のアプリケーションで使用できるアプリケーションを開発している場合、各アップグレードの変更がサードパーティの使用にどのように影響するかを説明する必要があります。これは、セマンティックバージョンが伝えたいことです。バージョンには3つの部分があります。それぞれメジャーバージョン、マイナーバージョン、およびチェックアップバージョンを指します。たとえば、メジャーバージョン、マイナーバージョン、バージョンです。バージョンは機能に影響を与えません。マイナーバージョンの変更は、多くの場合、新しい機能を追加するためのものであり、使用には影響しません。ただし、メジャーバージョンの変更は、使用レベルでの非互換性をもたらすことが多く、さらに調整が必要です。(webpackがアップグレードされるたびに考えてください!)X, Y, Z
1.2.3
1
2
bugfix
3
bugfix
2. npmパッケージ管理
パッケージ管理を簡単にするためだけにnpm
登場しました。プロジェクトには数百の依存関係があり、各依存関係には数百の依存関係があります。依存関係の地獄に陥らないようにするために、いくつかの単純なコマンドでnpm
これらの依存関係をインストールおよび管理できるため、時間を大幅に節約できます。
npm
パッケージをインストールして保存package.json
すると、パッケージ名やバージョンなどの情報が自動的に追加されます。npm
もちろん、バージョンのワイルドカードもサポートされています。npm
デフォルトで最新バージョンをインストールし、バージョン番号の前に^記号を追加します。たとえば^1.2.12
、これは最小1.2.12
バージョンを使用する必要があることを示し、これより上では、同じ大きなバージョン番号のバージョンであれば問題ありません。結局、マイナーバージョンとバグ修正バージョンは使用に影響を与えないので、同じメジャーバージョンの上位バージョンを使用しても安全です。あなたは学ぶことができsemver
、より約ワイルドカードここでは、だけでなく、電卓。npm
semver
- 記号
^
:インストールされているのがアプリケーションのバージョン以上であることを示しますが、同じメジャーバージョン番号が必要です。例:vuex: "^3.1.3"
、3.1.3
およびそれ以上3.x.x
が満たされています。 - シンボル
~
:アプリケーションのバージョン以上にインストールされていることを示しますが、同じメジャーバージョン番号とマイナーバージョン番号が必要です。例:vuex: "^3.1.3"
、3.1.3
およびそれ以上3.1.x
が満たされています。 - 署名なし:署名なしは、固定バージョン番号を意味します。たとえば、
vuex: "3.1.3"
これはインストールされている3.1.3
バージョンである必要があります。
3.なぜ必要なのかpackage-lock.json
npm install
inputでありpackage.json
、その出力はnode_modules
ツリーです。理想的にnpm install
は纯函数
、同じように動作し、package.json
常に同じnode_modules
ツリーに対してまったく同じツリーを生成する必要があります。いくつかのケースでは、それは本当です。しかし、他の多くの状況では、これnpm
は実行できません。以下の理由があります。
- npmのバージョンが異なると、インストールアルゴリズムも異なります。
- 前回のインストール以降、一部の依存関係がリリースされている可能性があるため、package.jsonのsemver-rangeバージョンに従って依存関係が更新されます。
- 依存関係の新しいバージョンがリリースされた可能性があります。固定依存関係指定子( "^ 1.2.3"ではなく "1.2.3")を使用しても、サブ依存関係を修正できないため、更新されますアイテムのバージョン。
// package.json
"dependencies": {
"packageA": "^2.1.0"
}
依存関係バージョンの更新により、いくつかの問題が発生する可能性があります。たとえば、A
新しいプロジェクトが作成され、上記のpackage.json
ファイルが生成されますがA
、依存関係をインストールする時期は比較的早いです。現時点packageA
では、最新バージョンは2.1.0
コードと互換性があり、表示されませんbug
。後で、B
クローンされたA
プロジェクトはpackageA
、依存関係をインストールするときの最新バージョンです。バージョンは2.2.0
、セマンティクスに従ってnpm
インストールされます2.2.0
が、2.2.0
バージョンAPI
が変更され、コードにバグが生じる可能性があります。
これがpackage.json
もたらす問題であり、同じコピーpackage.json
が異なる時間と環境で異なる結果を生み出します。
理論上、この問題は発生しないはずnpm
です。オープンソースの世界の一部として、リリースの原則にも従うためです。同じメジャーバージョン番号の新しいバージョンは古いバージョンと互換性があるはずです。つまり、2.1.0
アップグレードし2.2.0
てもAPIは変更されません。
しかし、多くのオープンソースライブラリ開発者は、このリリース原則を厳密に遵守しなかったため、上記の問題が発生しました。
異なる環境node_modules
で同じものを生成するには、をnpm
使用しますpackage-lock.json
。npm install
これは、npm
生成または更新されますそれが実行するたびにpackage-lock.json
。
4.異なるnpmバージョンでのnpm iのルール
npm 5.0.x版本
:package.json
依存関係に更新があるかどうかに関係なく、それnpm i
に基づいてpackage-lock.json
ダウンロードされます。このインストール戦略に対応して、誰かがこの問題(#16866)を提起し、それが5.1.0
ポストバージョンルールに発展しました。5.1.0版本后
:package.json
新しいバージョンの依存関係にあるとき、依存関係と更新の新しいバージョンをダウンロードするnpm install
ことを無視package-lock.json
しますpackage-lock.json
。このインストール戦略に対応して、誰かが問題を提起しました-#179795.4.2
ポストバージョンルールを取得するには、npm寄稿者iarnaのコメントを参照してください。5.4.2版本后
:package.json
ファイルが1つしかない場合、操作npm i
はそのpackage-lock.json
ファイルに基づいてファイルを生成します。このファイルは、今回のinstall
スナップショットに相当します。package.json
指定された直接依存バージョンだけでなく、間接依存バージョンも記録されます。- もしと互換性のあるバージョン(バージョンバージョンの指定された範囲内で)、この時点でもかかわらず、新しいバージョンが存在し、実行がまだ基づいて実践シナリオ1 -ダウンロード。
package.json
semver-range version
package-lock.json
package-lock.json
package.json
package.json
npm i
package-lock.json
- 手動で変更した場合とし、バージョンと互換性がありません、実行時間は、互換性に更新されます練習シナリオ2 -バージョン。
package.json
version ranges
package-lock.json
npm i
package-lock.json
package.json
注:作成された依存関係
npm install
のpackage.json
リストを読み、それpackage-lock.json
を使用して、インストールするこれらの依存関係のバージョンを通知します。依存関係が存在するpackage.json
が存在しないpackage-lock.json
場合、実行npm install
により、この依存関係の決定されたバージョンがpackage-lock.json
inに更新され、他の依存関係のバージョンは更新されません。
5.練習
シーン1
// package.json
"dependencies": {
"vue": "^2.0.0"
}
// package-lock.json
"dependencies": {
"vue": {
"version": "2.1.0",
"resolved": "https://registry.npm.taobao.org/vue/download/vue-2.1.0.tgz",
"integrity": "sha1-KTuj76rKhGqmvL+sRc+FJMxZfj0="
}
}
この場合package-lock.json
、指定さ2.1.0
れ^2.0.0
た範囲、npm install
インストールされているvue2.1.0
バージョンで指定されています。
シーン2
// package.json
"dependencies": {
"vue": "^2.2.0"
}
// package-lock.json
"dependencies": {
"vue": {
"version": "2.1.0",
"resolved": "https://registry.npm.taobao.org/vue/download/vue-2.1.0.tgz",
"integrity": "sha1-KTuj76rKhGqmvL+sRc+FJMxZfj0="
}
}
この場合、package-lock.json
指定され2.1.0
ていない^ 2.2.0
指定された範囲内で、npm install
我々は続く^2.2.0
最新インストールするには、ルールを2.6.10
、バージョン、およびpackage-lock.json
アップデートのバージョンを2.6.10
。
3.この例を引用する
この削除後package.lock.json
の重要な理由はantd
、ライブラリrc-pagination
へのサブ依存関係のアップグレードによるものでした。引用しantd
たバージョンは変更されていませんが、どちらも変更されています3.21.3
。しかし、従属関係の説明ではantd
、次のようになります。
semver
ルールとは対照的に、依存コンポーネントのメジャーバージョンとマイナーバージョンは一貫している必要があり、改訂バージョンの要件はありません。ライブラリのコードは復元前に削除されpackage-lock.json
、rc-pagination
依存関係の場合は1.20.12
バージョンがダウンロードされ、削除package-lock.json
後、新しくinstall
生成package-lock.json
されたロックバージョンは1.20.15
次のようになります。
然而,对于rc-pagination
的版本升级,开发者没有遵循上述的semver
规则,其中某个修订版本,有了不兼容修改,对于分页组件,pageSize
必须默认传值,而不是由计算得出。故产品中所有依赖分页组件的模块,如果没有给pageSize
传递默认值,通通报错白屏。
四、镇定思痛
在这里,需要引出npm ci
的概念:
关于npm ci
ci
:Continuous Integration
,持续集成。npm
版本至少是v5.7.1
。- 此命令与
npm install
类似,不同之处在于它旨在用于自动化环境,例如集成测试环境、线上环境、或者您希望确保干净安装依赖项的任何情况。通过跳过某些面向用户的功能,它可以比常规的npm install
快得多。它也比常规安装更严格,它可以捕获由于本地环境的增量安装引起的错误或不一致。 npm ci
是根据package-lock.json
去安装确定的依赖,package.json
只是用来验证是不是有不匹配的版本,假设package-lock.json
中存在一个确定版本的依赖A
,如果package.json
中不存在依赖A
或者依赖A
版本和lock
中不兼容,npm ci
就会报错。
npm ci
和 npm install
差异
- 项目必须存在
package-lock.json
或npm-shrinkwrap.json
。 - 如果
package-lock.json
中的依赖和package.json
中不匹配,npm ci
会退出并且报错,而不是去更新package-lock.json
。 npm ci
只能安装整个项目的依赖,无法安装单个依赖。- 如果
node_modules
已经存在,它将在npm ci
开始安装之前自动删除。 npm ci
永远不会改变package.json
和package-lock.json
。
我们目前的CI
构建流程脚本中使用的一直是npm i
。即使package.lock.json
文件上库,对于大版本的依赖变动,我们安装的包也是不确定的。而且 npm i
指令需要耗费大量的时间进行依赖检查,远程地址查询,本地依赖对比等操作,比较费时。对于这两点,我们完全可以通过package-lock.json
上库 + npm ci
指令,控制库上每次自动化构建流程下载的依赖包固定不变。对于package.json
和package-lock.json
文件的更新,由团队内统一的一个负责人负责,每次大版本变更,确定一个依赖的子依赖版本树,这样保证其他人不会改动到package-lock.json
,且团队内部每个人下载的包固定不变。