本文首發公衆號「 前端從進階到入院」,歡迎關注!
在知乎看參與 Vue Conf 2021 是怎樣的體驗?這個問題的時候,偶然發現 Anthony Fu 的回答裏提到了一個好玩的凡爾賽插件:vite-plugin-sleep。html
先看看回答中 Anthony Fu 是怎麼引出這個插件的:前端
關於 QA 環節中對於 Vite 快的意義的提問彷佛引起了你們的一些討論,藉此機會說說本身的淺見。
咱們有兩個詞,UX 和 DX,分別對應用戶體驗(User Experience)和開發者體驗(Developer Experience)。webpack的確某種程度上,做爲開發者咱們應該優先知足於終端用戶的體驗,可是隨着開發者數量的增長,以及軟件需求的愈加複雜,開發者一樣做爲人的體驗也十分重要。git
若是開發者不能得到很好的 DX,便很難有足夠好的效率去進行 UX 的改善。而性能的提高能夠更好的讓機器接受人的命令而不是浪費時間在等待機器完成工做。github
固然,若是你是以爲工具太快影響休息的話,這裏安利一下 @小炫 的插件,讓你的 Vite 也休息一下 vite-plugin-sleep(被你發現了,其實抖這個機靈纔是個人目的)web
這充滿凡爾賽氣息的話語屬實逗笑我了,Webpack 的構建之慢確實帶給了咱們一些美好的摸魚時間,Vite 是奪走它們的罪魁禍首,這纔是屬於打工人的插件!面試
先看看 vite-plugin-sleep 的「動機」章節:shell
In the old days with webpack, we had many times when we could compile with pay, and with vite it was so
fast that we couldn't rest.
Time to take a nap in the vite.
在 Webpack 陪伴的那些日子裏,咱們在編譯的時候有不少的時間能夠用來休息,但 Vite 太快了,奪走了這一切。json
是時候小睡一會了……api
yarn add vite-plugin-sleep
// vite.config.ts import sleep from "vite-plugin-sleep"; /** @see {@link https://vitejs.dev/config/} */ export default defineConfig({ plugins: [ // ...other plugins sleep(/* options */), ], });
就這麼簡單,安裝而後引入,屬於你的摸魚時間又回來了。
看看這個插件的源碼是什麼樣的,順便學習一下 Vite 插件的編寫方式。
Vite 插件的通用形式通常是個函數,接受用戶傳入的一個 options 配置選項,返回 Vite 標準的插件格式,一個形如這樣的對象:
{ name: 'vite-plugin-sleep', config() { // 自定義 config 邏輯 } load() { // 自定義 load 邏輯 }, }
Vite 暴露了不少鉤子函數給用戶,讓用戶在適當的時機對源碼內部的行爲進行一些介入和更改。
在官網的 插件 API —— 鉤子 章節閱讀文檔,注意有一部分鉤子是繼承自 Rollup 的,因此須要去 Rollup 的官網來查看使用說明。
以官網中提到的例子來解釋:
export default function myPlugin() { const virtualFileId = "@my-virtual-file"; return { name: "my-plugin", // 必須的,將會顯示在 warning 和 error 中 resolveId(id) { if (id === virtualFileId) { return virtualFileId; } }, load(id) { if (id === virtualFileId) { return `export const msg = "from virtual file"`; } }, }; }
這個插件容許用戶引入一個虛擬文件(在實際文件中不存在),經過 load
鉤子來自定義讀取文件的內容,用戶就能夠這樣引入 "from virtual file"
這個字符串了。
import { msg } from "@my-virtual-file"; console.log(msg);
有了這些前置知識,咱們來看下這個插件是怎麼寫的:
import type { Plugin } from "vite"; import type { UserOptions } from "./lib/options"; import { sleep } from "./lib/utils"; import { name } from "../package.json"; export default function sleepPlugin(userOptions: UserOptions = {}): Plugin { const options = { ...userOptions, }; let firstStart = true; return { name, enforce: "pre", configureServer(server) { server.middlewares.use(async (req, __, next) => { // if not html, next it. // @ts-expect-error if (!req.url.endsWith(".html") && req.url !== "/") { return next(); } if (firstStart) { await sleep(options.devServerStartDelay || 20000); firstStart = false; } next(); }); }, async load() { await sleep(options.hmrDelay || 2000); return null; }, }; }
其實很簡單,configureServer
鉤子是 Vite 官方提供的獨有鉤子(也就是 Rollup 中不存在的鉤子),是用於配置開發服務器的鉤子,最多見的用例是添加一些自定義服務中間件。
而 load
鉤子則是 Rollup
內置的,根據官網的說法,return null
表明這個文件交給其餘插件或者由默認解析行爲處理,也就是延遲兩秒後啥都不幹。
再回到插件的內容,先定義一個睡覺的函數:
export function sleep(delay: number) { return new Promise((resolve) => setTimeout(resolve, delay)); }
配合 await 語法,能夠實現很是優雅的睡眠。
經過 enforce: 'pre'
來強制這個插件的鉤子在最前面執行(其餘插件別想阻止我摸魚)。
configureServer
這個鉤子裏的代碼也很簡單,初次啓動 Vite 開發服務器的時候,訪問入口 HTML 文件時,sleep
沉睡用戶傳入的時間,默認 20 秒。(20 秒夠幹嗎?XD,請設置成 120 秒。)
官方給出的例子就是添加中間件,但尤老闆萬萬沒想到中間這段註釋代碼被摸魚小能手填充以後,竟是用來作這種事!
以後是 load
鉤子,讀取每一個文件的時候,默認沉睡 2 秒。
就這麼簡單,一個 Vite 摸魚插件完成了。
週末了,經過這個凡爾賽的插件圖個樂子,順便學習一下 Vite 插件的基礎知識,美滋滋!
歡迎關注 ssh,前端潮流趨勢、原創面試熱點文章應有盡有。
記得關注後加我好友,我會不按期分享前端知識,行業信息。2021 陪你一塊兒度過。