file

最近由於我陸續在研究 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 資料夾底下的,於是我在該資料夾底下新增了 vue2vue3 兩個資料夾,裡面分別放了對應的測試程式、以及一個非常簡短的 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 討論 當中有很多例子,這裡就不贅述了。


分享此頁至:
最後修改日期: 2022/02/06

留言

撰寫回覆或留言

發佈留言必須填寫的電子郵件地址不會公開。您的留言可能會在審核之後才出現在頁面上。