Hi Dai Gei Ho~ 我是Winnie ~
在昨天文章中我們簡單介紹 Vite 基本內容與設定後,在此篇文章中我們要來說說如何透過Vite實現開發熱更新。
事情是這樣的,由於 Extension 不像開發網站一樣有開發的運行環境可以測試使用,只能透過 開發人員模式上傳 測試的套件包 來運行,所以每當程式碼修改時,也就只能手動重整來更新測試套件是否正常,如果還使用 Vite 或其他打包工具來開發時,就會多出來一個動作,要額外再編譯程式碼。
咦,那什麼是熱更新 ?
熱更新 英文全名為 Hot Module Replacement,簡稱HMR,也就是說在開發時當程式碼修改時,能透過不刷新網頁的情況下,將修改的模組(Module)更新成新的內容,同時不會影響其他模組(Module)的運作。
但這邊要解釋下,雖然Vite也有自帶HMR,但因為在開發模式啟動的 devServer,在 Extension 開發中無法使用,所以在此篇文章所說的 熱更新 是我們要基於 Vite 的現有的設定功能 來自己簡單做一個 HMR。
而在這邊主要解決兩個問題:
我們先來看看第一個問題:
關於自動編譯的功能,在 Vite 有提供一個 vite build --watch
可以使用,只要在package.json
的 "scripts"
腳本中新增即可
注意: 這邊的 "build-watch" 可以自己定義名稱
{
"scripts": {
"dev": "vite", //dev模式
"build": "vite build", // 打包模式
"build-watch": "vite build--watch", // watch 打包模式
"preview": "vite preview" //預覽模式
}
}
當新增 build-watch 指令後, 我們可以透過 vite build-watch
來打包專案,此時就會進入watch
模式中,當需要編譯的檔案有修改時,就會即時編譯。
處理自動編譯的問題之後,接著我們來看看第二個問題
在 自動重整 更新Extension 前,首先我們要知道 Vite 何時打包完成,且通知當前套件自動重整。
整個流程大概切分三個步驟:
打包完成
→ dev server 通知 Extension 與 Browser
→ 執行重整更新
由於在 Vite 文件中 尚無提供關於 如何監聽編譯完成 的方法,所以在這邊我們只好透過 Rollup 提供的 Output Generation Hooks 來自定義 Vite Plugin , 實現 監聽編譯完成的事件。
Rollup 為 Vite 主要打包工具,是基於ES2015的JavaScript編譯工具,同時相較於其他打包工具,其能讓編譯過後的檔案容量更小、速度更快。
// build_watch.js
export default () => {
return {
name: "build_watch"
closeBundle() {
// 編譯結束時...
},
watchChange() {
//程式碼修改時...
},
closeWatcher() {
//關閉watch時...
}
}
}
接著要通知 Extension 與 Browser 重整,我們可以透過創建一個WebSocket
與頁面連接。
先安裝 WebSocket:
pnpm add -D ws
接著 透過 config 來判斷目前的指令是否為build-watch模式,如果是創建一個 WebSocket server 同時監聽連接事件。
// build_watch.js
...略
name: "build_watch",
config: (config, {
command
}) => {
//在 build 且 watch 下使用
const canUse = command === 'build' && Boolean(config.build.watch)
if (canUse) {
// 創建 WebSocket
wss = new WebSocketServer({ port: 2333 })
wss.on('connection', (client) => {
console.log('client:',client)
ws = client
})
}
}
...略
接著 使用 rollup 中 Output Generation Hooks 的 closeBundle()
寄送訊息通知頁面
import {
WebSocketServer,
WebSocket
} from 'ws'
let ws = WebSocket;
let wss = WebSocketServer;
let timer;
const send = (msg) => {
// 如果當前沒有 sw 就取消通知;
if (!ws) return
msg = JSON.stringify(msg)
//通知頁面
ws.send(msg)
}
export default () => {
return {
...略
closeBundle() {
timer = setTimeout(() => send('watch-build-ok'), 500)
},
watchChange() {
clearTimeout(timer);
},
closeWatcher() {
// 如果 ws & wss 就執行 .close()
ws && ws.close()
wss && wss.close()
clearTimeout(timer)
//清空 ws
ws = null;
wss = null;
timer = null;
}
}
}
這邊加入timer延遲的原因為 當程式碼多次修改時,第一次編譯完成會觸發 closeBundle
,馬上又會進行重新編譯,此時如果立刻通知其頁面更新,因為第二次編譯還沒完成,當編譯完成時就無法通知到對應的頁面 造成重新整理失敗。
所以需透過 closeBundle
hook 加入timer來延遲,同時在watchChange
hook來 重新計算時間。
import buildWatcher from './.vite/plugin/build_watch';
export default defineConfig({
plugins: [
buildWatcher()
]
})
判斷透過 環境變數 判斷當前是否為開發模式,如果是連接 WebSocket
,且監聽 onmessage 事件,如果為此訊息透過chrome.runtime.reload()
來重整套件。
//popup.js
if (import.meta.env.DEV) {
const ws = new WebSocket('ws://localhost:2333')
ws.onmessage = (event) => {
let msg = JSON.parse(event.data)
if (msg === 'watch-build-ok') {
chrome.runtime.reload()
}
}
}
這段程式碼最終在 vite build 模式下,會透過tree shaking 移除
以上就是關於 用Vite實現Extension開發熱更新的介紹,那今天文章先到這邊了,謝謝願意花時間看此篇文章的你,如果文章有錯誤的地方,再麻煩不吝嗇的給予指教,感謝!!
今日想推薦 -> 當我們一起走過