本节内容基于Vite插件API。
vite
的插件机制是基于 Rollup
生态的。也就是说大多数兼容情况下,Rollup
插件能够直接用于 vite
工程中。
您可以查看完整的Rollup插件文档。
定义与使用
一个插件的简单定义与使用方式如下:
// myPlugin.js
const fileRegex = /\.(my-file-ext)$/
export default function myPlugin() {
return {
name: 'transform-file',
transform(src, id) {
if (fileRegex.test(id)) {
return {
code: compileFileToJS(src),
map: null // 如果可行将提供 source map
}
}
}
}
}
// vite.config.js
import { defineConfig } from 'vite'
import myPlugin from 'myPlugin.js'
export default defineConfig({
plugins: [myPlugin()]
})
通用钩子
正如上文所述,vite
插件机制是基于 Rollup
的。因此二者具有一些通用钩子。
以下钩子在服务器启动时被调用:
options
buildStart
以下钩子会在每个传入模块请求时被调用:
resolveId
load
transform
以下钩子在服务器关闭时被调用:
buildEnd
closeBundle
TIP
请注意 moduleParsed
钩子在开发中是不会被调用的,因为 Vite
为了性能会避免完整的 AST
解析。
特殊钩子
Vite
在通用钩子的基础上,自定义一些内置钩子供开发者使用。这类特殊钩子,会被 Rollup
忽略。
config
- 类型:
(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void
该钩子在解析 Vite
配置前调用。
钩子接收原始用户配置(命令行选项指定的会与配置文件合并)和一个描述配置环境的变量,包含正在使用的 mode
和 command
。
它可以返回一个将被深度合并到现有配置中的部分配置对象,或者直接改变配置(如果默认的合并不能达到预期的结果)。
// 返回部分配置(推荐)
const partialConfigPlugin = () => ({
name: 'return-partial',
config: () => ({
resolve: {
alias: {
foo: 'bar'
}
}
})
})
// 直接改变配置(应仅在合并不起作用时使用)
const mutateConfigPlugin = () => ({
name: 'mutate-config',
config(config, { command }) {
if (command === 'build') {
config.root = 'foo'
}
}
})
configResolved
- 类型:
(config: ResolvedConfig) => void | Promise<void>
在解析 Vite
配置后调用。
使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它也很有用。
const examplePlugin = () => {
let config
return {
name: 'read-config',
configResolved(resolvedConfig) {
// 存储最终解析的配置
config = resolvedConfig
},
// 在其他钩子中使用存储的配置
transform(code, id) {
if (config.command === 'serve') {
// dev: 由开发服务器调用的插件
} else {
// build: 由 Rollup 调用的插件
}
}
}
}
configureServer
- 类型:
(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>
该钩子可用于配置开发服务器。
const myPlugin = () => ({
name: 'configure-server',
configureServer(server) {
server.middlewares.use((req, res, next) => {
// 自定义请求处理...
})
}
})
存储服务器实例,供其他钩子使用:
const myPlugin = () => {
let server
return {
name: 'configure-server',
configureServer(_server) {
server = _server
},
transform(code, id) {
if (server) {
// 使用 server...
}
}
}
}
configurePreviewServer
- 类型:
(server: { middlewares: Connect.Server, httpServer: http.Server }) => (() => void) | void | Promise<(() => void) | void>
该钩子可用于配置预览服务器。
const myPlugin = () => ({
name: 'configure-preview-server',
configurePreviewServer(server) {
// 返回一个钩子,会在其他中间件安装完成后调用
return () => {
server.middlewares.use((req, res, next) => {
// 自定义处理请求 ...
})
}
}
})
transformIndexHtml
- 类型:
IndexHtmlTransformHook | { enforce?: 'pre' | 'post', transform: IndexHtmlTransformHook }
该钩子可用于转换 index.html
。
const htmlPlugin = () => {
return {
name: 'html-transform',
transformIndexHtml(html) {
return html.replace(
/<title>(.*?)<\/title>/,
`<title>Title replaced!</title>`
)
}
}
}
handleHotUpdate
- 类型:
(ctx: HmrContext) => Array<ModuleNode> | void | Promise<Array<ModuleNode> | void>
该钩子执行自定义 HMR
更新处理。
// 插件注册钩子
handleHotUpdate({ server }) {
server.ws.send({
type: 'custom',
event: 'special-update',
data: {}
})
return []
}
// 客户端处理监听
if (import.meta.hot) {
import.meta.hot.on('special-update', (data) => {
// 执行自定义更新
})
}
插件顺序
Vite
插件支持配置 enforce
属性来自定义执行顺序。完整的执行顺序如下:
Alias
- 带有
enforce: 'pre'
的用户插件 Vite
核心插件- 没有
enforce
值的用户插件 Vite
构建用的插件- 带有
enforce: 'post'
的用户插件 Vite
后置构建插件(最小化,manifest
,报告)
插件场景
默认情况下插件在开发(serve
)和构建(build
)模式中都会调用。
如果插件只需要在预览或构建期间有条件地应用,可以使用 apply
属性指明仅在 'build'
或 'serve'
模式时调用。
function myPlugin() {
return {
name: 'build-only',
apply: 'build' // 或 'serve'
}
}
虚拟模块
Vite
插件中支持定义虚拟模块。
在插件中定义虚拟模块:
// myPlugin.js
export default function myPlugin() {
const virtualModuleId = 'virtual:my-module'
const resolvedVirtualModuleId = '\0' + virtualModuleId
return {
name: 'my-plugin', // 必须的,将会在 warning 和 error 中显示
resolveId(id) {
if (id === virtualModuleId) {
return resolvedVirtualModuleId
}
},
load(id) {
if (id === resolvedVirtualModuleId) {
return `export const msg = "from virtual module"`
}
}
}
}
然后就可以在代码中引入虚拟模块:
// main.js
import { msg } from 'virtual:my-module'
console.log(msg)