辛宝Otto

辛宝Otto 的玄酒清谈

北漂前端程序员儿 / 探索新事物 / Web Worker 主播之一/内向话痨
xiaoyuzhou
email

【總結帖】深入淺出管理 uni-app 依賴的 uvm

【匯總貼】深入淺出管理 uni-app 依賴的 uvm
匯總貼:深入淺出管理 uni-app 依賴的 uvm

經驗分享的目標#

逛論壇發現有一些問題歸屬於@dcloudio/uvm ,問題相似,解答也相似,這裡做個匯總帖子,爭取能一次性解決常見問題。

本文目標是帶讀 uvm 源碼,熟悉和理解 uvm 設計思路和作用,並匯總常見問題,最終達到熟悉 uvm 源碼能自主解決問題的目的。

uvm 全稱是 uni-app version manager,可以類比 nvm - node version manager

背景介紹#

uvm 作為官方的解決方案,在官網文檔 https://uniapp.dcloud.net.cn/quickstart-cli.html#cliversion 有明顯提及:

可以使用  @dcloudio/uvm  管理編譯器的版本,此工具僅自動增加或更新 uni-app 編譯器主要依賴,對於新增的編譯命令(scripts)暫時不會自動處理,需手動參考新工程進行配置。

內部跳轉 [[uni-app 學習 #uni-app 依賴升級 uvm]]

作為一個高速迭代的技術框架,uni-app 和周邊生態每天都會開發編碼、修復問題。出了常規的前端方案,還需要同時支持 hbuilderX,陳舊版本的依賴是沒有意義的,是有最新版本對當前項目有明顯的意義。

通過一種方案,實現前端依賴自動升級就顯得有必要了,這個過程最好是一鍵升級,不需要關注當前的版本,和最新的版本具體是什麼。

因此 @dcloudio/uvm 就出現了,在項目目錄中執行 npx @dcloudio/uvm 就能實現 package.json 相關依賴的自動更新。

出於一些歷史原因,uvm 的項目源碼沒有放到公網展示,但 npm 的產物沒有走壓縮編譯,閱讀產物源碼和開發源碼效果一致,這裡簡單介紹下源碼和大致代碼結構。

項目源碼#

訪問 npm 倉庫 @dcloudio/uvm,點擊 Code 部分。可以看到最終的產物,和原始代碼沒什麼區別。https://www.npmjs.com/package/@dcloudio/uvm?activeTab=code

Pasted image 20231123175924

首先看 package.json 識別相關依賴和註冊命令。

package.json#

"dependencies": {
"cross-spawn": "^7.0.3",
"inquirer": "^8.2.0",
"minimist": "^1.2.5",
"node-fetch": "^2"
},
"devDependencies": {
"xmldom": "^0.6.0"
}

依賴比較簡單,跨平台執行命令,交互式 cli,請求發送。相關的,主要還是看 bin

命令註冊看 bin 註冊 bin/index.js,源碼如下,相對比較簡單和整齊。

Pasted image 20231122171157

通過閱讀源碼可以看到,當通過註冊命令啟動時候,會讀取當前 argv 參數,比如不傳的話默認填寫 latest,也會讀取當前命令行所代表的項目地址。

流程#

在截圖 line30 會執行 start(),會依次經歷 info() find()get(),最後是 merge()

info()#

info() 方法中,會讀取當前目錄的 package.json 去分析 devDependencies 依賴是否包含下面的依賴:

const plugins = {
  vue2: '@dcloudio/vue-cli-plugin-uni',
  vue3: '@dcloudio/vite-plugin-uni'
}

最終返回對應的依賴和是否 vue3,這意味著 vue2 和 vue3 要升級的依賴是不同的。這裡挖個坑,後面帶讀 @dcloudio/vite-plugin-uni 依賴的原理,感興趣請評論區告訴我。

find()#

定位到 /@dcloudio/uvm/lib/version.js#find

find 方法中,會讀取當前的 plugin 、和 具體版本特徵值或者 "latest" 、是否 vue3 進行傳遞判斷。

實際處理使用拿到當前的版本最後一段數字,去遠程拉數據,不外乎 latest alpha release 三個取值。獲取遠程的 version 值。比如 3.96.2023110403,這裡截圖打個斷點看看:

Pasted image 20231122173836

斷點進相關歷史判斷。

之後繼續請求 'https://registry.npmmirror.com/@dcloudio/vite-plugin-uni',還是各種特徵值判斷。

這裡會請求遠程數據,獲取 hbuilderX 版本信息,和 registry 信息。這裡是對網絡有要求。

Pasted image 20231123181106

這裡的 registry 默認是 cnpm ,這依賴 cnpm 的穩定性,有一定網絡波動的風險,但起碼能保證國內用戶能訪問通。

get()#

還會繼續判斷 get 方法,這裡以 vue3 的為例,最終回去獲取 https://gitee.com/dcloud/uni-preset-vue/blob/vite/package.json 的信息,也就是以遠程庫為基準進行處理。

為了兼容歷史版本的變更,這裡邏輯基本不可讀了,做了大量版本的兼容。在翻閱 ask 社區 uvm 問題時候,可以看到一些兼容的血淚史。

這裡如果是 vue3 會進入 getVue3(),這裡默認會讀取 gitee 的遠程倉庫信息。如果出於某種原因,github 和 gitee 倉庫沒有正確同步,就會導致信息不匹配。

merge()#

這一步驟是最後的執行階段。會拿到 deps ,準備具體執行。使用 spawnAsync 去分別更新依賴和開發者依賴。

這一塊使用 cross-spawn 繞過不同系統執行命令的問題。

技術總結#

通過上面簡單的核心邏輯帶讀,可以看到 uvm 執行的本質思路是跨系統執行命令,獲取當前版本信息和遠程 gitee 上典型倉庫的 package.json,進行 複雜 判斷,得出要升級的結果。

常見 QA#

運行報錯提示 Not find version xxx ,請提供具體版本號

這個目前已經沒有類似問題了,對一些歷史陳舊的版本可能存在一定問題,如果你遇到了請提供你當前的版本號。

運行報錯提示 code ETARGET

可能是緩存和網絡問題,嘗試刪除緩存和當前 node_modules ,嘗試重新安裝依賴。
也可能是網絡同步問題,發版之後同步到國內需要一定時間,可以休息一下等一等再嘗試。

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。