没想到你是这样的npm install
大家好,我是若川。今天給大家推薦一篇關(guān)于 npm install 的好文。很快能看完。
點(diǎn)擊下方卡片關(guān)注我、加個(gè)星標(biāo)
學(xué)習(xí)源碼整體架構(gòu)系列、年度總結(jié)、JS基礎(chǔ)系列
前言
項(xiàng)目中執(zhí)行npm install發(fā)生了什么,眾所周知,執(zhí)行npm install時(shí)會(huì)在當(dāng)前項(xiàng)目目錄的node_modules中安裝依賴。并且將依賴項(xiàng)的層級(jí)關(guān)系保存在package-lock.json中。那么依賴項(xiàng)的層級(jí)關(guān)系是怎么確認(rèn)的?依賴項(xiàng)之間是否存在區(qū)別?有無package-lock.json在安裝時(shí)有什么區(qū)別呢?筆者希望借以此文可以和讀者們一起厘清npm install。
工欲善其事必先利其器,先一起來了解下npm install。
npm-install
常用的命令包含(具體含義和執(zhí)行效果會(huì)在下文說明)
npm install
npm install -P|--save-prod
npm install -D|--save-dev
npm install -O|--save-optional
npm install --no-save
aliases: npm i, npm add
npm install這個(gè)命令會(huì)在項(xiàng)目路徑下安裝一個(gè)或多個(gè)依賴包,如果項(xiàng)目中存在package-lock、npm-shrinkwrap或yarn.lock文件。那么安裝過程將就基于這些文件。其優(yōu)先級(jí)為:
npm-shrinkwrap.json
package-lock.json
yarn.lock
其中npm-shrinkwrap.json是npm 5之前的依賴鎖定文件,其在npm 5后被package-lock.json替換。兩個(gè)文件功能類似,最大的不同是npm-shrinkwrap.json需要執(zhí)行npm shrinkwrap來初始化生成,而package-lock.json為自動(dòng)生成。本文撰寫時(shí)npm使用的版本為v6.14.5,故下文所有樣例均在此版本下做交流討論。其他版本任何問題歡迎留言討論。yarn.lock是yarn cli的產(chǎn)物,不在此文章討論。
npm install執(zhí)行時(shí)會(huì)解析package.json中定義的依賴關(guān)系,進(jìn)而根據(jù)package.json生成package-lock.json依賴鎖定文件。package.json中的依賴關(guān)系可以由開發(fā)人員自行定義,也可使用npm install [--optional]來指定存儲(chǔ)位置,或使用npm install --no-save不進(jìn)行存儲(chǔ)。
自古習(xí)物先習(xí)源。package.json中是那些在影響依賴樹呢?
package.json
package.json文件是項(xiàng)目的描述文件,包括項(xiàng)目的name、version、description等很多字段。但真正影響依賴樹的并不多,包括dependencies、devDependencies 、peerDependencies、 optionalDependencies 、bundledDependencies。下面一起來看下他們區(qū)別和使用場景。
dependencies:主要依賴
dependencies是主要依賴。也即必須依賴。由包名和版本區(qū)間映射成的簡單 json對(duì)象組成。版本區(qū)間由一個(gè)或多個(gè)分隔符組成。是項(xiàng)目運(yùn)行、打包的主要依賴。執(zhí)行npm install時(shí)會(huì)從上至下遞歸安裝dependencies及其內(nèi)部依賴。并將解析的依賴樹存儲(chǔ)在package-lock.json中。會(huì)隨版本一起發(fā)布到npm庫。是最重要的依賴節(jié)點(diǎn)。
執(zhí)行npm install -P|--save-prod會(huì)將指定包放入此節(jié)點(diǎn)。
常用的dependencies如:axios、fetch等。
{"dependencies":?{"axios":?"^0.21.1","fetch":?"^1.1.0"} }devDependencies:開發(fā)依賴
devDependencies是開發(fā)環(huán)境的依賴。其格式同dependencies,開發(fā)人員本地執(zhí)行npm install時(shí)也會(huì)從上至下遞歸安裝devDependencies及其內(nèi)部依賴。并將解析的依賴樹存儲(chǔ)在package-lock.json中。也會(huì)隨版本一起發(fā)布到npm庫。但是不同的是。非開發(fā)人員通過項(xiàng)目安裝依賴時(shí)。也就是包安裝后出現(xiàn)在node_modules中時(shí),devDependencies不會(huì)被安裝,也不會(huì)出現(xiàn)在項(xiàng)目的package-lock.json中。
所以在開發(fā)時(shí),dependencies和devDependencies區(qū)別并不大,但是作為依賴包被其他項(xiàng)目引入時(shí),只有dependencies中的依賴會(huì)被解析成依賴樹并下載。devDependencies中的依賴會(huì)被忽略。
執(zhí)行npm install -D|--save-dev會(huì)將指定包放入此節(jié)點(diǎn)。
常用的devDependencies如:karma、mocha、webpack等
{"devDependencies":?{"karma":?"^1.3.0","mocha":?"^5.2.0","webpack":?"^1.13.1","webpack-dev-server":?"^1.14.1"} }peerDependencies:同等依賴
peerDependencies是同等依賴。其格式同dependencies。主要在開發(fā)包時(shí)使用,常規(guī)開發(fā)項(xiàng)目不建議使用。比如某些情況下開發(fā)人員為了表明在不同系統(tǒng)和運(yùn)行環(huán)境下的兼容性,即非所有情況下都是必要的依賴。就會(huì)通過peerDependencies來表明。peerDependencies中更像是當(dāng)前包所依賴是插件。peerDependencies里面的依賴會(huì)隨版本一起發(fā)布,但是不會(huì)自動(dòng)安裝,需要開發(fā)和使用人員手動(dòng)安裝。(npm v7下會(huì)默認(rèn)安裝)
如eslint-plugin-prettier會(huì)同等依賴eslint和prettier。即eslint-plugin-prettier需要在eslint和prettier都安裝時(shí)才會(huì)生效。但是其自身并不會(huì)強(qiáng)制安裝eslint和prettier。而是會(huì)通過警告的方式提示開發(fā)者。
`eslint-plugin-prettier requires a peer of xxx but none is installed. You must install peer dependencies yourself`如果不想在未安裝peerDependencies的情況下提示警告。可以通過peerDependenciesMeta設(shè)置optional為true來關(guān)閉警告。
{"peerDependencies":?{"eslint":?">=5.0.0","prettier":?">=1.13.0"},"peerDependenciesMeta":?{"eslint":?{"optional":?true}} }optionalDependencies:可選依賴
optionalDependencies是可選依賴。其格式同dependencies。當(dāng)需要某些依賴在安裝失敗時(shí)不會(huì)阻塞項(xiàng)目的運(yùn)行和打包,就可以使用optionalDependencies來定義。optionalDependencies里面的依賴會(huì)隨版本一起發(fā)布,且會(huì)自動(dòng)安裝。可以使用npm install --no-optional命令來跳過安裝。
執(zhí)行npm install -O|--save-optional會(huì)將指定包放入此節(jié)點(diǎn)。
optionalDependencies使用需要開發(fā)者在項(xiàng)目中作兼容。如:
try?{var?foo?=?require('foo')var?fooVersion?=?require('foo/package.json').version }?catch?(er)?{foo?=?null }if?(?notGoodFooVersion(fooVersion)?)?{foo?=?null }//?..?then?later?in?your?program?..if?(foo)?{foo.doFooThings() }bundledDependencies:綁定依賴
bundledDependencies是綁定依賴,其值是一個(gè)數(shù)組。在發(fā)包時(shí)定義綁定包。常規(guī)項(xiàng)目中使用的并不多。和npm install的也并無關(guān)系,所以在此不做過多介紹。值得一提的是,使用bundleDependencies也是可以的。
{"name":?"awesome-web-framework","version":?"1.0.0","bundledDependencies":?["renderized","super-streams"] }了解了package.json中影響依賴樹的節(jié)點(diǎn),那么接下來就是重頭戲npm install登場了~
一、無依賴沖突
最簡單的場景莫過于此,當(dāng)項(xiàng)目的package.json的依賴及其子 依賴間沒有沖突時(shí),即A依賴B、C、D。表示為A[B、C、D]。則依賴會(huì)平鋪在node_modules下。即使有多個(gè)相同的依賴,只要版本不存在沖突,就都符合當(dāng)前場景。
舉個(gè)例子。fetch-demo2項(xiàng)目中值依賴fetch這一個(gè)包。
{"name":?"fetch-demo2","version":?"1.0.0","description":?"","main":?"index.js","dependencies":?{"fetch":?"^1.1.0"},"devDependencies":?{},"scripts":?{"test":?"echo?\"Error:?no?test?specified\"?&&?exit?1"},"keywords":?[],"author":?"","license":?"ISC" }此時(shí)執(zhí)行npm i,會(huì)得到如下的目錄結(jié)構(gòu)的node_modules。
可得到依賴樹(根據(jù)package-lock.json分析得出)
不難得出以下結(jié)論。當(dāng)項(xiàng)目中的依賴無沖突時(shí),項(xiàng)目依賴及其內(nèi)部依賴會(huì)平鋪在一級(jí)node_modules中。
二、項(xiàng)目頂級(jí)依賴存在沖突
頂級(jí)依賴即項(xiàng)目package.json中的依賴。
當(dāng)項(xiàng)目頂級(jí)依賴存在沖突時(shí),會(huì)將頂級(jí)依賴放在node_modules中的一級(jí)目錄下,沖突的包放在自己的node_modules下。為了模擬這種場景,將biskviit@2.0.0放在fetch-demo2項(xiàng)目的頂級(jí)依賴上。
{"dependencies":?{"fetch":?"^1.1.0","biskviit":?"2.0.0"} }執(zhí)行npm install后查看node_modules的目錄結(jié)構(gòu)
分析依賴樹
可以看出在頂級(jí)依賴biskviit@2.0.0和內(nèi)部依賴biskviit@1.0.1存在沖突時(shí),頂級(jí)依賴會(huì)占據(jù)node_modules的一級(jí)目錄,內(nèi)部依賴則會(huì)存儲(chǔ)在其內(nèi)部的node_modules中
三、項(xiàng)目內(nèi)部依賴存在沖突
當(dāng)項(xiàng)目的內(nèi)部依賴存在沖突時(shí),會(huì)先檢測一級(jí)node_modules是否存在依賴包,不存在則存儲(chǔ),如果存在判斷是否有版本沖突,無沖突則使用一級(jí)node_modules的依賴包,有沖突則存儲(chǔ)在自身的node_modules中。還是舉例說明下。
一級(jí)node_modules無沖突包
發(fā)布自定義新包c(diǎn)onflict-lbywer@1.0.0到npm。其依賴為
{"dependencies":?{"biskviit":?"^2.0.0"} }將fetch-demo2項(xiàng)目的頂級(jí)依賴改為
{"dependencies":?{"conflict-lbywer":?"1.0.0","fetch":?"^1.1.0"} }刪除node_modules和package-lock.json后,執(zhí)行npm i后,查看目錄結(jié)構(gòu)
分析依賴樹
可以看出conflict-lbywer所依賴的biskviit@2.0.0和fetch所依賴的biskviit@1.0.1沖突時(shí),在頂級(jí)依賴沒有biskviit的情況下,將biskviit@2.0.0安裝到了頂級(jí)依賴。
如果將頂級(jí)依賴中的conflict-lbywer和fetch更換順序呢,依賴包順序是否會(huì)發(fā)生變化,我們一起來研究。
修改頂級(jí)依賴
{"dependencies":?{"fetch":?"^1.1.0","conflict-lbywer":?"1.0.0"} }刪除node_modules和package-lock.json后,執(zhí)行npm i后,查看目錄結(jié)構(gòu)
分析依賴樹
可以看出在調(diào)整conflict-lbywer和fetch順序后,目錄結(jié)構(gòu)并無變化。所以可得出結(jié)論,在一級(jí)node_modules不存在沖突包時(shí),會(huì)將高版本的包放在一級(jí)node_modules中。低版本的放到內(nèi)部的node_modules中。
一級(jí)node_modules有沖突包
如果一級(jí)node_modules有沖突包時(shí),情況又會(huì)如何呢?
刪除頂級(jí)依賴中的conflict-lbywer
{"dependencies":?{"fetch":?"^1.1.0"} }刪除node_modules和package-lock.json后,執(zhí)行npm i后,查看目錄結(jié)構(gòu)
分析依賴樹
頂級(jí)依賴添加conflict-lbywer@1.0.0
{"dependencies":?{"fetch":?"^1.1.0","conflict-lbywer":?"1.0.0"} }直接執(zhí)行npm i后,查看目錄結(jié)構(gòu)
分析依賴樹
可以發(fā)現(xiàn),在依賴樹無變化的情況下,node_modules的目錄結(jié)構(gòu)是不一樣的。所以可以得出結(jié)論,在一級(jí)node_moudles已經(jīng)存在依賴包的情況下,新安裝的依賴包如果存在沖突,會(huì)安裝到內(nèi)部的node_modules中。
四、存在package-lock.json
這種情況也很簡單,npm install會(huì)完全按照package-lock.josn的層級(jí)結(jié)構(gòu)下載安裝依賴包
刪除node_moudles后,執(zhí)行npm install
直接執(zhí)行npm install后,查看目錄結(jié)構(gòu)
分析依賴樹
可以發(fā)現(xiàn),在存在package-lock.json的情況下,node_modules的目錄結(jié)構(gòu)是穩(wěn)定的。
結(jié)語
上文對(duì)執(zhí)行npm install時(shí),一些常見的情況做了測試和分析,也給出了相應(yīng)的結(jié)論。歡迎讀者們批評(píng)斧正。也歡迎打賞點(diǎn)贊哦~
參考文獻(xiàn)和鏈接
https://docs.npmjs.com/cli/v7/commands/npm-install
https://docs.npmjs.com/cli/v7/configuring-npm/package-json
https://docs.npmjs.com/cli/v7/configuring-npm/folders
最近組建了一個(gè)江西人的前端交流群,如果你也是江西人可以加我微信 ruochuan12 拉你進(jìn)群。
今日話題
略。歡迎分享、收藏、點(diǎn)贊、在看我的公眾號(hào)文章~
一個(gè)愿景是幫助5年內(nèi)前端人走向前列的公眾號(hào)
可加我個(gè)人微信?ruochuan12,長期交流學(xué)習(xí)
推薦閱讀
我在阿里招前端,我該怎么幫你(可進(jìn)模擬面試群)
2年前端經(jīng)驗(yàn),做的項(xiàng)目沒技術(shù)含量,怎么辦?
點(diǎn)擊上方卡片關(guān)注我、加個(gè)星標(biāo)
·················?若川簡介?·················
你好,我是若川,畢業(yè)于江西高校。現(xiàn)在是一名前端開發(fā)“工程師”。寫有《學(xué)習(xí)源碼整體架構(gòu)系列》多篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會(huì)寫一篇年度總結(jié),已經(jīng)寫了7篇,點(diǎn)擊查看年度總結(jié)。
同時(shí),活躍在知乎@若川,掘金@若川。致力于分享前端開發(fā)經(jīng)驗(yàn),愿景:幫助5年內(nèi)前端人走向前列。
總結(jié)
以上是生活随笔為你收集整理的没想到你是这样的npm install的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Taro+react开发(8)--控制跳
- 下一篇: android 百度地图无法显示,And