你真的理解 devDependencies 和 dependencies 的區(qū)別嗎?
共 7939字,需瀏覽 16分鐘
·
2024-04-23 09:20
點(diǎn)擊上方 前端Q,關(guān)注公眾號(hào)
回復(fù)加群,加入前端Q技術(shù)交流群
作者:井柏然 原文:https://juejin.cn/post/7135795969370619918
你是否真的理解 devDependencies 和 dependencies 的區(qū)別?如果不能確切的回答、理解還停留在模糊的階段,那就接著往下看。筆者結(jié)合案例講解,保證一文就能讓大家清晰理解他們的區(qū)別。
筆者可以大膽的說(shuō):
devDependencies和dependencies簡(jiǎn)直就是自己最熟悉的陌生人了。對(duì)他們的理解一直都停留在表層,停留在百度、google里對(duì)他們區(qū)別的描述。以至于筆者一直都沒(méi)有深刻的理解和認(rèn)識(shí),所以經(jīng)常不知道裝包時(shí)什么應(yīng)該-D、-S,直到做了組件庫(kù)后,從實(shí)踐中理解了他們的區(qū)別... ...
本文的核心:理清 devDependencies 中的 dev ,到底指的是什么,搞清楚這個(gè) dev 的概念。如此一來(lái),devDependencies 和 dependencies 之間的區(qū)別就清晰可見(jiàn)了。
一、走出 “dev” 的誤區(qū)
關(guān)于 “devDependencies 和 dependencies 有什么區(qū)別?” 這樣的問(wèn)題,我們隨便百度、google一下都能出來(lái)很多個(gè)答案,其中最廣為流傳的說(shuō)法大概就是:“ devDependencies 是開(kāi)發(fā)環(huán)境下需要用到的依賴(lài), dependencies 是生產(chǎn)環(huán)境下需要用到的依賴(lài)” 這樣的話(huà)術(shù),這也就是很容易讓人走進(jìn)誤區(qū)的開(kāi)端。至于為什么這么說(shuō),我們接著往下看。
1. devDependencies 的 dev 理解誤區(qū)
存在即合理,即然這是個(gè)容易讓人產(chǎn)生誤區(qū)的話(huà)術(shù),為什么它是搜索引擎中最容易搜索到的答案呢?其實(shí),從某種角度來(lái)看,這個(gè)說(shuō)法并沒(méi)有什么毛病,只是很容易讓人走進(jìn)誤區(qū)。如果沒(méi)有實(shí)踐中體會(huì)過(guò)他們的區(qū)別,就很難真正的理解這句話(huà),這也是讓我們掉進(jìn)誤區(qū)的原因。
其中最大的誤區(qū)便是對(duì) “dev” 的理解。這么說(shuō)可能不夠清晰,筆者把它轉(zhuǎn)述成一個(gè)問(wèn)題:
-
安裝在 devDependencies中的依賴(lài),在項(xiàng)目執(zhí)行build的時(shí)候會(huì)不會(huì)被打包進(jìn) dist 產(chǎn)物中?
上面這個(gè)問(wèn)題其實(shí)很簡(jiǎn)單,大家不要掉到筆者這個(gè)提問(wèn)的坑里。我們從正常的項(xiàng)目打包流程分析(不管是 webpack 還是 vite,打包的核心步驟都類(lèi)似),這里從最簡(jiǎn)化的進(jìn)行分析,只為了針對(duì)上述問(wèn)題。
-
初始化配置 -
項(xiàng)目入口 -
依賴(lài)解析 -
loader處理 -
... ...
好了,看到這樣的打包流程(集中關(guān)注第2、3點(diǎn)),大家應(yīng)該也意識(shí)到一點(diǎn):項(xiàng)目打包跟 devDependencies 這個(gè)字段并沒(méi)什么關(guān)系。這樣一來(lái),上述問(wèn)題的答案也就很清晰了。只要是項(xiàng)目中用到的依賴(lài)(且安裝到 node_modules 中),不管這個(gè)依賴(lài)是放在 devDependencies 還是放在 dependencies ,都會(huì)被打包工具解析、構(gòu)建,最后都打進(jìn) dist 產(chǎn)物中。
總結(jié):生產(chǎn)打包 與 devDependencies 字段無(wú)關(guān)。devDependencies 中的 dev 并不是指我們 dev server 時(shí)候的 dev ,不能簡(jiǎn)單的把 dev 理解成當(dāng)前項(xiàng)目的 “開(kāi)發(fā)環(huán)境” 。接著往下,我們通過(guò)真實(shí)的裝包來(lái)驗(yàn)證一下這個(gè)結(jié)論。
2. 驗(yàn)證 devDependencies
為了加深大家對(duì)上述 “dev誤區(qū)” 的理解,筆者這里做一個(gè)小實(shí)驗(yàn)。
-
隨便用vue-cli生成一個(gè) vue2 項(xiàng)目,目錄如下。
-
當(dāng)前項(xiàng)目的依賴(lài)情況如下圖:
可以看到,目前的 vue 是放在
dependencies字段中。 -
install一下依賴(lài),然后到node_modules中找到 vue 的依賴(lài)包,并且找到對(duì)應(yīng)的入口文件。 -
在 vue.runtime.esm.js 中,加入一行代碼。看看打包后的情況如何。
-
執(zhí)行
build。并對(duì) dist 文件夾搜索。沒(méi)有意外,vue2 的包給打進(jìn)了該項(xiàng)目的 dist 包中。
大家對(duì)于上述的結(jié)果當(dāng)然不會(huì)感覺(jué)到有何不妥,那接下來(lái),筆者把 vue 的依賴(lài)信息移動(dòng)到 devDependencies 中,然后刪除掉之前的 node_modules 目錄后重新執(zhí)行 install ,結(jié)果如圖所示。
這時(shí),再重復(fù)上述步驟 3、4、5 ,對(duì) vue2 項(xiàng)目進(jìn)行打包,再去 dist目錄中搜索手動(dòng)添加到 vue2 源碼中的 console.log ,結(jié)果如圖所示。
結(jié)果就是,放在 devDependencies 的 vue2 在 build 時(shí)候(mode 為 production)依然會(huì)被打包進(jìn)單頁(yè)應(yīng)用的項(xiàng)目中。所以,通過(guò)這個(gè)實(shí)踐,就為了搞清楚一個(gè)點(diǎn),devDependencies 的 dev 并不是指我們?cè)跇I(yè)務(wù)項(xiàng)目開(kāi)發(fā)中的 dev 和 prod,它甚至跟打包時(shí)候的 mode 扯不上關(guān)系。
那他們到底的區(qū)別在哪里,為什么會(huì)存在這2個(gè)字段?我們接著往下看。
二、『npm包』的 devDependencies
這里提到了 npm包 ,敏感的同學(xué)可能就猜到 devDependencies 和 dependencies 的真正區(qū)別了。其實(shí) devDependencies 這個(gè)字段的 dev 的真正含義,更多是指 npm包 的開(kāi)發(fā)階段所需要的依賴(lài)。
1. npm 包的 dev
怎么理解前面提到的 npm包 開(kāi)發(fā)階段所需要的依賴(lài)?我們大概回憶一下npm包從 開(kāi)發(fā) - 發(fā)包 的流程。
-
npm初始化—— package.json。想要開(kāi)發(fā)一個(gè) npm包,最先一定是要進(jìn)行初始化,執(zhí)行命令npm init,然后填寫(xiě)一些信息比如 name 、 version 、 description ...此時(shí)便會(huì)生成一個(gè)pakcage.json文件。 -
npm包的開(kāi)發(fā)。這個(gè)階段,也就是對(duì) npm包 功能實(shí)現(xiàn)的階段,我們會(huì)開(kāi)始編寫(xiě)代碼。然而,我們?cè)诰帉?xiě)npm包的時(shí)候,可能需要用到其他的庫(kù),這個(gè)時(shí)候我們就需要去安裝其他的庫(kù)。 -
npm包的打包、發(fā)布。npm包開(kāi)發(fā)完成后,當(dāng)然就是要對(duì)我們的項(xiàng)目進(jìn)行打包,然后通過(guò) npm publish命令去發(fā)布我們的npm包。
整個(gè) npm包的實(shí)現(xiàn) 大概就是這么一個(gè)流程。其中第二點(diǎn),筆者提到了:如果開(kāi)發(fā)過(guò)程中需要用到其他的工具庫(kù),就要把依賴(lài)安裝到當(dāng)前項(xiàng)目里!這就涉及到本文的重點(diǎn)了,要怎么安裝呢?-D、還是-S?不同的命令會(huì)帶來(lái)怎么樣不同的后果呢?
現(xiàn)在,我門(mén)來(lái)通過(guò)一個(gè)具體案例開(kāi)探討這個(gè)問(wèn)題的答案。
場(chǎng)景描述:現(xiàn)在要開(kāi)發(fā)一個(gè)基于 element-plus 的二次封裝的組件庫(kù),所以在開(kāi)發(fā)調(diào)試階段,筆者需要安裝 vue3 、 element-plus ... 等等依賴(lài),以輔助我們開(kāi)發(fā)組件。
對(duì)比實(shí)驗(yàn):
-
將 vue3、element-plus都放在組件庫(kù)package.json的devDependencies中,然后將組件庫(kù)發(fā)包。最后,在業(yè)務(wù)項(xiàng)目中安裝該組件庫(kù),看依賴(lài)情況。 -
將 vue3放在組件庫(kù)package.json的devDependencies中,element-plus放在組件庫(kù)package.json的dependencies中,然后將組件庫(kù)發(fā)包。最后,在業(yè)務(wù)項(xiàng)目中安裝該組件庫(kù),看依賴(lài)情況。
2. 對(duì)比實(shí)驗(yàn)1
-
首先在業(yè)務(wù)項(xiàng)目中安裝組件庫(kù) vc-element-plus。依賴(lài)如下圖:
執(zhí)行安裝,操作如下:
image.png -
看下安裝的 vc-element-plus 內(nèi)部的依賴(lài)安裝情況。如圖:
回顧實(shí)驗(yàn)1條件:
"dependencies": {
"@element-plus/icons-vue": "^2.0.6",
"@xxx/vc-shared": "workspace:*",
"lodash": "^4.17.21"
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.3",
"element-plus": "^2.2.8",
"vue": "^3.2.36",
"vue-router": "4",
"less": "^4.1.3"
}
根據(jù)步驟2中的圖可以清晰看出,放在 dependencies 字段中的三個(gè)依賴(lài)包:@element-plus/icons-vue 、 @xxx/vc-shared 、 lodash 都被安裝到組件庫(kù)的 node_modules 中,而組件庫(kù)位于當(dāng)前的業(yè)務(wù)項(xiàng)目的 node_modules 中。換句話(huà)說(shuō),業(yè)務(wù)項(xiàng)目中擁有了組件庫(kù) dependencies 中的依賴(lài)包。
這里,筆者進(jìn)行猜想,實(shí)驗(yàn)2中,element-plus 將被裝到組件庫(kù)的內(nèi)部依賴(lài)中。緊接著,我們進(jìn)行實(shí)驗(yàn)2驗(yàn)證一下猜想。
3. 對(duì)比實(shí)驗(yàn)2
-
首先在業(yè)務(wù)項(xiàng)目中安裝組件庫(kù) vc-element-plus(版本號(hào)對(duì)比實(shí)驗(yàn)1已經(jīng)不同)。依賴(lài)如下圖:
同樣的,刪除node_module后進(jìn)行裝包,操作如下:
image.png -
看下安裝的 vc-element-plus 內(nèi)部的依賴(lài)安裝情況。如圖:
ok,這樣一對(duì)比,應(yīng)該就很清晰了。很明顯,實(shí)驗(yàn)2中安裝了4個(gè)依賴(lài),其中多出來(lái)的就是我們實(shí)驗(yàn)二中放進(jìn) dependencies 中 element-plus。(注意,@element-plus是圖標(biāo)那些的,跟element-plus不是同一個(gè)依賴(lài)源)。再次回顧 dependencies 字段驗(yàn)證一下:
"dependencies": {
"@element-plus/icons-vue": "^2.0.6",
"@xxx/vc-shared": "workspace:*",
"lodash": "^4.17.21",
"element-plus": "^2.2.8",
},
"devDependencies": {
"@vitejs/plugin-vue": "^2.3.3",
"vue": "^3.2.36",
"vue-router": "4",
"less": "^4.1.3"
}
到這里,大家應(yīng)該對(duì) devDependencies 和 dependencies 之間的區(qū)別有一個(gè)清晰的認(rèn)識(shí)了。至于項(xiàng)目裝包中什么時(shí)候使用 -D,什么時(shí)候使用 -S 也有自己的理解了~
4. 總結(jié) devDependencies 和 dependencies 的區(qū)別
結(jié)論:devDependencies 和 dependencies的區(qū)別核心體現(xiàn)在 npm包 中。只要開(kāi)發(fā)的項(xiàng)目是發(fā)npm包提供給外部、其他業(yè)務(wù)項(xiàng)目使用的,需要非常注意依賴(lài)的安裝地方,因?yàn)楦悴缓煤苋菀自跇I(yè)務(wù)使用中會(huì)出現(xiàn)bug。而如果只是自己項(xiàng)目用,不需要發(fā)npm包的話(huà),把依賴(lài)安裝到 devDependencies 或者 dependencies 中,實(shí)質(zhì)上是沒(méi)有任何區(qū)別的。
為什么在開(kāi)發(fā) npm包 的時(shí)候 不嚴(yán)格區(qū)分 devDependencies 、 dependencies 進(jìn)行裝包可能會(huì)導(dǎo)致業(yè)務(wù)項(xiàng)目的使用中出現(xiàn)bug呢?筆者舉一個(gè)例子來(lái)加深理解:
-
假設(shè)npm包開(kāi)發(fā)者不小心把 vue3 的依賴(lài)寫(xiě)到了 dependencies中(用于開(kāi)發(fā)調(diào)試的),版本是3.0.36。 -
業(yè)務(wù)項(xiàng)目自身用了 [email protected]的情況下,安裝了這個(gè) npm包 ,由于 npm包 中的dependencies有[email protected]這個(gè)依賴(lài),此時(shí)會(huì)在裝 npm包 的同時(shí)安裝36版本的vue。 -
由于 npm包中會(huì)用到vue,代碼是這樣引入的: import { onMount } from 'vue',此時(shí),npm包會(huì)在自己內(nèi)部的node_modules中找到[email protected]的包并使用,此時(shí)就會(huì)產(chǎn)生 2 個(gè) vue3 實(shí)例,就很容易出現(xiàn)一些奇怪的bug。(業(yè)務(wù)項(xiàng)目的[email protected]和 npm包的[email protected]) -
這里還要注意一點(diǎn)就是 externals。有同學(xué)可能會(huì)說(shuō),npm包打包的時(shí)候會(huì)externals掉第三方的庫(kù),比如上述中的 vue3 ,externals只是保證 vue3 的代碼不打包進(jìn) npm包 的代碼中而已。
經(jīng)過(guò)筆者上述的場(chǎng)景列舉,大家應(yīng)該都能get到,如果開(kāi)發(fā) npm包 中不嚴(yán)格區(qū)分 devDependencies 、 dependencies 的依賴(lài)安裝,可能會(huì)導(dǎo)致用戶(hù)處在使用 npm包 的時(shí)候出現(xiàn)問(wèn)題。所以,看完本文能清晰理解 devDependencies 和 dependencies 的區(qū)別了嗎
往期推薦
最后
歡迎加我微信,拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...
歡迎關(guān)注「前端Q」,認(rèn)真學(xué)前端,做個(gè)專(zhuān)業(yè)的技術(shù)人...
