3

輕前端筆記 - Vue3 SFC(.vue) 元件打包

 2 years ago
source link: https://blog.darkthread.net/blog/vue-cli-service-buile-vue3-sfc/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Vue3 SFC(.vue) 元件打包-黑暗執行緒

昨天分享透過 vue3-sfc-loader 載入 .vue 檔案的解決方案,讓輕前端也能輕鬆應用 SFC 元件實現氣刀體一致,但仍有美中不足之處。

首先,vue3-sfc-loader 的原理是把 Vue CLI 開發階段用的 SFC 編譯程式搬到瀏覽器端( vue3-sfc-loader.js = Webpack( @vue/compiler-sfc + @babel ) ),因此 vue3-sfc.loader.js 高達 1.37MB,以當代 JavaScript 力求輕薄的標準有點肥大。

第二,.vue 編譯動作將重複在每個瀏覽器每次載入執行一次(所以 vue3-sfc-loader 設計了簡單的 compiledCache 機制),不利網頁效能。

在我的想法裡,開發測試階段以簡單方便優先,上線時則需追求最佳化,才是良好的系統架構。於是我開始研究,有沒有不需要建立 Vue 專案,將單一 .vue 打包成 .js 的做法。

前後花了二十幾個小時爬文跟反覆實驗,大半個勞動節連假跟它拼到底,從中午搞到凌晨,睡沒幾小時想到點子又跳下床開始測試,用了點 Hakcing 手段,終於試出滿意的解法,興奮到尖叫。(好久沒有這麼熱血了)

身為前端菜鳥對 node.js 所知有限,研究到 Vue CLI 內部運作根本在「越級打怪」。幸好,靠著累積多年的實戰經驗及 Debug 技巧,終究還是讓我破解難題。

經過一番搜索,我先找到一個看似完美的 vue-cli-service build --target lib 指令。

以全域方式裝好 @vue/cli-service,只需要 vue-cli-service build --target lib '.\timer.vue',Vue CLI 會將 .vue 編譯成 .js 及 .css,還有一個 demo.html,展示在網頁載入 vue.js、timer.umd.js 及 timer.css,並建立 Vue Model 使用元件,這是標準的輕前端做法沒錯,好感動呀。(安裝及執行步驟可參考這篇)

dmeo.html 還可直接執行測試,驗證包出來的 js 跟 css 沒問題,很酷吧!

只是,我馬上發現問題,雖然元件可以動,但 demo.html 載入的是 //unpkg.com/vue@2,不是 Vue3。另一個線索是,必須要安裝 Vue2 專用的 vue-template-compiler 才能產生 .js,所以元件是被編譯成 Vue2 版本。

vue-cli-service 沒提供參數指定 Vue2 或 Vue3,我只能追進原始碼。結果讓我憂喜參半,好消息是 vue-cli-service 可同時支援 Vue2 跟 Vue3,壞消息是採用 Vue2 或 Vue3 是依專案環境自動判斷,單靠一個 .vue 檔無法判別。

再追到上游,cli-service 的 Vue 版本判斷由 @vue\cli-service\lib\util\getVueMajor.js 這段程式決定:

 * Get the major Vue version that the user project uses
 * @param {string} cwd the user project root
 * @returns {2|3}
 */
module.exports = function getVueMajor (cwd) {
  const vue = loadModule('vue', cwd)
  // TODO: make Vue 3 the default version
  const vueMajor = vue ? semver.major(vue.version) : 2
  return vueMajor
}

當只有單一 .vue 檔沒有專案相關檔案,取不到 vue 模組時將預設為 2。(有 TODO 註解,所以未來版本預設值將改為 3)

vue create hello 建立一個 Vue3 專案,把 .vue 擺進去,再執行 vue-cli-service build --target lib,確實就能判斷為 Vue3,但會變成找不到 vue/compiler-sfc 模組錯誤。

感覺問題出在 Vue CLI 版本更新速度偏慢,對 Vue3 元件編譯的支援還沒到位,故用起來種種不順,不像 Vue2 般行雲流水,理論再等一陣子就會改善。

如果你跟我一樣任性「不管,拎杯現在就要」,可參考以下我找到的 Workaround 解法:(註:包含非正規手法,請自行斟酌)

  1. 安裝 @vue/cli-service、@vue/compiler-sfc
    npm i -g @vue/cli-service
    npm i -g @vue/compiler-sfc
    
  2. 找到 C:\Users\使用者名稱\AppData\Roaming\npm\node_modules\@vue\cli-service\lib\util\getVueMajor.js,第 11 行原本為 2,改為 3,把 TODO 變成 JUST DO IT (假設該環境以 Vue3 為主)
      const vueMajor = vue ? semver.major(vue.version) : 3
    
  3. vue crate dummy 新建一個 Vue3 專案,找到其中的 node_modules\vue 資料夾

    將其複製到 C:\Users\使用者名稱\AppData\Roaming\npm\node_modules 目錄下

經過這番魔改,就能用 Vue CLI 將 .vue 快速轉成 js + css 了,開心!!

[2022-05-02 更新] 讀者 Shu Huan Huang 分享一招,在 .vue 所在目錄執行 npm i vue 產生 node_modules 目錄讓 vue-cli-service 將 .vue 視為 Vue3 版,取代第 2 步修改 getVueMajor.js 的動作,而第 3 步建立 Vue3 專案動作也可用 npm i vue 取代,取得 node_modules\vue。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK