最近由於我陸續在研究 Vue 3,也考慮了增加我的 Shrewd 框架對 Vue 3 的支援。為了確保串接上正確無誤、尤其又因為 Vue 3 跟 Vue 2 的差異真的很大,把測試程式寫好寫滿真的是不可或缺的。不過這個時候就遇到一個小問題了:我要怎樣同時在我的專案裡面安裝 Vue 2 和 Vue 3、以便我的測試程式可以兩邊都有測到?
內容目錄
NPM 別名
要把同一個套件安裝兩種不同的版本,其中一個方法就是用 NPM 別名(alias),這是一個從 NPM 6.9 開始支援的功能。簡單來說就是用類似下面的語法來進行套件的安裝:
npm install vue2@npm:vue
npm install vue3@npm:vue@next
如此一來的話,就會把 vue
(Vue 2)安裝成 vue2
這個名稱、而把 vue@next
(Vue 3)安裝成 vue3
這個名稱。引用的時候,根據引用的是 vue2
還是 vue3
即可切換不同的版本。
然而,為了要寫測試程式,我所需要的不是只有 Vue 而已,而還需要另一個套件 @vue/test-utils
。這個套件也有區分對應的 Vue 版本,其中 @vue/test-utils@1
是給 Vue 2 用的,而 @vue/test-utils@2
是給 Vue 3 用的。由於 @vue/test-utils
當然會去呼叫 vue
的功能,此時用 NPM 別名就行不通了,因為即使我把 vue
跟 @vue/test-utils
各安裝了兩種版本並且取了別名,後者在引用的時候引的仍然是叫做 vue
、而不會是我取的別名,所以它根本就抓不到正確的相依套件。
用資料夾區分
經過實驗之後,我發現這種情境之下的理想解決方法應該是直接用資料夾來區分兩大套版本的相依套件。在我的專案中,測試程式是位於 test/specs
資料夾底下的,於是我在該資料夾底下新增了 vue2
和 vue3
兩個資料夾,裡面分別放了對應的測試程式、以及一個非常簡短的 package.json
,內容分別如下:
// vue2/package.json
{
"devDependencies": {
"@vue/test-utils": "^1.3.0",
"vue": "^2.6.14"
}
}
// vue3/package.json
{
"devDependencies": {
"@vue/test-utils": "^2.0.0-rc.18",
"vue": "^3.2.27"
}
}
然後我分別在這兩個資料夾當中執行 npm install
,就會在這兩個資料夾裡面分別建立自己的 node_modules
資料夾和 package-lock.json
、並且把套件裝好。如此一來,在這兩個資料夾當中的測試程式雖然引用的都是叫做 vue
跟 @vue/test-utils
,但是因為它們自帶有不同的 node_modules
,Node.js 在解析套件名稱的時候會去抓最靠近的 node_modules
中的對應套件,如此一來兩邊的測試程式就可以互相不干擾地正確執行了。
自動執行子資料夾中的套件安裝
但是這個時候我注意到了一個問題。假設改天我在別的環境底下把我的專案 git clone 下來,然後我在專案的根目錄當中執行 npm install
的話,會把子資料夾中的 package.json
所指定的套件也安裝上去嗎?不會的。因為 NPM 並不會意識到那些 package.json
的存在。長遠來說這似乎是有一點麻煩的事情。
幸好這不是個很難解決的問題。我們可以藉由定義 NPM 的 postinstall
這個週期指令來讓 NPM 在執行安裝的時候順便做任何一些我們指定的事情。假設我們很清楚子資料夾的結構的話,可以在根目錄中的 package.json
中加上如下的東西就行了:
{
...
"scripts": {
...
"install:vue2": "cd test/specs/vue2 && npm install || exit 0",
"install:vue3": "cd test/specs/vue3 && npm install || exit 0",
"postinstall": "npm run install:vue2 && npm run install:vue3"
}
...
}
值得留意的是,postinstall
這個腳本在兩個時間點上都會觸發:一個是當我們把這個專案本身 clone 下來之後執行 npm install
的時候,另一個是在這個專案發布成為 NPM 套件之後、有人把這個套件安裝在他的專案中、成為相依套件的時候。當然,我並不希望在第二種情況中執行這個安裝腳本,不過這無妨:注意到我在後面寫上了 || exit 0
,而由於 test
資料夾當然沒有跟著一起發布到 NPM 上頭去,一旦腳本執行到 cd test/specs/vue2
這一段發生錯誤(因為找不到資料夾)時就會跳到 exit 0
正常結束腳本了。
而如果子資料夾的結構經常變動或者數量很多的話,這樣的寫法就不切實際了,但是也可以自己寫一個 script 去爬資料夾結構、並且只要看到 package.json
檔案就去執行安裝。這類的 script 在 這一篇 StackOverflow 討論 當中有很多例子,這裡就不贅述了。
留言