天天看點

npm中package.json與package-lock.json的差別

作者:尚矽谷教育

子產品化開發在前端越來越流行,使用node和npm可以很友善的下載下傳管理項目所需要的依賴子產品。package.json就是用來描述項目及項目所依賴的資訊子產品。那package.json和package-lock.json有什麼關聯呢。

一、package.json

通過npm包管理工具,指令行 npm install 可以自動生成package.json。

dependencies和devDependencies

devDependencies下列出的子產品,是我們開發時用的依賴項,像一些進行單元測試之類的包,比如jest,我們用寫單元測試,它們不會被部署到生産環境。

dependencies下的子產品,則是我們生産環境中需要的依賴,即正常運作該包時所需要的依賴項。

npm中package.json與package-lock.json的差別

語義化版本:

使用第三方依賴時,通常需要指定依賴的版本範圍,比如:

"dependencies": {

"core-js": "^3.8.3",

"axios": "^1.3.1",

"element-ui": "^2.15.12",

"vue-router": "^3.6.5",

"vuex": "^3.6.2",

"vue": "^2.6.14"

},

版本号由三部分組成:major.minor.patch,主版本号.次版本号.修補版本号。

例如:"vue-router": "^3.6.5",主要版本3,次要版本6,更新檔5。

  • 更新檔中的更改表示不會破壞任何内容的錯誤修複。
  • 次要版本的更改表示不會破壞任何内容的新功能。
  • 主要版本的更改代表了一個破壞相容性的大變化。如果使用者不适應主要版本更改,則内容将無法正常工作。
  • ^向上尖号是定義向後(新)相容依賴,在大版本上相同,就允許下載下傳最新的包。

語義化版本規則定義了一種理想的版本号更新規則,希望所有的依賴更新都能遵循這個規則,但是往往會有許多依賴不是嚴格遵循這些規定的。

是以,如何管理好這些依賴,尤其是這些依賴的版本就顯得尤為重要,否則一不小心就會陷入因依賴版本不一緻導緻的各種問題中。

二、問題的産生

當我們使用了 ^ 或者其他符号來控制依賴包版本号的時候 ,多人開發,就有可能存在大家安裝的依賴包版本不一樣的情況,就會存在項目運作的結果不一樣。

場景

安裝 vue 後,我們可以在項目中的 package.json 中看到版本号為 vue: ^3.0.0,這也是我們電腦中的版本号。然而,時間一長,vue 釋出了新版本 3.0.1。如果一個新同僚克隆了項目并執行了 npm install,那麼他電腦中的 vue 版本将會是 3.0.1。因為 ^ 僅鎖定了主版本,是以我們的電腦中的 vue 版本會不一緻。理論上來說,它們應該是相容的(如果大家都遵循語義版本控制),但是 bugfix 可能會影響我們正在使用的功能。此外,當使用不同版本的 vue 運作時,應用程式也會産生不同的結果。

大家思考思考,這樣的話,不同人電腦安裝的依賴版項目,是不是都有可能不一樣,就會導緻每個人電腦運作的應用程式産生不同的結果。就會存在bug的隐患。

問題産出的原因

package.json檔案隻能鎖定大版本,即版本号的第一位,不能鎖定後面的小版本,你每次npm install時候拉取的該大版本下面最新的版本

解決辦法

為了解決 npm install 的不确定性問題,在 npm 5.x 版本新增了 package-lock.json 檔案

當你執行npm install的時候,node從package.json檔案讀取子產品名稱,從package-lock.json檔案中擷取版本号,然後進行下載下傳或者更新。

三、package-lock.json

package-lock.json 它會在 npm 更改 node_modules 目錄樹 或者 package.json 時自動生成的,它準确的描述了目前項目npm包的依賴樹,并且在随後的安裝中會根據 package-lock.json 來安裝,保證是相同的一個依賴樹,不考慮這個過程中是否有某個依賴有小版本的更新。

package-lock.json檔案可以鎖定所有子產品的版本号,包括主子產品和所有依賴子子產品。package-lock.json 的作用是鎖定依賴結構,即隻要你目錄下有 package-lock.json 檔案,那麼你每次執行 npm install 後生成的 node_modules 目錄結構一定是完全相同的。

package-lock.json生成邏輯

正文例如:我們有如下依賴結構

"dependencies": {

"core-js": "^3.8.3",

"axios": "^1.3.1",

"element-ui": "^2.15.12",

"vue-router": "^3.6.5",

"vuex": "^3.6.2",

"vue": "^2.6.14"

}

在執行 npm install 後生成的 package-lock.json 如下:

"dependencies": {

"axios": {

"version": "1.3.2",

"resolved": "https://registry.npmjs.org/axios/-/axios-1.3.2.tgz",

"integrity": "sha512-1M3O703bYqYuPhbHeya5bnhpYVsDDRyQSabNja04mZtboLNSuZ4YrltestrLXfHgmzua4TpUqRiVKbiQuo2epw==",

"requires": {

"follow-redirects": "^1.15.0",

"form-data": "^4.0.0",

"proxy-from-env": "^1.1.0"

}

},

"core-js": {

"version": "2.6.12",

"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz",

"integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="

},

"element-ui": {

"version": "2.15.12",

"resolved": "https://registry.npmjs.org/element-ui/-/element-ui-2.15.12.tgz",

"integrity": "sha512-Y5FMT2BPOindU2GkDEQ5ZKUVxDawKONRNMh2eL3uBx1FOtvUJ+L6IxXLVsNxq4WnaX/UnVNgWXebl7DobygZMg==",

"requires": {

"async-validator": "~1.8.1",

"babel-helper-vue-jsx-merge-props": "^2.0.0",

"deepmerge": "^1.2.0",

"normalize-wheel": "^1.0.1",

"resize-observer-polyfill": "^1.5.0",

"throttle-debounce": "^1.0.1"

}

},

}

  • dependencies 是一個對象,對象和 node_modules 中的包結構一一對應,對象的 key 為包名稱,值為包的一些描述資訊:
  • version:包版本 —— 這個包目前安裝在 node_modules 中的版本。
  • resolved:包具體的安裝來源。
  • integrity:包 hash 值,基于 Subresource Integrity 來驗證已安裝的軟體包是否被改動過、是否已失效
  • requires:對應子依賴的依賴,與子依賴的 package.json 中 dependencies的依賴項相同。
  • dependencies:結構和外層的 dependencies 結構相同,存儲安裝在子依賴 node_modules 中的依賴包。

這裡注意:并不是所有的子依賴都有 dependencies 屬性,隻有子依賴的依賴和目前已安裝在根目錄的 node_modules 中的依賴沖突之後,才會有這個屬性。

使用建議

開發系統應用時,建議把 package-lock.json 檔案送出到代碼版本倉庫,進而保證所有團隊開發者以及 CI 環節可以在執行 npm install 時安裝的依賴版本都是一緻的。

注意事項

使用cnpm install時候,并不會生成 package-lock.json 檔案,也不會根據 package-lock.json 來安裝依賴包,還是會使用 package.json 來安裝。

總結

package.json記錄的是目前項目中你下載下傳了哪些包(也即npm install xx 的包資訊),記錄了你下載下傳的包資訊(位址、版本号等),不包含依賴包資訊。

package-lock.json檔案記錄的是目前項目中你下載下傳了哪些包以及你下載下傳的這些包的各種依賴包資訊,包括位址、版本号等。