從0開始寫一個簡單的vite hmr 插件( 二 )

2.5 如何讓typescript支持導入這個模塊?回到之前,我們不是說vite插件中transform能夠豐富資源的導入,
但是這不代表typescript就認可,不認可依然不能提供完備的補全和檢查,
所以為了讓typescript徹底服氣,就需要在vite-env.d.ts中寫一段模塊解析的配置
// vite-env.d.tsdeclare module '*.todo' {export const data: string;export function parser(content: string);}這里定義了一個模塊,并導出了兩個成員
一個叫data, 是string類型的資源
一個叫parser,是個解析函數(稍后會介紹)
這樣寫了之后,typescript就會默認我們能夠導入.todo 后綴的文件,并且這里面有兩個成員,一個是data,一個是parser 。
3. todo插件編寫O 吃飯X 喝水O 跑步五公里這樣一種文本,O表示未完成 , X表示完成,后面表示當前todo的信息
3.1 todo插件在plugins中創建一個todoParser.ts
export default function todoParser(): Plugin {let todoFileRegex = /\.(todo)$/;// 解析.todo 的正則return {name: "todo-parser",transformIndexHtml(html) {return html.replace(/<title>(.*?)<\/title>/, '<title>TODO Parser</title>');},async transform(src, id) {// module injectconsole.log(id);// 看看當前文件是否通過了正則,如果通過了,就執行if (todoFileRegex.test(id)) {return {// 這里的parser是解析器,稍后會說code: `export let data = "https://www.huyubaike.com/biancheng/${parser(src)}"export ${parser}`};}}}}相信閱讀了前面有關vite插件的介紹應該不難理解
3.2 parser為了能夠解析.todo文件,并且輸出我們希望的內容,
還需要提供解析一個解析器來解析 。
// todoParser.tsfunction parser(src: string) {// 解析const lines = src.split('\n');let todoList = "";let finishRegex = /^X/;let readyRegex = /^O/;let content = /\s(.*)$/let randomId: string;for (let line of lines) {randomId = Math.random().toString(32).slice(2);let html: string;if (finishRegex.test(line)) {console.log(line);html = `<li><input type='checkbox' checked id='${randomId}'/><label for='${randomId}'>${line.trim().match(content)![1]}</li>`console.log("通過",html);} else if (readyRegex.test(line)) {html = `<li><input type='checkbox' id='${randomId}'/><label for='${randomId}'>${line.trim().match(content)![1]}</li>`console.log("拒絕",html);}todoList += html!;}return todoList;}我們這里通過正則獲取了每一行數據中表示狀態的 OX, 以及其內容,并且封裝為一組checkbox
這些文本信息可以直接插入html以顯示其內容
3.3 插件的裝載import { defineConfig } from "vite";import todoParser from './plugins/todoParser';export default defineConfig({plugins: [todoParser()],assetsInclude: ["src/**/*.todo"]})回到vite.config.ts中,在plugins數組內部直接執行todoParser(),實現插件的裝載
在main.ts 中接收這個導入的資源 , 并且賦值到document中
import { data } from './assets/journey.todo'import './style.css'; // 樣式,這里消除了li的一般樣式 list-style: noneconsole.log(data);document.body.innerHTML = data;

從0開始寫一個簡單的vite hmr 插件

文章插圖
  • 上面的預覽圖可以發現我們實現了功能,但是每次一寫完 , 整個頁面就會全部刷新,這可不太好,所以還需要HMR
4. HMR 實現
從0開始寫一個簡單的vite hmr 插件

文章插圖
注意,vite中server和client是可以相互通信!這里只需要server向client發送消息
4.1 server 發送vite服務器實例的獲取有很多種方法:
  1. 直接通過vite鉤子 configureServer(server) {}獲取
    一般用來給vite服務器添加中間件
  2. 通過處理更新的鉤子獲取 handleHotUpdate({file, server, modules}){}
這里我們要實現的是熱更新,所以采用handleHotUpdate就可以了,在模塊更新的時候,就會觸發這個函數,通過server向client發送更新的消息,以及更新的數據 , 然后讓瀏覽器在未刷新的情況下直接更新
async handleHotUpdate({ server, file, modules }) {let fileData = https://www.huyubaike.com/biancheng/await fs.readFile(modules[0].id as string);server.ws.send({type:'custom',event: 'special-update', // 事件名data: {msg: "Update from server",updateVal: fileData.toString()}})console.log(`${file} should be updated`);return [];}通過node的fs模塊讀取到了文本的數據
隨后通過server.ws.send()向client發送的數據,其中更新之后的數據存放在data.updateVal中
4.2 client 獲取在vite中,模塊熱更新以事件的形式拋出,具體來說是

推薦閱讀