npm install xxxx --legacy-peer-deps命令是什么? - 知乎 https://zhuanlan.zhihu.com/p/506596270
npm install xxxx --legacy-peer-deps命令是什么?
摘要:帶着好奇心,研究學習了一番npm install xxxx --legacy-peer-deps命令是什么?為什么可以解決下載時候產生的依賴沖突呢?
本文分享自華為雲社區《npm install xxxx --legacy-peer-deps命令是什么?為什么可以解決下載時候產生的依賴沖突呢?》,作者: gentle_zhou 。
在日常使用命令npm install / npm install XX下載依賴的操作中,我經常會遇到無法解析依賴樹的問題(依賴沖突):
但是每當遇到這種情況的時候,我用命令npm install --legacy-peer-deps就可以順利進行下載操作:
這是為什么呢?帶着好奇心,我去研究學習了一番npm install xxxx --legacy-peer-deps命令是什么?為什么可以解決下載時候產生的依賴沖突呢?(注:我本地當前正在使用的npm版本是8.6.0)
本文導航:什么是peerDependency?;npm install xxxx --legacy-peer-deps命令是什么?為什么可以解決下載時候產生的依賴沖突呢?;參考資料。
什么是peerDependency?
我們日常在前端項目開發過程中,見到最多的一定是package.json文件里的devDependencies(用於在開發環境下依賴的模塊)和dependencies(無論開發環境還是生產環境都需要的依賴模塊)這兩個字段(感興趣的小伙伴可以看我這篇文章:package.json文件里的dependencies和devDependencies有什么區別嗎?)。
那么命令--legacy-peer-dep里的peerDependency是什么依賴呢?根據geeksforgeeks網站里的定義:
Peer Dependencies: In package.json file, there is an object called as peerDependencies and it consists of all the packages that are exactly required in the project or to the person who is downloading and the version numbers should also be the same. That is the reason they were named as peerDependencies. The best example is ‘react’ which is common in every project to run similarly.
翻譯一下就是說,在package.json文件中,存在一個叫做peerDependencies(對等依賴關系)的對象,它包含了項目里需要的所有的包或則用戶正在下載的版本號相同的所有的包(很繞,但意思就是對等依賴關系指定我們的包與某個特定版本的npm包兼容);對等依賴關系最好的例子就是React,一個聲明式的創建用戶界面的JS庫。
那么我們為什么需要對等依賴關系呢?
假設我們現在有一個HelloHWCloud工程,已經在其根目錄下的package.json文件中的dependencies字段里聲明了packageA作為依賴,而其下面有兩個項目app_A和app_B,它們也依賴packageA。如果我們用dependencies而不是peerDepenedencies來聲明,那么npm install安裝完項目之后的依賴結構如下圖所示:
├── HelloHWCloud
│ └── node_modules
│ ├── packageA
│ ├── app_A
│ │ └── nodule_modules
│ │ └── packageA
│ └── app_B
│ │ └── nodule_modules
│ │ └── packageA
從上圖可以看出,packageA依賴包被安裝了3次,造成了2次安裝冗余。
而如果采用peerDepenedency來下載,就可以避免這個核心依賴庫被重復下載的問題。還是上面那個場景,我們在項目app_A和app_B的package.json文件里的peerDependencies字段聲明一下核心依賴庫packageA,然后在根目錄的package.json文件里的dependencies字段也聲明一下packageA。接着再執行npm install,生成的依賴結構就會如下圖所示:
├── HelloHWCloud
│ └── node_modules
│ ├── packageA
│ ├── app_A
│ └── app_B
如上圖所示,packageA就只會被安裝一次。因此,npm 從版本v7開始,install就默認以peerDependencies的方式去下載了:
- 如果用戶在根目錄的package.json文件里顯式依賴了核心庫,那么各個子項目里的peerDepenedencies聲明就可以忽略
- 如果用戶沒有顯式依賴核心庫,那么就按照子項目的peerDepenedencies中聲明的版本將依賴安裝到項目根目錄里
而方式2就會導致一個問題:用戶依賴的包版本與各個子項目依賴的包版本相互不兼容,那么就會報錯(無法解析依賴樹的問題(依賴沖突))讓用戶自行去修復,因而導致安裝過程的中斷。(因為是從npm v7引入的,因此npm v3-v6就不會發生這個錯誤)
npm install xxxx --legacy-peer-deps命令是什么?為什么可以解決下載時候產生的依賴沖突呢?
npm install xxxx --legacy-peer-deps命令與其說是告訴npm要去干什么,不如說是告訴npm不要去干什么。
legacy的意思:遺產/(軟件或硬件)已過時但因使用范圍廣而難以替代的;而npm install xxxx --legacy-peer-deps命令用於繞過peerDependency里依賴的自動安裝;它告訴npm忽略項目中引入的各個依賴模塊之間依賴相同但版本不同的問題,以npm v3-v6的方式去繼續執行安裝操作。
所以其實該命令並沒有真的解決沖突,而是忽略了沖突,以“過時”(v3-v6)的方式進行下載操作。
參考資料
- https://classic.yarnpkg.com/en/docs/dependency-types
- https://github.blog/2021-02-02-npm-7-is-now-generally-available/
- https://blog.logrocket.com/whats-new-in-npm-v7/
- https://stackoverflow.com/questions/66239691/what-does-npm-install-legacy-peer-deps-do-exactly-when-is-it-recommended-wh
【前端開發技巧】npm install xxxx --legacy-peer-deps到底做了些什么? - 掘金 https://juejin.cn/post/6971268824288985118
下面,我就結合我現有的理解實踐進行分析解答:
在理解 --legacy-peer-deps 做了什么前,我們先來了解一下peerDependency

正常開發中,我們經常接觸到的是package.json中的dependencies 和devDependencies, 本文不對上面兩個進行細節分析,讓我們來看看peerDependencies是什么?
Dependencies: Libraries or modules that an NPM module needs in order to work in production.
peerDependencies: A peer dependency is a specific version or set of versions of a third-party software library that a module is designed to work with. They're similar in concept to the relationship between a browser extension and a browser.
在NPM v7中,默認安裝peerDependencies,在我們日常使用的插件例如babel-plugin-dynamic-import-node、babel-plugin-transform-vue-jsx、lottie-web,它們都依賴於webpack進行開發的。
peerDependencies在我們的日常開發當中到底承擔一個怎樣的角色呢?
舉個例子 【借鑒】
假設現在有一個helloWorld工程,已經在其package.json的dependencies中聲明了 packageA,有兩個插件plugin1和plugin2他們也依賴 packageA,如果在插件中使用dependencies而不是peerDependencies來聲明 packageA,那么npm install安裝完plugin1和plugin2之后的依賴圖是這樣的:
.
├── helloWorld
│ └── node_modules
│ ├── packageA
│ ├── plugin1
│ │ └── nodule_modules
│ │ └── packageA
│ └── plugin2
│ │ └── nodule_modules
│ │ └── packageA
復制代碼
從上面的依賴圖可以看出,helloWorld 本身已經安裝了一次packageA,但是因為因為在 plugin1 和 plugin2 中的 dependencies 也聲明了 packageA,所以最后 packageA 會被安裝三次,有兩次安裝是冗余的。
而 peerDependency 就可以避免類似的核心依賴庫被重復下載的問題。 如果在 plugin1 和 plugin2 的package.json中使用peerDependency來聲明核心依賴庫,例如:
plugin1/package.json
{
"peerDependencies": {
"packageA": "1.0.1"
}
}
復制代碼
plugin2/package.json
{
"peerDependencies": {
"packageA": "1.0.1"
}
}
復制代碼
在主系統中聲明一下 packageA:
helloWorld/package.json
{
"dependencies": {
"packageA": "1.0.1"
}
}
復制代碼
此時在主系統中執行npm install生成的依賴圖就是這樣的:
.
├── helloWorld
│ └── node_modules
│ ├── packageA
│ ├── plugin1
│ └── plugin2
復制代碼
可以看到這時候生成的依賴圖是扁平的,packageA 也只會被安裝一次。
因此我們總結下在插件使用dependencies聲明依賴庫的特點:
- 如果用戶顯式依賴了核心庫,則可以忽略各插件的peerDependencies聲明;
- 如果用戶沒有顯式依賴核心庫,則按照插件peerDependencies中聲明的版本將庫安裝到項目根目錄中;
- 當用戶依賴的版本、各插件依賴的版本之間不相互兼容,會報錯讓用戶自行修復。
--legacy-peer-deps 的作用
在理解peerDependencies的功能后,讓我們來看看 --legacy-peer-deps 的作用; 
上面講過,在NPM v7中,現在默認安裝peerDependencies。
在很多情況下,這會導致版本沖突,從而中斷安裝過程。
--legacy-peer-deps標志是在v7中引入的,目的是繞過peerDependency自動安裝;它告訴 NPM 忽略項目中引入的各個modules之間的相同modules但不同版本的問題並繼續安裝,保證各個引入的依賴之間對自身所使用的不同版本modules共存。

