vite 插件钩子详解
vite 开发模式下插件的生命周期钩子执行顺序
其中 Vite
会调用一系列与 Rollup
兼容的钩子,这个钩子主要分为三个阶段:
-
服务器启动阶段:
options
和buildStart
钩子会在服务启动时被调用 -
请求响应阶段: 当浏览器发起请求时,
Vite
内部依次调用resolveId
、load
和transform
钩子 -
服务器关闭阶段:
Vite
会依次执行buildEnd
和closeBundle
钩子。
除了以上钩子,其他 Rollup
插件钩子(如 moduleParsed
、renderChunk
)均不会在 Vite
开发阶段调用。而生产环境下,由于 Vite
直接使用 Rollup
,Vite
插件中所有 Rollup
的插件钩子都会生效。
执行顺序

-
服务启动阶段:
config
(Vite
独有)、configResolved
(Vite
独有)、options
、configureServer
(Vite
独有)、buildStart
-
请求响应阶段: 如果是
html
文件,仅执行transformIndexHtml
钩子;对于非HTML
文件,则依次执行resolveId
、load
和transform
钩子 -
热更新阶段: 执行
handleHotUpdate
钩子。 -
服务关闭阶段: 依次执行
buildEnd
和closeBundle
钩子
vite 插件各个钩子
config
Vite
在读取完配置文件(即 vite.config.ts
)之后,会拿到用户导出的配置对象,然后执行 config
钩子。在这个钩子里面,你可以对配置文件导出的对象进行自定义的操作,如下代码所示:
// 返回部分配置(推荐)
const editConfigPlugin = () => ({
name: 'vite-plugin-modify-config',
config: () => ({
alias: {
react: require.resolve('react')
}
})
})
官方推荐的姿势是在 config
钩子中返回一个配置对象,这个配置对象会和 Vite
已有的配置进行深度的合并。
configResolved
Vite
在解析完配置之后会调用 configResolved
钩子,这个钩子一般用来记录最终的配置信息,而不建议再修改配置,用法如下图所示:
const exmaplePlugin = () => {
let config
return {
name: 'read-config',
configResolved(resolvedConfig) {
// 记录最终配置
config = resolvedConfig
},
// 在其他钩子中可以访问到配置
transform(code, id) {
console.log(config)
}
}
}
options
替换或操作传递给 rollup.rollup
的选项对象。返回 null
不会替换任何内容。如果只需要读取选项,则建议使用 buildStart
钩子,因为该钩子可以访问所有 options
钩子的转换考虑后的选项。
configureServer
这个钩子仅在开发阶段会被调用,用于扩展 Vite
的 Dev Server
,一般用于增加自定义 server
中间件,如下代码所示:
const myPlugin = () => ({
name: 'configure-server',
configureServer(server) {
// 姿势 1: 在 Vite 内置中间件之前执行
server.middlewares.use((req, res, next) => {
// 自定义请求处理逻辑
})
// 姿势 2: 在 Vite 内置中间件之后执行
return () => {
server.middlewares.use((req, res, next) => {
// 自定义请求处理逻辑
})
}
}
})
buildStart
在每个 rollup.rollup
构建上调用。当你需要访问传递给 rollup.rollup()
的选项时,建议使用此钩子,因为它考虑了所有 options
钩子的转换,并且还包含未设置选项的正确默认值。
resolveId
在 Vite 插件系统中,resolveId
是一个非常重要的钩子,用于解决模块的 ID(即模块的路径)。当 Vite 在构建或开发过程中遇到一个导入时,它会调用 resolveId
钩子来解析该模块的实际路径。resolveId
钩子允许插件控制如何找到和处理这些模块。
resolveId 钩子的作用
resolveId
的主要作用是:
-
解析模块路径:Vite 通过
resolveId
钩子将模块的相对路径或模块别名转换为实际的文件路径或 URL。 -
自定义模块解析:如果你需要处理一些自定义的导入路径(例如,模块别名、虚拟模块等),可以通过
resolveId
来实现。 -
支持虚拟模块:虚拟模块是不存在于文件系统中的模块,通常用于通过 Vite 插件生成或修改内容。
resolveId
可以将这些虚拟模块映射到相应的文件或内容。 -
自定义解析逻辑:你可以在
resolveId
中编写自定义的模块解析逻辑,以实现更复杂的行为(例如,处理某些特殊的导入路径,或覆盖默认的解析规则)。
resolveId 的执行时机
resolveId
会在每次模块导入时执行,通常是在 Vite 解析源文件的过程中触发。当 Vite 遇到一个模块的导入语句时,它会调用插件链中的每个插件的 resolveId
钩子,直到找到一个返回非 null
值的插件为止。
resolveId
钩子会在以下几种场景下触发:
-
解析 JavaScript、TypeScript、CSS、JSON 等模块的导入。
-
解析组件库、插件中的虚拟模块或文件。
-
解析带有路径别名的导入(如
@/foo
)。 -
解析扩展名不标准的导入(如
.vue
、.ts
)。
resolveId 钩子的参数
resolveId
钩子接收以下参数:
-
source (string): 导入语句中的模块路径(即 import 'source' 中的 'source' 部分)。这是插件需要解析的模块路径。
-
importer (string | undefined): 导入当前模块的文件路径。也就是引发当前导入语句的文件路径。如果当前模块是顶级模块(没有其他模块导入它),该值为 undefined。
-
isEntry (boolean): 是否是入口文件的导入。如果是入口文件的导入,Vite 会尝试将该模块作为程序的入口。
-
ssr (boolean): 是否处于 SSR(服务器端渲染)模式。如果为 true,表示当前是 SSR 环境。
resolveId 的返回值
resolveId
必须返回以下几种值之一:
-
null: 如果插件无法解析该模块路径,则返回 null。这表示模块将交给下一个插件或默认解析方式处理。
-
字符串: 如果插件能够解析该模块路径,则返回解析后的路径(例如,绝对路径或相对路径)。返回的路径将作为模块的最终路径使用。
-
false: 返回 false 表示这个模块不再继续尝试解析。
-
对象(可选):可以返回一个包含 id 属性的对象,id 是解析后的路径。可以用于返回更多的元数据。
示例:使用 resolveId 自定义模块解析
以下是一个简单的插件示例,展示了如何在 Vite 中使用 resolveId
钩子自定义模块解析。
import { Plugin } from 'vite';
export default function aliasPlugin(): Plugin {
return {
name: 'alias-plugin',
resolveId(source) {
// 如果是以 "@/components" 开头的模块路径,则解析为自定义路径
if (source.startsWith('@/components')) {
const resolvedPath = source.replace('@', '/src/components');
return resolvedPath;
}
// 对于其他模块,返回 null,交给下一个插件处理
return null;
}
};
}
-
在此示例中,resolveId 钩子会拦截所有以 @/components 开头的导入路径,并将其转换为 /src/components 目录下的路径。
-
如果模块路径不符合自定义规则,则返回 null,让 Vite 或其他插件继续处理该路径。
import { Plugin } from 'vite';
export default function virtualModulePlugin(): Plugin {
return {
name: 'virtual-module-plugin',
resolveId(source) {
// 如果导入的是虚拟模块 "virtual-module",返回一个自定义路径
if (source === 'virtual-module') {
return 'virtual:/my-virtual-module.js';
}
return null; // 其他路径交给 Vite 默认的解析处理
},
load(id) {
// 当 Vite 请求虚拟模块时,提供该模块的内容
if (id === 'virtual:/my-virtual-module.js') {
return `export default 'This is a virtual module.';`;
}
return null;
}
};
}
-
在 resolveId 中,我们拦截了对 virtual-module 模块的请求,并返回了一个虚拟模块的路径 virtual:/my-virtual-module.js。
-
在 load 钩子中,我们处理了该虚拟模块,并返回了它的内容。
import { Plugin } from 'vite';
import path from 'path';
export default function customFileTypePlugin(): Plugin {
return {
name: 'custom-file-type-plugin',
resolveId(source) {
// 假设我们自定义支持 `.txt` 文件的导入
if (source.endsWith('.txt')) {
const resolvedPath = path.resolve(__dirname, 'assets', source);
return resolvedPath;
}
return null;
},
load(id) {
// 读取文本文件内容
if (id.endsWith('.txt')) {
return `export default ${JSON.stringify('This is a text file.')};`;
}
return null;
}
};
}
-
resolveId 解析以
.txt
结尾的文件,并返回该文件的绝对路径。 -
在 load 中返回该文本文件的内容。
load
在 Vite 插件系统中,load 钩子用于在模块加载阶段处理和修改文件内容。它是插件对 Vite 构建过程中的一个重要环节,允许你在文件内容被传递给其他部分(如转译、打包等)之前,进行处理、修改、优化或者生成内容。
load 钩子的作用
load 钩子的主要作用是:
-
修改文件内容:你可以在此钩子中修改模块的源代码,例如进行内容转换、代码注入等操作。
-
处理虚拟模块:如果你在 resolveId 中创建了虚拟模块,load 钩子允许你返回该虚拟模块的内容。
-
自定义文件处理逻辑:你可以根据文件类型、路径等条件对文件进行特殊处理,如对
.txt
文件进行加载,或者对某些模块进行特殊的转换。
load 钩子的执行时机
load 钩子会在 Vite 的构建过程中被触发,它发生在模块被解析之后(resolveId 之后),但是在它被传递给转译器(如 Babel、TypeScript)和打包器(如 Rollup)之前。具体来说,load 会在以下几种情况下触发:
-
当模块被请求时(例如,导入一个模块)。
-
当模块的路径已经解析并且准备加载时。
-
在加载虚拟模块时,Vite 会调用 load 钩子来提供虚拟模块的内容。
load 钩子的参数
load 钩子接收以下参数:
-
id (string): 请求的模块路径,通常是文件路径或者虚拟模块的路径。这个路径由 resolveId 解析出来。
-
ssr (boolean): 当前是否处于 SSR(服务器端渲染)模式。如果是 SSR 环境,插件可以返回不同的模块内容或执行特定的操作。
load 的返回值
load 钩子必须返回以下值之一:
-
string: 返回模块的源代码。返回的字符串会被 Vite 后续的处理流程使用。
-
null: 如果当前模块无法被处理或修改,返回 null,表示该模块交给后续的插件或默认流程继续处理。
-
Promise<string | null>: 如果 load 是一个异步函数,它可以返回一个 Promise,Promise 解析的值必须是 string 或 null。
-
{ code: string, map?: object }: 除了代码内容,load 还可以返回一个对象,其中包含 code(源代码)和 map(source map)。如果有 source map,Vite 会将它与代码一起传递给后续处理。
示例:使用 load 钩子
import { Plugin } from 'vite';
export default function virtualModulePlugin(): Plugin {
return {
name: 'virtual-module-plugin',
resolveId(source) {
if (source === 'virtual-module') {
return 'virtual:/my-virtual-module.js';
}
return null;
},
load(id) {
if (id === 'virtual:/my-virtual-module.js') {
// 返回虚拟模块的内容
return `export default 'This is a virtual module.';`;
}
return null;
}
};
}
-
resolveId 钩子拦截了 virtual-module 模块,并将其解析为 virtual:/my-virtual-module.js。
-
在 load 中,我们提供了该虚拟模块的内容:export default 'This is a virtual module.'。
import { Plugin } from 'vite';
import path from 'path';
import fs from 'fs';
export default function textFilePlugin(): Plugin {
return {
name: 'text-file-plugin',
resolveId(source) {
// 如果是以 .txt 结尾的路径,则进行自定义解析
if (source.endsWith('.txt')) {
return path.resolve(__dirname, 'src', source);
}
return null;
},
load(id) {
// 如果是自定义解析的 .txt 文件,读取文件内容并返回
if (id.endsWith('.txt')) {
const content = fs.readFileSync(id, 'utf-8');
return `export default ${JSON.stringify(content)};`;
}
return null;
}
};
}
-
resolveId 解析 .txt 文件,并返回它的绝对路径。
-
load 读取 .txt 文件的内容,并将其作为一个字符串导出。
import { Plugin } from 'vite';
export default function modifyJSPlugin(): Plugin {
return {
name: 'modify-js-plugin',
load(id) {
// 如果是 JavaScript 文件,可以对其进行修改
if (id.endsWith('.js')) {
return `console.log('This is modified by the plugin');\n` + fs.readFileSync(id, 'utf-8');
}
return null;
}
};
}
-
load 钩子会拦截所有 .js 文件,并在文件内容的开头插入一行日志:console.log('This is modified by the plugin');
import { Plugin } from 'vite';
export default function jsWithSourceMapPlugin(): Plugin {
return {
name: 'js-with-source-map-plugin',
load(id) {
if (id.endsWith('.js')) {
const code = `console.log('Modified JS');`;
const map = {
version: 3,
file: id,
sources: [id],
names: [],
mappings: 'AAAA'
};
return { code, map };
}
return null;
}
};
}
-
load 返回了一个包含 code 和 map 的对象,code 是修改后的代码,map 是对应的 source map。
-
这使得 Vite 在构建时能够正确地映射修改后的代码到源文件,方便调试和错误追踪。
transform
在 Vite 插件系统中,transform 钩子是用于处理和转换模块代码的关键钩子。它是在构建过程中,模块的源代码被传递给 Vite 的打包工具(如 Rollup)之前执行的。这一钩子让你能够对模块进行转换、注入代码、压缩或者执行其他类似的操作。
transform 钩子的作用
transform 钩子的主要作用是:
-
修改文件内容:对 JavaScript、TypeScript、CSS 等文件内容进行转换。
-
支持其他编译器:可以用于将某些语言(如 TypeScript、SASS、SCSS 等)编译成浏览器可以理解的 JavaScript 或 CSS。
-
代码注入:允许你在文件中插入额外的代码,或者动态修改文件的内容。
transform 钩子的执行时机
transform 钩子在模块加载并且 Vite 开始对其进行转换时触发。它会在模块内容被解析并经过 load 钩子处理之后触发,但在最终交给打包工具(如 Rollup)处理之前执行。也就是说,transform 钩子是 Vite 执行 JavaScript/TypeScript、CSS 以及其他资源转换的地方。
-
transform 是针对模块内容的逐个转换,通常用于对每个文件的源代码进行转换。
-
transform 主要针对的是源文件的内容,尤其是 JavaScript、TypeScript、CSS 等文件,它允许你在这些文件中进行代码的修改和注入。
transform 钩子的参数
transform 钩子接收以下参数:
-
code (string): 当前模块的源代码,通常是文件内容的字符串。这个参数代表了文件的源代码,可以在 transform 中修改这个内容。
-
id (string): 请求的模块路径,通常是文件路径或虚拟模块的路径。这个路径是 Vite 用来解析该模块的标识。
-
options (object): 这个对象包含了 Vite 当前构建的配置选项。你可以根据这些选项来调整 transform 的行为(如是否启用 sourceMap,是否开启 esbuild 转换等)。
-
ssr (boolean): 当前是否处于 SSR(服务器端渲染)模式。可以用来区分客户端和服务器端的转换需求。如果是 SSR 模式,可能会有不同的代码转换需求。
transform 的返回值
transform 必须返回以下之一:
-
string: 变换后的代码内容。这个字符串将会作为新的模块代码,传递给后续的插件或构建步骤。
-
null: 如果当前模块不需要处理,或者没有做任何变换,返回 null。这意味着插件不处理该文件,交给下一个插件或默认流程继续处理。
-
{ code: string, map?: object }: 除了修改后的 code 外,transform 还可以返回一个对象,该对象包含:
-
code: 转换后的代码内容。
-
map (可选): 对应的 source map。map 是一个对象,表示源代码到转换后代码之间的映射。如果你提供了 map,Vite 会在构建时自动生成正确的 source map。
-
-
Promise<string | null> 或 Promise<{ code: string, map?: object }>: 如果 transform 是一个异步函数,它应该返回一个 Promise,Promise 的解析值可以是上述三种情况之一。
示例:使用 transform 钩子
import { Plugin } from 'vite';
export default function jsTransformPlugin(): Plugin {
return {
name: 'js-transform-plugin',
transform(code, id) {
if (id.endsWith('.js')) {
// 在所有 JavaScript 文件的顶部插入一行代码
const transformedCode = `console.log('Transformed by js-transform-plugin');\n` + code;
return transformedCode;
}
return null;
}
};
}
-
该插件会在所有
.js
文件的顶部插入一行代码 console.log('Transformed by js-transform-plugin');。 -
transform
钩子会返回修改后的代码内容。
import { Plugin } from 'vite';
export default function tsTransformPlugin(): Plugin {
return {
name: 'ts-transform-plugin',
transform(code, id) {
if (id.endsWith('.ts')) {
// 对 TypeScript 代码做一些简单的替换
const transformedCode = code.replace(/console\.log/g, 'console.debug');
return transformedCode;
}
return null;
}
};
}
-
该插件会将所有 TypeScript 文件中的 console.log 替换为 console.debug。
import { Plugin } from 'vite';
export default function transformWithSourceMapPlugin(): Plugin {
return {
name: 'transform-with-source-map-plugin',
transform(code, id) {
if (id.endsWith('.js')) {
// 修改代码内容
const transformedCode = `console.log('Modified JS with source map');\n` + code;
// 返回带有 source map 的转换结果
const map = {
version: 3,
file: id,
sources: [id],
names: [],
mappings: 'AAAA'
};
return {
code: transformedCode,
map
};
}
return null;
}
};
}
-
该插件不仅修改了
.js
文件的代码内容,还为其提供了 source map,以便调试和追踪代码的来源。
import { Plugin } from 'vite';
export default function ssrTransformPlugin(): Plugin {
return {
name: 'ssr-transform-plugin',
transform(code, id, options) {
if (options.ssr) {
// 如果是 SSR 模式,做一些不同的转换
return code.replace('window', 'globalThis');
}
return code;
}
};
}
-
该插件根据是否处于 SSR 模式,做不同的转换。如果是 SSR 模式,它会将 window 替换为 globalThis,以保证代码能够在 Node.js 环境中运行。
transformIndexHtml
在 Vite 中,transformIndexHtml 是一个特殊的插件钩子,专门用于对生成的 index.html 文件进行处理。它允许开发者在 Vite 构建过程中,修改、注入或自定义 HTML 文件,通常用于在页面中插入自定义的 <script>、<link> 标签,或者修改某些现有内容。
transformIndexHtml 钩子的作用
transformIndexHtml 主要用于:
-
注入自定义的 HTML 代码:比如插入外部资源(如 JS、CSS 文件)、内联脚本、元数据等。
-
修改 <head> 或 <body> 内容:在 HTML 文件的 <head> 或 <body> 部分注入额外的元素(如 <meta>、<title>、<script>、<link> 等)。
-
修改 HTML 结构:可以在构建过程中修改生成的 index.html 文件的结构,例如替换某些默认模板内容。
-
处理 HTML 模板:可以针对模板引擎(如 Pug、Handlebars 等)做一些特定的 HTML 预处理。
transformIndexHtml 钩子的执行时机
-
transformIndexHtml 在 Vite 打包生成 HTML 页面时触发,通常在构建完成后、生成最终的 index.html 文件之前。它的主要目的是对 index.html 文件进行修改、增强或动态注入内容。
-
如果你想在 HTML 文件中添加资源链接(如脚本、样式表、favicon、动态标签等),可以在这个钩子中进行操作。
transformIndexHtml 钩子的参数
transformIndexHtml 钩子接收两个参数:
-
html (string): 当前的 index.html 文件的原始内容。这个参数表示 HTML 文件的源代码,可以对其进行修改和注入。
-
env (object): 当前的构建环境信息。包含一些与构建过程相关的配置选项,如是否是生产模式 (prod),或者是否启用了某些插件等。
transformIndexHtml 的返回值
transformIndexHtml 必须返回修改后的 html 字符串,或者返回一个对象来修改 HTML 的某些部分。具体返回值的类型可以是:
-
string: 修改后的 index.html 内容。
-
Promise<string>: 如果钩子是异步的,返回一个 Promise,解析值为修改后的 html 字符串。
-
{ html: string, inject: { head: string[], body: string[] } }: 返回一个对象,允许你指定更多详细的注入内容,包括:
-
html: 修改后的 HTML 内容。
-
inject: 一个对象,允许你分别注入 head 和 body 部分的内容,格式如下:
-
head: 注入到 <head> 部分的 HTML 代码。
-
body: 注入到 <body> 部分的 HTML 代码。
-
-
示例:使用 transformIndexHtml 插件钩子
import { Plugin } from 'vite';
export default function injectScriptsPlugin(): Plugin {
return {
name: 'inject-scripts-plugin',
transformIndexHtml(html) {
return html.replace(
'</head>',
`
<script src="https://cdn.example.com/some-library.js"></script>
<link rel="stylesheet" href="https://cdn.example.com/style.css">
</head>`
);
}
};
}
-
该插件会在 index.html 的 </head> 标签前注入一个外部的 <script> 和 <link> 标签。
import { Plugin } from 'vite';
export default function modifyTitlePlugin(): Plugin {
return {
name: 'modify-title-plugin',
transformIndexHtml(html) {
return html.replace(
/<title>(.*?)<\/title>/,
`<title>Custom Title - ${process.env.VITE_APP_NAME}</title>`
);
}
};
}
-
该插件会替换 index.html 中的 <title> 标签内容,将标题动态替换为 Custom Title + 从环境变量中读取的应用名称。
import { Plugin } from 'vite';
export default function envInjectPlugin(): Plugin {
return {
name: 'env-inject-plugin',
transformIndexHtml(html, { env }) {
if (env.MODE === 'production') {
return html.replace(
'</body>',
`<script>console.log('Production mode activated');</script></body>`
);
} else {
return html.replace(
'</body>',
`<script>console.log('Development mode');</script></body>`
);
}
}
};
}
-
该插件根据 Vite 构建的环境变量(如 MODE)在 index.html 的 <body> 结束前注入不同的 JavaScript 代码。如果是生产环境,注入一条消息;如果是开发环境,注入另一条消息。
import { Plugin } from 'vite';
export default function injectHeadAndBody(): Plugin {
return {
name: 'inject-head-body-plugin',
transformIndexHtml(html) {
return {
html,
inject: {
head: `<meta name="description" content="My Custom Vite App">`,
body: `<script>console.log('Injected after body!');</script>`
}
};
}
};
}
-
该插件会将 <meta> 标签注入到 <head> 部分,同时将一段 JavaScript 代码注入到 <body> 的结束标签前。
import { Plugin } from 'vite';
export default function dynamicHtmlPlugin(): Plugin {
return {
name: 'dynamic-html-plugin',
transformIndexHtml(html) {
const version = process.env.npm_package_version;
return html.replace(
'<body>',
`<body><h1>Welcome to my app! Version: ${version}</h1>`
);
}
};
}
-
该插件会动态修改 index.html 文件,在 <body> 标签开始的位置插入一个显示版本号的 <h1> 标签。
handleHotUpdate
在 Vite 中,handleHotUpdate 是一个重要的插件钩子,它用于处理热模块替换(HMR,Hot Module Replacement)。HMR 是开发过程中非常关键的特性,允许在不刷新整个页面的情况下更新单个模块的内容,从而提高开发效率,避免页面的重新加载。
handleHotUpdate 钩子的作用
handleHotUpdate 钩子的主要作用是处理和响应热更新事件。具体来说,插件通过该钩子可以:
-
拦截模块更新:当某个文件发生变化时,handleHotUpdate 会被调用,插件可以在此时决定是否处理这个变化。
-
触发额外的操作:比如根据文件变化执行某些额外的操作,如重新加载模块、更新缓存、刷新页面等。
-
修改更新的模块:插件可以在此时修改或决定热更新的具体行为,比如通过自定义的更新逻辑来替代默认行为。
-
传递模块信息:插件可以通过 ctx.modules 向 Vite 提供相关的模块信息,以确保 HMR 正常工作。
handleHotUpdate 的参数
handleHotUpdate 接收一个参数,通常是一个上下文对象 ctx,其包含以下属性:
-
file (string):
-
被修改的文件路径,通常是 .js、.ts、.vue、.css 等资源文件的路径。
-
如果是处理非模块文件(如 .html),文件路径也会被提供。
-
-
server (ViteDevServer):
-
当前的 Vite 开发服务器实例,可以用来访问一些 Vite 内部功能,比如模块图(module graph)、HMR 模块等。
-
-
modules (Array<Module>):
-
变更的模块列表。这个属性是一个数组,包含当前正在热更新的所有模块对象。
-
-
update (boolean):
-
一个布尔值,表示是否是模块的更新操作。如果为 true,表示当前文件是一个已经被热更新的模块。
-
handleHotUpdate 的返回值
handleHotUpdate 必须返回一个数组,这些数组中的每个元素都是一个模块对象(Module)。返回的模块列表将会被 Vite 用来处理 HMR 更新。
-
返回的数组:ctx.modules,这是一个可以通过 HMR 更新的模块列表。如果插件希望某些模块被热更新处理,必须把这些模块推送到该数组中。
-
如果插件不做任何处理,或者决定不更新模块,可以返回空数组或不返回任何内容。
handleHotUpdate 的典型用途
-
拦截 HMR 更新:有些情况下你可能希望拦截某些文件的热更新,比如某些文件并不需要更新、或者需要更新时进行额外的操作(如重新加载资源、缓存清理等)。
-
修改模块的热更新行为:你可以通过此钩子来自定义 HMR 的处理逻辑,例如重载某个组件或模块,甚至在更新时手动刷新页面。
-
触发页面重新加载:对于某些资源(如 index.html 或其他关键文件),插件可能会在 HMR 更新时要求浏览器刷新页面,以确保最新的内容被应用。
示例:
import { Plugin } from 'vite';
export default function myHmrPlugin(): Plugin {
return {
name: 'my-hmr-plugin',
handleHotUpdate(ctx) {
const { file, server, modules } = ctx;
// 判断文件是否是某个特定模块
if (file.endsWith('.css')) {
console.log(`CSS file updated: ${file}`);
// 在 HMR 更新时执行自定义的处理逻辑
// 例如,重新加载相关的模块或清理缓存
// 可以通过 `ctx.modules` 向 Vite 提供模块信息,以便触发 HMR 更新
return modules;
}
// 对于其他类型的更新,可以做类似的处理
if (file.endsWith('.js')) {
console.log(`JavaScript file updated: ${file}`);
return modules; // 返回需要更新的模块
}
return []; // 如果不需要处理这个文件,可以返回空数组
}
};
}
-
该插件拦截所有 .css 和 .js 文件的更新,记录日志并返回模块列表,触发 Vite 对该模块的热更新。
-
如果文件类型不是 .css 或 .js,则不做任何处理,返回空数组。
import { Plugin } from 'vite';
export default function forcePageReloadPlugin(): Plugin {
return {
name: 'force-page-reload-plugin',
handleHotUpdate(ctx) {
const { file, server } = ctx;
// 强制更新 `index.html` 或其他关键资源时刷新页面
if (file.endsWith('index.html')) {
console.log('index.html updated, reloading the page...');
// 通过 server.reload 强制刷新页面
server.ws.send({
type: 'full-reload',
path: file
});
}
return [];
}
};
}
-
当 index.html 文件被更新时,插件会强制页面刷新。通过向 Vite 服务器发送一个 full-reload 消息,Vite 会重新加载整个页面。
import { Plugin } from 'vite';
export default function customHmrPlugin(): Plugin {
return {
name: 'custom-hmr-plugin',
handleHotUpdate(ctx) {
const { file, server } = ctx;
// 如果是某个特殊的文件,进行特殊处理
if (file.endsWith('.vue')) {
// 在更新 Vue 文件时,做一些特定的操作,比如清除缓存、强制重新渲染组件等
console.log('Vue component updated:', file);
// 手动触发某个模块的更新
return [server.moduleGraph.getModuleById(file)];
}
return [];
}
};
}
-
当 .vue 文件更新时,插件会返回特定的模块,通知 Vite 对其进行更新处理。