前言
上篇文章我們瞭解了package.json
,一般與它同時出現的還有一個package-lock.json
,這兩者又有什麼關係呢?下面一起來了解吧。
介紹
package-lock.json
它會在 npm 更改 node_modules 目錄樹 或者 package.json 時自動生成的 ,它準確的描述了當前項目npm包的依賴樹,並且在隨後的安裝中會根據 package-lock.json 來安裝,保證是相同的一個依賴樹,不考慮這個過程中是否有某個依賴有小版本的更新。
爲什麼需要package-lock.json
相信跟多人跟我一樣會有一個疑問:爲什麼有了package.json
還需要package-lock.json
?實際上兩者並不是同一時期提出來的,package-lock.json
是在npm5
之後才提出來的,從上面MDN的介紹來看,它的出現主要是爲了解決依賴的版本管理問題。
npm install
執行後,會生成一個node_modules
樹,在理想情況下, 希望對於同一個 package.json
總是生成完全相同 node_modules
樹。在某些情況下,確實如此。但在多數情況下,npm
無法做到這一點。有以下兩個原因:
- 某些依賴項自上次安裝以來,可能已發佈了新版本 。比如:A 包在團隊中第一個人安裝的時候是
1.0.5
版本,package.json
中的配置項爲A: '^1.0.5'
,團隊中第二個人把代碼拉下來的時候,A 包的版本已經升級成了1.0.8
,根據package.json
中的semver-range version
規範,此時第二個人npm install
後 A 的版本爲1.0.8
,可能會造成因爲依賴版本不同而導致的 bug - 針對上面的問題,可能有的小夥伴會覺得把 A 的版本號固定爲
A: '1.0.5'
不就可以了嗎?但是這樣的做法其實並沒有解決問題, 比如 A 的某個依賴在第一個人下載的時候是2.1.3
版本,但是第二個人下載的時候已經升級到了2.2.5
版本,此時生成的node_modules
樹依舊不完全相同 ,固定版本只是固定來自身的版本,依賴的版本無法固定
關於依賴的版本
我們可以先來了解依賴的版本
{
"dependencies": {
"@nestjs/common": "^10.0.0",
"@nestjs/core": "^10.0.0",
}
}
比如我們常見的依賴版本一般長這樣,它一般由三部分組成:major.minor.patch
,依次爲主版本號、次版本號、修補版本號。
主要版本
的更改代表了一個破壞兼容性的大變化。 如果用戶不適應主要版本更改,則內容將無法正常工作。次要版本
的更改表示不會破壞任何內容的新功能。修補版本
的更改表示不會破壞任何內容的錯誤修復。
比如上面我們看到的^10.0.0
,主版本號爲10、次版本號爲0、修補版本號爲0,那^
表示什麼呢?
版本號指定標識符
這個符號其實是用來指定版本範圍的,與之對應的有以下符號:
^
會匹配最新的大版本依賴包,比如^1.2.3
會匹配所有>=1.1.2 <2.0.0
的版本,包括1.3.0
,但是不包括2.0.0
~
會匹配最近的小版本依賴包,比如~1.2.3
會匹配所有>=1.1.2 <1.2.0
的版本,但是不包括1.3.0
*
安裝最新版本的依賴包,比如*1.2.3
會匹配x.x.x
- 無符號時,比如
1.2.3
,那就是將要使用的確切版本,總是會下載這個版本的依賴包
認識package-lock.json
這個文件看起來比package.json
又大有複雜,動不動就是上萬行代碼。
我們可以只安裝某一個依賴看看它內部長啥樣,比如axios
:
{
"name": "demo",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"asynckit": {
"version": "0.4.0",
"resolved": "https://mirrors.tencent.com/npm/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"axios": {
"version": "1.4.0",
"resolved": "https://mirrors.tencent.com/npm/axios/-/axios-1.4.0.tgz",
"integrity": "sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==",
"requires": {
"follow-redirects": "^1.15.0",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://mirrors.tencent.com/npm/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://mirrors.tencent.com/npm/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"follow-redirects": {
"version": "1.15.2",
"resolved": "https://mirrors.tencent.com/npm/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA=="
},
"form-data": {
"version": "4.0.0",
"resolved": "https://mirrors.tencent.com/npm/form-data/-/form-data-4.0.0.tgz",
"integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
}
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://mirrors.tencent.com/npm/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://mirrors.tencent.com/npm/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://mirrors.tencent.com/npm/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
}
}
}
從這裏我們可以發現,它的dependencies
與package.json
不一樣,它除了axios
之外還包含了一些其它的依賴,實際上這些其它的依賴都是axios
的依賴或者是它依賴的依賴...
從上面的介紹中我們也能知道,它實際上描述的是當前項目的依賴樹
它有一些與package.json
文件中不同的屬性,比如:
lockfileVersion
一個整數版本,從1開始,該文檔的版本號
resolved
依賴的安裝地址,其實就是一個包下載地址
intergrity
表示解壓的完整性 Hash 值
dev
表示該模塊是否爲頂級模塊的開發依賴或者是一個的傳遞依賴關係
requires
依賴包所需要的所有依賴項,對應依賴包 package.json 裏
dependencices
中的依賴項
npm install策略
當我們每次使用npm install
進行依賴安裝的時候,它到底是按照什麼規則去幫我們下載依賴的呢?
這裏其實有好幾個版本,但我們只需要瞭解最新版本就行了。
先看有無lock
文件:
如果有,則對比package.json和package-lock.json
- 如果
package-lock.json
裏包版本號符合package.json
要求,則直接獲取包信息(如果是從遠程拉取,則按照package-lock.json
,否則以實際緩存的爲準),構建依賴樹,(注意這一步只是確定邏輯上的依賴樹,並非真正的安裝,後面會根據這個依賴結構去下載或拿到緩存中的依賴包);那麼接下來就看.npmrc
裏有沒有緩存,如果有緩存文件,則從緩存文件中拉取內容,否則從遠程拉取;並更改package-lock。json
版本號 - 如果版本號不符合要求,則直接從遠程拉取,並更新
package-lock.json
中的版本號
如果沒有,則:
- 根據
package.json
構建依賴樹(注意這一步只是確定邏輯上的依賴樹,並非真正的安裝,後面會根據這個依賴結構去下載或拿到緩存中的依賴包) - 如果緩存中
(.npmrc)
有,則優先從緩存中讀取,否則從遠程讀取;注意:(如果是從遠程拉取,則按照package.json
,否則以實際緩存的爲準)
需要注意的是,在使用cnpm install
時候,並不會生成 package-lock.json
文件,也不會根據 package-lock.json
來安裝依賴,它只會根據 package.json
來安裝依賴
場景一
// package.json
"dependencies": {
"vue": "^2.0.0"
}
// package-lock.json
"dependencies": {
"vue": {
"version": "2.7.14",
"resolved": "https://mirrors.tencent.com/npm/vue/-/vue-2.7.14.tgz",
"integrity": "sha512-b2qkFyOM0kwqWFuQmgd4o+uHGU7T+2z3T+WQp8UBjADfEv2n4FEMffzBmCKNP0IGzOEEfYjvtcC62xaSKeQDrQ==",
"requires": {
"@vue/compiler-sfc": "2.7.14",
"csstype": "^3.1.0"
}
}
}
這種情況下package-lock.json
指定的2.7.14
在^2.0.0
指定的範圍內,npm install
會安裝vue2.7.14
版本。
場景二
// package.json
"dependencies": {
"vue": "^2.2.0"
}
// package-lock.json
"dependencies": {
"vue": {
"version": "2.1.0",
"resolved": "https://mirrors.tencent.com/npm/vue/-/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.7.14
版本,並且將package-lock.json
的版本更新爲2.7.14
。
現在應該能夠理解package.json
文件是如何做到對依賴進行版本鎖定的吧,我們一般在安裝依賴時如果不指定版本,那麼安裝的版本號並不是固定的而是一個最優版本,最優版本會在版本前多了一個^
或者~
符號
"dependencies": {
"vue": "^2.0.0"
}
但我們的lock
文件中肯定是會指定一個固定版本進行安裝的,一般是改依賴的符合版本範圍的最新版本
"dependencies": {
"vue": {
"version": "2.1.0",
"resolved": "https://mirrors.tencent.com/npm/vue/-/vue-2.1.0.tgz",
"integrity": "sha1-KTuj76rKhGqmvL+sRc+FJMxZfj0="
}
}
至於爲什麼不直接在package.json
中將版本鎖定,那是因爲你只能指定你安裝的依賴的版本,但不能指定你依賴的依賴的版本
package-lock.json什麼時候會變?
開發過程中是不是經常遇到這個文件衝突的,自己明明沒改這個文件爲啥會衝突?那是因爲我們的一些操作會影響到該文件的內容,比如:
package-lock.json
在npm install
的時候會自動生成
- 當我們修改依賴位置,比如將部分依賴從
開發依賴改
成生產依賴
,雖然整體上的依賴並未改變,但是也會影響package-lock.json
中依賴的dev
字段
- 如果我們切換
npm鏡像
時,執行npm install
時也會修改package-lock.json
,因爲它是會記錄我們的依賴包地址的(resolved) - 當我們使用
npm install
添加或npm uninstall
移除包的時候,也會修改package-lock.json
- 當我們更新某個包的版本的時候,也會修改
package-lock.json
package-lock.json需要提交到倉庫嗎?
npm 官網建議:把
package-lock.json
一起提交到代碼庫中,不要 ignore。但是在執行 npm publish 的時候,它會被忽略而不會發布出去。
如何查看依賴安裝的版本?
上面我們已經瞭解到,package.json
中保存的依賴版本一般不是一個具體版本,而是一個帶有^
或~
的最優版本,那我們怎麼才能知道當前項目依賴安裝的具體版本呢?
- 查看
package-lock.json
文件,這裏保存的是依賴的具體版本 - 從
node_modules
文件夾中找到對應依賴的package.json
文件,裏面的version
字段就是該依賴的版本 - 使用
npm list --depth 0
查看項目所有的依賴版本
如果這篇文章有幫助到你,❤️關注+點贊❤️鼓勵一下作者,關注 前端南玖
第一時間獲取最新文章~