Vite 插件也可以提供鉤子來服務(wù)于特定的 Vite 目標(biāo)。這些鉤子會(huì)被 Rollup 忽略
(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void
?async
?, ?sequential
?在解析 Vite 配置前調(diào)用。鉤子接收原始用戶配置(命令行選項(xiàng)指定的會(huì)與配置文件合并)和一個(gè)描述配置環(huán)境的變量,包含正在使用的 mode
和 command
。它可以返回一個(gè)將被深度合并到現(xiàn)有配置中的部分配置對(duì)象,或者直接改變配置(如果默認(rèn)的合并不能達(dá)到預(yù)期的結(jié)果)。
示例:
// 返回部分配置(推薦)
const partialConfigPlugin = () => ({
name: 'return-partial',
config: () => ({
alias: {
foo: 'bar'
}
})
})
// 直接改變配置(應(yīng)僅在合并不起作用時(shí)使用)
const mutateConfigPlugin = () => ({
name: 'mutate-config',
config(config, { command }) {
if (command === 'build') {
config.root = __dirname
}
}
})
注意:
用戶插件在運(yùn)行這個(gè)鉤子之前會(huì)被解析,因此在 config
鉤子中注入其他插件不會(huì)有任何效果。
(config: ResolvedConfig) => void | Promise<void>
?async
?, ?parallel
?在解析 Vite 配置后調(diào)用。使用這個(gè)鉤子讀取和存儲(chǔ)最終解析的配置。當(dāng)插件需要根據(jù)運(yùn)行的命令做一些不同的事情時(shí),它也很有用。
示例:
const exmaplePlugin = () => {
let config
return {
name: 'read-config',
configResolved(resolvedConfig) {
// 存儲(chǔ)最終解析的配置
config = resolvedConfig
},
// 在其他鉤子中使用存儲(chǔ)的配置
transform(code, id) {
if (config.command === 'serve') {
// dev: 由開發(fā)服務(wù)器調(diào)用的插件
} else {
// build: 由 Rollup 調(diào)用的插件
}
}
}
}
注意,在開發(fā)環(huán)境下,command
的值為 serve
(在 CLI 中,vite
和 vite dev
是 vite serve
的別名)。
(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>
?async
?, ?sequential
?是用于配置開發(fā)服務(wù)器的鉤子。最常見的用例是在內(nèi)部 connect 應(yīng)用程序中添加自定義中間件:
const myPlugin = () => ({
name: 'configure-server',
configureServer(server) {
server.middlewares.use((req, res, next) => {
// 自定義請(qǐng)求處理...
})
}
})
configureServer
鉤子將在內(nèi)部中間件被安裝前調(diào)用,所以自定義的中間件將會(huì)默認(rèn)會(huì)比內(nèi)部中間件早運(yùn)行。如果你想注入一個(gè)在內(nèi)部中間件之后運(yùn)行的中間件,你可以從 configureServer
返回一個(gè)函數(shù),將會(huì)在內(nèi)部中間件安裝后被調(diào)用:
const myPlugin = () => ({
name: 'configure-server',
configureServer(server) {
// 返回一個(gè)在內(nèi)部中間件安裝后
// 被調(diào)用的后置鉤子
return () => {
server.middlewares.use((req, res, next) => {
// 自定義請(qǐng)求處理...
})
}
}
})
在某些情況下,其他插件鉤子可能需要訪問開發(fā)服務(wù)器實(shí)例(例如訪問 websocket 服務(wù)器、文件系統(tǒng)監(jiān)視程序或模塊圖)。這個(gè)鉤子也可以用來存儲(chǔ)服務(wù)器實(shí)例以供其他鉤子訪問:
const myPlugin = () => {
let server
return {
name: 'configure-server',
configureServer(_server) {
server = _server
},
transform(code, id) {
if (server) {
// 使用 server...
}
}
}
}
注意 configureServer
在運(yùn)行生產(chǎn)版本時(shí)不會(huì)被調(diào)用,所以其他鉤子需要防范它缺失。
IndexHtmlTransformHook | { enforce?: 'pre' | 'post', transform: IndexHtmlTransformHook }
?async
?, ?sequential
?轉(zhuǎn)換 ?index.html
? 的專用鉤子。鉤子接收當(dāng)前的 HTML 字符串和轉(zhuǎn)換上下文。上下文在開發(fā)期間暴露?ViteDevServer
?實(shí)例,在構(gòu)建期間暴露 Rollup 輸出的包。
這個(gè)鉤子可以是異步的,并且可以返回以下其中之一:
{ tag, attrs, children }
?)。每個(gè)標(biāo)簽也可以指定它應(yīng)該被注入到哪里(默認(rèn)是在 ?<head>
? 之前){ html, tags }
? 的對(duì)象基礎(chǔ)示例:
const htmlPlugin = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return html.replace(
/<title>(.*?)<\/title>/,
`<title>Title replaced!</title>`
)
}
}
}
完整鉤子簽名:
type IndexHtmlTransformHook = (
html: string,
ctx: {
path: string
filename: string
server?: ViteDevServer
bundle?: import('rollup').OutputBundle
chunk?: import('rollup').OutputChunk
}
) =>
| IndexHtmlTransformResult
| void
| Promise<IndexHtmlTransformResult | void>
type IndexHtmlTransformResult =
| string
| HtmlTagDescriptor[]
| {
html: string
tags: HtmlTagDescriptor[]
}
interface HtmlTagDescriptor {
tag: string
attrs?: Record<string, string>
children?: string | HtmlTagDescriptor[]
/**
* 默認(rèn): 'head-prepend'
*/
injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend'
}
類型: ?(ctx: HmrContext) => Array<ModuleNode> | void | Promise<Array<ModuleNode> | void>
?
執(zhí)行自定義 HMR 更新處理。鉤子接收一個(gè)帶有以下簽名的上下文對(duì)象:
interface HmrContext {
file: string
timestamp: number
modules: Array<ModuleNode>
read: () => string | Promise<string>
server: ViteDevServer
}
modules
?是受更改文件影響的模塊數(shù)組。它是一個(gè)數(shù)組,因?yàn)閱蝹€(gè)文件可能映射到多個(gè)服務(wù)模塊(例如 Vue 單文件組件)。read
?這是一個(gè)異步讀函數(shù),它返回文件的內(nèi)容。之所以這樣做,是因?yàn)樵谀承┫到y(tǒng)上,文件更改的回調(diào)函數(shù)可能會(huì)在編輯器完成文件更新之前過快地觸發(fā),并 ?fs.readFile
? 直接會(huì)返回空內(nèi)容。傳入的 ?read
?函數(shù)規(guī)范了這種行為。鉤子可以選擇:
handleHotUpdate({ server }) {
server.ws.send({
type: 'custom',
event: 'special-update',
data: {}
})
return []
}
客戶端代碼應(yīng)該使用 ?HMR API
? 注冊(cè)相應(yīng)的處理器(這應(yīng)該被相同插件的 transform
鉤子注入):
if (import.meta.hot) {
import.meta.hot.on('special-update', (data) => {
// 執(zhí)行自定義更新
})
}
更多建議: