因?yàn)槭褂肞eerDependencies而引發(fā)的bug
前言
前幾天有個(gè)人跟我反饋說,她fork了我右鍵菜單那個(gè)開源項(xiàng)目,一直無法打包成功。我尋思著應(yīng)該不可能吧,當(dāng)我嘗試打包時(shí),果然翻車了??。
經(jīng)過了一番調(diào)試后,終于找到了問題所在,本文就跟大家分享下這個(gè)問題從發(fā)現(xiàn)到解決的整個(gè)過程,歡迎各位感興趣的開發(fā)者閱讀本文。
排查問題
因?yàn)槲译娔X重裝過幾次系統(tǒng),一些放在github上的項(xiàng)目我就沒有備份,我把項(xiàng)目(https://github.com/likaia/vue-right-click-menu-next/)重新clone到本地,安裝依賴項(xiàng)后運(yùn)行了build命令,意想不到的事情發(fā)生了:它報(bào)錯(cuò)了??
- ERROR Failed to compile with 4 errors 11:02:26 AM
- error in ./src/components/right-menu.vue
- Module parse failed: Unexpected token (1:0)
- File was processed with these loaders:
- * ./node_modules/eslint-loader/index.js
- You may need an additional loader to handle the result of these loaders.
上述報(bào)錯(cuò)的意思是找不到處理vue文件的相關(guān)loader,我就納悶了,這不可能啊,幾個(gè)月前插件寫好時(shí)還能打包的,現(xiàn)在咋就突然不能打包了呢。
可能是node版本的問題
難道是我node版本的問題?插件寫好到現(xiàn)在代碼一直沒動(dòng)過,唯一變化的就是我升級(jí)了node版本,降級(jí)node版本太麻煩,于是我安裝了node版本管理工具n。
因?yàn)槲业南到y(tǒng)是macos,我可以直接用brew來安裝它,命令如下:
- brew install n
如果你是windows系統(tǒng),你可以通過npm包的形式來安裝它,命令如下:
- npm install -g n
安裝完成后,我去找了下我寫這個(gè)項(xiàng)目時(shí)所發(fā)布的node版本v14.14.0,我們用n工具來安裝并切換它:
- n 14.14.0
我們運(yùn)行node --version命令看下是否成功。
一切準(zhǔn)備就緒,我尋思著應(yīng)該不會(huì)出現(xiàn)問題了吧??,結(jié)果運(yùn)行后,我傻眼了,仍然報(bào)著同樣的錯(cuò)誤??
node版本管理工具有挺多的,除了文中說的n還有nvm、npx,感興趣的開發(fā)者可自行了解。
發(fā)現(xiàn)貓膩(yarn.lock)
當(dāng)我一籌莫展發(fā)呆時(shí),突然發(fā)現(xiàn)目錄樹中的yarn.lock變色了,看來是有改動(dòng)了,我尋思著不可能啊,我沒動(dòng)package.json中的依賴項(xiàng)啊,怎么會(huì)發(fā)生變化呢?
重新創(chuàng)建個(gè)項(xiàng)目試試
既然lock文件發(fā)生了變化,那我重新創(chuàng)建個(gè)項(xiàng)目試試,把相關(guān)依賴項(xiàng)拷過去再打包看看。
我們繼續(xù)使用Vue CLI作為插件搭建環(huán)境,對(duì)此不熟悉的開發(fā)者請(qǐng)移步我的另一篇文章:使用CLI開發(fā)一個(gè)Vue3的npm庫
- vue create test-vue3-project
項(xiàng)目創(chuàng)建完成后,我把相關(guān)文件拷貝了過去,修改了package.json中的build命令。
- {
- "build": "vue-cli-service build --target lib --name vueRightMenuPlugin src/main.ts"
- }
運(yùn)行命令后,它居然打包成功了??
找到問題
經(jīng)過前面的一番折騰,創(chuàng)建了一個(gè)新的項(xiàng)目他就好了,那我比對(duì)下這倆項(xiàng)目有啥不同之處,那么問題就迎刃而解了。
經(jīng)過比對(duì)后,我發(fā)現(xiàn)了package.json中的不同之處:
- "dependencies": {
- "core-js": "^3.6.5",
- "vue": "^3.0.0"
- }
- "peerDependencies": {
- "core-js": "^3.6.5",
- "vue": "^3.0.0"
- }
區(qū)別就在于,vue和core-js這兩個(gè)包的位置,問題應(yīng)該就出在這里了。
我們來驗(yàn)證下吧,將dependencies中的那兩個(gè)包放到peerDependencies中,重新install下,再build看下。
不出意料,果然報(bào)錯(cuò)了。
那么為啥我的項(xiàng)目之前能跑,現(xiàn)在卻沒法跑了,我想應(yīng)該是因?yàn)橹案牧撕?,我沒有重新install的緣故吧??。
解決問題
那么,既然找到問題了,我們反過來,把右鍵菜單的peerDependencies下的兩個(gè)包放到dependencies下,再看看問題能否得到解決。
當(dāng)我滿懷信心的執(zhí)行build命令后,結(jié)局卻讓我很失望。
是的,他換了個(gè)錯(cuò)誤??
image-20210912132222990
看報(bào)錯(cuò)是類型無法自動(dòng)推導(dǎo),這就很怪異了。那么就只能嘗試下我的三板斧了:
- 重啟軟件
- 重啟電腦
- 刪除項(xiàng)目,重新clone,重新install依賴
前兩個(gè)嘗試過后,發(fā)現(xiàn)并無卵用,只好用了最后一個(gè)方法。
重新install后,執(zhí)行了build命令,成功解決了這個(gè)問題。
為什么呢
問題是解決了,那么為什么要那樣做呢?接下來就帶大家深入研究下dependencies和peerDependencies。
dependencies
dependencies是package.json中的一個(gè)屬性,里面放運(yùn)行代碼時(shí)所需的依賴,在install時(shí)這些包會(huì)被安裝,打包項(xiàng)目時(shí),這里面的包也會(huì)被打包進(jìn)去。
peerDependencies
peerDependencies也是package.json中的一個(gè)屬性,這個(gè)單詞翻譯過來是對(duì)等依賴的意思,這里面的包在install時(shí)并不會(huì)安裝,打包項(xiàng)目時(shí),這里面的包也不會(huì)被打包進(jìn)去。
兩者存在的問題
如果將依賴包放在dependencies下,那么當(dāng)別人在他的項(xiàng)目中引入你的插件時(shí),會(huì)出現(xiàn)下述情況:
- 他項(xiàng)目里沒有引入你所需的依賴包,那么你插件所依賴的包會(huì)被安裝
- 他項(xiàng)目里引入了你所需的依賴包:
- 版本號(hào)一致,那么你所需的依賴包不會(huì)被安裝,插件將共用項(xiàng)目里的依賴包
- 版本號(hào)不一致,那么你所需的依賴包就會(huì)被安裝,項(xiàng)目里就存在了兩套不同版本的依賴
版本號(hào)一致那還好,萬事大吉。版本號(hào)不一致時(shí),你插件所依賴的那個(gè)包需要的功能與調(diào)用者項(xiàng)目里安裝的那個(gè)版本的包并無區(qū)別,那么調(diào)用者的項(xiàng)目將變得臃腫起來,又多安裝了一份依賴。
如果將依賴包放在peerDependencies下,對(duì)插件開發(fā)者是不友好的,會(huì)出現(xiàn)下述問題:
- install的時(shí)候,所需的依賴不會(huì)安裝,使用ide開發(fā)時(shí)會(huì)報(bào)錯(cuò)找不到相關(guān)依賴。
- build的時(shí)候,因?yàn)橐蕾囄窗惭b,導(dǎo)致無法打包(文章開頭提到的報(bào)錯(cuò))
這么看的話,peerDependencies這個(gè)屬性,好像沒啥用了。當(dāng)然存在即合理,如果大家有什么更好的看法,歡迎在評(píng)論區(qū)留言討論。
解決方案
知道他們各自的優(yōu)點(diǎn)和缺點(diǎn)后,我也就知道了如何解決這個(gè)問題。
既然dependencies中的依賴包只要和調(diào)用者的版本號(hào)一致,就不需要重新安裝依賴,那我們把它的版本號(hào)放開,給個(gè)范圍,這樣不就可以了??
在package.json中的版本號(hào)可以帶下述符號(hào):
- ~波浪號(hào),匹配最新補(bǔ)丁版本號(hào),即版本號(hào)的第三個(gè)數(shù)字,例如~3.0.0就會(huì)匹配3.0.x版本,將在3.1.0停止
- ^插入符號(hào),匹配次要的版本號(hào),即版本號(hào)的第二個(gè)數(shù)字,例如^3.0.0就會(huì)匹配任何3.x.x版本,將在4.0.0停止
- >、<、>=、<=比較運(yùn)算符,匹配的就是這個(gè)區(qū)間的版本,例如>3.0.0 <= 3.1.4,就會(huì)匹配這個(gè)區(qū)間的版本號(hào)
如果不帶符號(hào),那么它就是精確匹配。
本文中,用的是^3.0.0,滿足了我們插件的使用場景,因此不需要更改。