插件的创作
可参考官网 插件 API 一节.
几个注意的点:
- 学习、调试、创作插件时,可以在项目中引入 vite-plugin-inspect 。
- 检查 Vite 插件的中间状态。
- 访问 localhost:5173/__inspect/ 检查项目的模块和栈信息。
- vite-plugin-inspect 文档 。
约定:
Rollup 插件:
如果插件不使用 Vite 特有的钩子,可以作为 兼容 Rollup 的插件 来实现,推荐使用 Rollup 插件名称约定。
- 前缀
rollup-plugin-+ 插件名称 package.json中包含rollup-plugin和vite-plugin关键字
Vite 专属插件:
- 前缀
vite-plugin-+ 插件名称 package.json中包含vite-plugin关键字- 插件文档中应该加上此插件为什么是一个
Vite专属插件的详细说明;(如,本插件用了哪些特有的插件钩子)。
插件只适用于特定的框架:
命名遵循格式:
vite-plugin-vue-前缀作为Vue插件vite-plugin-react-前缀作为React插件vite-plugin-svelte-前缀作为Sevlte插件
虚拟模块:
虚拟模块是 Vite 沿用 Rollup 的虚拟模块,虚拟模块相似 alias 别名,然而模块的内容并非间接从磁盘中读取,而是编译时生成。
虚拟模块是一种很实用的模式,使你能够对应用 ESM 语法的源文件传入一些编译时信息。
Demo:
创作了一个带虚拟模块的Vite插件 vite-plugin-my-plugin:
// 插件代码:vite-plugin-my-plugin.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)
特点:
- 虚拟模块以
virtual:为前缀 - 插件名应被用作命名空间,如:
vite-plugin-posts插件可以要求用户导入virtual:posts或者virtual:posts/helpers; 而不是virtual:posts和virtual:helpers一个插件中出现两个没有名称关联的虚拟模块的导入; - 使用了虚拟模块的插件在解析时应该将模块 ID 加上前缀
\0;避免其他插件尝试处理这个ID;
插件钩子
Vite & Rollup 通用钩子:
以下钩子在服务器启动时被调用:
options
buildStart
以下钩子会在每个传入模块请求时被调用:
resolveId
load
transform
以下钩子在服务器关闭时被调用:
buildEnd
closeBundle
更多钩子可参见:Rollup 构建钩子
Vite 独有钩子:
Vite 插件可以提供钩子来服务于特定的 Vite 目标。这些钩子会被 Rollup 忽略;
在解析 Vite 配置前调用。它可以返回一个将被深度合并到现有配置中的部分配置对象,或者直接改变配置(如果默认的合并不能达到预期的结果)。
config类型:
(config: userConfig, env: { mode: string, command: string }) => UserConfig | null | void
在解析 Vite 配置后调用。使用这个钩子读取和存储最终解析的配置。当插件需要根据运行的命令做一些不同的事情时,它也很有用。
configResolved类型:
(config: ResolvedConfig) => void | Promise
是用于配置开发服务器的钩子:
configureServer类型:
(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>
与 configureServer 相同但是作为预览服务器:
configPreviewServer
(server: { middlewares: Connect.Server, httpServer: http.Server }) => (() => void) | void | Promise<(() => void) | void>
转换 index.html 的专用钩子:
transformIndexHtml类型:
IndexHtmlTransformHook | { order?: 'pre' | 'post', handler: IndexHtmlTransformHook }
执行自定义 HMR 更新处理:
handleHotUpdate类型:
(ctx: HmrContext) => Array | void | Promise | void>
路径规范化
Vite 提供了工具函数 normalizePath做路径规范化处理;
Demo:
import { normalizePath } from 'vite'
normalizePath('foo\\bar') // 'foo/bar'
normalizePath('foo/bar') // 'foo/bar'
过滤 & include/exculde 模式:
Vite 暴露了 @rollup/pluginutils 的 createFilter 函数,以支持 Vite 独有插件和集成使用标准的 include/exclude 过滤模式
@rollup/pluginutilsRollup插件常用的一组实用函数。createFilter函数:- 结合
options.include和options.exclude, 进一步做过滤处理 - 参数:
(include?: <picomatch>, exclude?: <picomatch>, options?: Object) - 返回:
String
- 结合
Usage:
import { createFilter } from '@rollup/pluginutils';
export default function myPlugin(options = {}) {
// assume that the myPlugin accepts options of `options.include` and `options.exclude`
var filter = createFilter(options.include, options.exclude, {
resolve: '/my/base/dir'
});
return {
transform(code, id) {
if (!filter(id)) return;
// proceed with the transformation...
}
};
}
插件执行顺序:
Vite 插件可配置属性 enforce 来调整插件列表中插件的执行顺序;
以下是插件执行顺序:
- Alias
- 带有
enforce: 'pre'的用户插件 - Vite 核心插件
- 没有 enforce 值的用户插件
- Vite 构建用的插件
- 带有
enforce: 'post'的用户插件 - Vite 后置构建插件(最小化,manifest,报告)
情景应用:
默认情况下插件在开发(serve)和构建(build)模式中都会调用。如果插件只需要在预览或构建期间有条件地应用,请使用 apply 属性指明它们仅在 'build' 或 'serve' 模式时调用:
Usage:
// vite-plugin-my-plugin.js
function myPlugin() {
return {
name: 'build-only',
apply: 'build' // 或 'serve'
}
}
apply 也可以是个函数,用来做更精准的控制
// vite-plugin-my-plugin.js
function myPlugin() {
return {
name: 'build-only',
apply(config, { command }) {
// 非 SSR 情况下的 build
return command === 'build' && !config.build.ssr
}
}
}