你真的理解 devDependencies 和 dependencies 的區(qū)別嗎?
作者:井柏然 原文:https://juejin.cn/post/7135795969370619918
你是否真的理解 devDependencies 和 dependencies 的區(qū)別?如果不能確切的回答、理解還停留在模糊的階段,那就接著往下看。筆者結(jié)合案例講解,保證一文就能讓大家清晰理解他們的區(qū)別。
筆者可以大膽的說:
devDependencies和dependencies簡直就是自己最熟悉的陌生人了。對他們的理解一直都停留在表層,停留在百度、google里對他們區(qū)別的描述。以至于筆者一直都沒有深刻的理解和認識,所以經(jīng)常不知道裝包時什么應該-D、-S,直到做了組件庫后,從實踐中理解了他們的區(qū)別... ...
本文的核心:理清 devDependencies 中的 dev ,到底指的是什么,搞清楚這個 dev 的概念。如此一來,devDependencies 和 dependencies 之間的區(qū)別就清晰可見了。
一、走出 “dev” 的誤區(qū)
關于 “devDependencies 和 dependencies 有什么區(qū)別?” 這樣的問題,我們隨便百度、google一下都能出來很多個答案,其中最廣為流傳的說法大概就是:“ devDependencies 是開發(fā)環(huán)境下需要用到的依賴, dependencies 是生產(chǎn)環(huán)境下需要用到的依賴” 這樣的話術,這也就是很容易讓人走進誤區(qū)的開端。至于為什么這么說,我們接著往下看。
1. devDependencies 的 dev 理解誤區(qū)
存在即合理,即然這是個容易讓人產(chǎn)生誤區(qū)的話術,為什么它是搜索引擎中最容易搜索到的答案呢?其實,從某種角度來看,這個說法并沒有什么毛病,只是很容易讓人走進誤區(qū)。如果沒有實踐中體會過他們的區(qū)別,就很難真正的理解這句話,這也是讓我們掉進誤區(qū)的原因。
其中最大的誤區(qū)便是對 “dev” 的理解。這么說可能不夠清晰,筆者把它轉(zhuǎn)述成一個問題:
- 安裝在
devDependencies中的依賴,在項目執(zhí)行build的時候會不會被打包進 dist 產(chǎn)物中?
上面這個問題其實很簡單,大家不要掉到筆者這個提問的坑里。我們從正常的項目打包流程分析(不管是 webpack 還是 vite,打包的核心步驟都類似),這里從最簡化的進行分析,只為了針對上述問題。
- 初始化配置
- 項目入口
- 依賴解析
- loader處理
- ... ...
好了,看到這樣的打包流程(集中關注第2、3點),大家應該也意識到一點:項目打包跟 devDependencies 這個字段并沒什么關系。這樣一來,上述問題的答案也就很清晰了。只要是項目中用到的依賴(且安裝到 node_modules 中),不管這個依賴是放在 devDependencies 還是放在 dependencies ,都會被打包工具解析、構(gòu)建,最后都打進 dist 產(chǎn)物中。
總結(jié):生產(chǎn)打包 與 devDependencies 字段無關。devDependencies 中的 dev 并不是指我們 dev server 時候的 dev ,不能簡單的把 dev 理解成當前項目的 “開發(fā)環(huán)境” 。接著往下,我們通過真實的裝包來驗證一下這個結(jié)論。
2. 驗證 devDependencies
為了加深大家對上述 “dev誤區(qū)” 的理解,筆者這里做一個小實驗。
-
隨便用vue-cli生成一個 vue2 項目,目錄如下。

-
當前項目的依賴情況如下圖:
可以看到,目前的 vue 是放在 dependencies字段中。 -
install一下依賴,然后到node_modules中找到 vue 的依賴包,并且找到對應的入口文件。
-
在 vue.runtime.esm.js 中,加入一行代碼??纯创虬蟮那闆r如何。

-
執(zhí)行
build。并對 dist 文件夾搜索。
沒有意外,vue2 的包給打進了該項目的 dist 包中。
大家對于上述的結(jié)果當然不會感覺到有何不妥,那接下來,筆者把 vue 的依賴信息移動到 devDependencies 中,然后刪除掉之前的 node_modules 目錄后重新執(zhí)行 install ,結(jié)果如圖所示。 

這時,再重復上述步驟 3、4、5 ,對 vue2 項目進行打包,再去 dist目錄中搜索手動添加到 vue2 源碼中的 console.log ,結(jié)果如圖所示。 
結(jié)果就是,放在 devDependencies 的 vue2 在 build 時候(mode 為 production)依然會被打包進單頁應用的項目中。所以,通過這個實踐,就為了搞清楚一個點,devDependencies 的 dev 并不是指我們在業(yè)務項目開發(fā)中的 dev 和 prod,它甚至跟打包時候的 mode 扯不上關系。
那他們到底的區(qū)別在哪里,為什么會存在這2個字段?我們接著往下看。
二、『npm包』的 devDependencies
這里提到了 npm包 ,敏感的同學可能就猜到 devDependencies 和 dependencies 的真正區(qū)別了。其實 devDependencies 這個字段的 dev 的真正含義,更多是指 npm包 的開發(fā)階段所需要的依賴。
1. npm 包的 dev
怎么理解前面提到的 npm包 開發(fā)階段所需要的依賴?我們大概回憶一下npm包從 開發(fā) - 發(fā)包 的流程。
- npm初始化——
package.json。想要開發(fā)一個 npm包,最先一定是要進行初始化,執(zhí)行命令npm init,然后填寫一些信息比如 name 、 version 、 description ...此時便會生成一個pakcage.json文件。 - npm包的開發(fā)。這個階段,也就是對 npm包 功能實現(xiàn)的階段,我們會開始編寫代碼。然而,我們在編寫npm包的時候,可能需要用到其他的庫,這個時候我們就需要去安裝其他的庫。
- npm包的打包、發(fā)布。npm包開發(fā)完成后,當然就是要對我們的項目進行打包,然后通過
npm publish命令去發(fā)布我們的npm包。
整個 npm包的實現(xiàn) 大概就是這么一個流程。其中第二點,筆者提到了:如果開發(fā)過程中需要用到其他的工具庫,就要把依賴安裝到當前項目里!這就涉及到本文的重點了,要怎么安裝呢?-D、還是-S?不同的命令會帶來怎么樣不同的后果呢?
現(xiàn)在,我門來通過一個具體案例開探討這個問題的答案。
場景描述:現(xiàn)在要開發(fā)一個基于 element-plus 的二次封裝的組件庫,所以在開發(fā)調(diào)試階段,筆者需要安裝 vue3 、 element-plus ... 等等依賴,以輔助我們開發(fā)組件。
對比實驗:
- 將
vue3、element-plus都放在組件庫package.json的devDependencies中,然后將組件庫發(fā)包。最后,在業(yè)務項目中安裝該組件庫,看依賴情況。
- 將
vue3放在組件庫package.json的devDependencies中,element-plus放在組件庫package.json的dependencies中,然后將組件庫發(fā)包。最后,在業(yè)務項目中安裝該組件庫,看依賴情況。
2. 對比實驗1
-
首先在業(yè)務項目中安裝組件庫 vc-element-plus。依賴如下圖:

執(zhí)行安裝,操作如下:
image.png -
看下安裝的 vc-element-plus 內(nèi)部的依賴安裝情況。如圖:

回顧實驗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 字段中的三個依賴包:@element-plus/icons-vue 、 @xxx/vc-shared 、 lodash 都被安裝到組件庫的 node_modules 中,而組件庫位于當前的業(yè)務項目的 node_modules 中。換句話說,業(yè)務項目中擁有了組件庫 dependencies 中的依賴包。
這里,筆者進行猜想,實驗2中,element-plus 將被裝到組件庫的內(nèi)部依賴中。緊接著,我們進行實驗2驗證一下猜想。
3. 對比實驗2
-
首先在業(yè)務項目中安裝組件庫 vc-element-plus(版本號對比實驗1已經(jīng)不同)。依賴如下圖:

同樣的,刪除node_module后進行裝包,操作如下:
image.png -
看下安裝的 vc-element-plus 內(nèi)部的依賴安裝情況。如圖:

ok,這樣一對比,應該就很清晰了。很明顯,實驗2中安裝了4個依賴,其中多出來的就是我們實驗二中放進 dependencies 中 element-plus。(注意,@element-plus是圖標那些的,跟element-plus不是同一個依賴源)。再次回顧 dependencies 字段驗證一下:
"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"
}
到這里,大家應該對 devDependencies 和 dependencies 之間的區(qū)別有一個清晰的認識了。至于項目裝包中什么時候使用 -D,什么時候使用 -S 也有自己的理解了~
4. 總結(jié) devDependencies 和 dependencies 的區(qū)別
結(jié)論:devDependencies 和 dependencies的區(qū)別核心體現(xiàn)在 npm包 中。只要開發(fā)的項目是發(fā)npm包提供給外部、其他業(yè)務項目使用的,需要非常注意依賴的安裝地方,因為搞不好很容易在業(yè)務使用中會出現(xiàn)bug。而如果只是自己項目用,不需要發(fā)npm包的話,把依賴安裝到 devDependencies 或者 dependencies 中,實質(zhì)上是沒有任何區(qū)別的。
為什么在開發(fā) npm包 的時候 不嚴格區(qū)分 devDependencies 、 dependencies 進行裝包可能會導致業(yè)務項目的使用中出現(xiàn)bug呢?筆者舉一個例子來加深理解:
- 假設npm包開發(fā)者不小心把 vue3 的依賴寫到了
dependencies中(用于開發(fā)調(diào)試的),版本是3.0.36。 - 業(yè)務項目自身用了
[email protected]的情況下,安裝了這個 npm包 ,由于 npm包 中的dependencies有[email protected]這個依賴,此時會在裝 npm包 的同時安裝36版本的vue。 - 由于 npm包中會用到vue,代碼是這樣引入的:
import { onMount } from 'vue',此時,npm包會在自己內(nèi)部的node_modules中找到[email protected]的包并使用,此時就會產(chǎn)生 2 個 vue3 實例,就很容易出現(xiàn)一些奇怪的bug。(業(yè)務項目的[email protected]和 npm包的[email protected]) - 這里還要注意一點就是
externals。有同學可能會說,npm包打包的時候會externals掉第三方的庫,比如上述中的 vue3 ,externals只是保證 vue3 的代碼不打包進 npm包 的代碼中而已。
經(jīng)過筆者上述的場景列舉,大家應該都能get到,如果開發(fā) npm包 中不嚴格區(qū)分 devDependencies 、 dependencies 的依賴安裝,可能會導致用戶處在使用 npm包 的時候出現(xiàn)問題。所以,看完本文能清晰理解 devDependencies 和 dependencies 的區(qū)別了嗎?
最后
如果你覺得這篇內(nèi)容對你挺有啟發(fā),我想邀請你幫我個小忙:
-
點個「喜歡」或「在看」,讓更多的人也能看到這篇內(nèi)容
-
我組建了個氛圍非常好的前端群,里面有很多前端小伙伴,歡迎加我微信「sherlocked_93」拉你加群,一起交流和學習
-
關注公眾號「前端下午茶」,持續(xù)為你推送精選好文,也可以加我為好友,隨時聊騷。
