小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
Vite 从入门到精通 | 插件系统
介绍
命名规范
- rollup-plugin-xxx
- vite-plugin-xxx
Vite 兼容 Rollup 钩子
- 服务启动时 (启动 server 时执行一次, 与文件更新无关)
- options
- buildStart
- 模块 (找到对应的文件,->加载->转变目标代码)
- resolveId
- load
- transform
- 服务关闭时
- buildEnd
- closeBundle
modulePased 是不会被调用的, 防止 Vite 整体对代码执行 AST 解析
rollup 插件可以在 build中配置
// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 引入 jsx 依赖
import vueJsx from '@vitejs/plugin-vue-jsx'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [ // 使用插件
vue(),
vueJsx(),// 使用 vue-jsx
],
build: {
rollupOptions:{
plugins
}
}
})
条件: rollup插件符合 vite 使用条件
- 没有使用 moduleParsed 钩子
- 在打包钩子和输出钩子之间没有很强的耦合
Vite 钩子
- config
- configResolved
- configureServer
- transformIndexHtml
- handleHotUpdate
Vite 插件执行时机
- Pre: 最先被执行的插件 , vite 使用 rolluo alias 插件之后就会按照plugin数组中定义的顺序的去执行
- Normal: vite 核心插件执行之后, vite build 插件执行之前执行
- post: vite build 插件 之后执行
实操
-
vite 项目创建 plugins/test-plugin.ts
// test-plugin.ts export default (enforce?: 'pre' | 'post') => { return { name: 'test', enforce, buildStart() { console.log("buildStart", enforce) }, resolveId(){ console.log('resolveId',enforce) } } } -
vite.config.js 配置
// vim vite.config.js import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' // 引入 jsx 依赖 import vueJsx from '@vitejs/plugin-vue-jsx' import testPlugin from './plugins/test-plugin' // https://vitejs.dev/config/ export default defineConfig({ plugins: [ vue(), vueJsx(), testPlugin('post'), testPlugin(), testPlugin('pre') ] }) -
输出结果
$ yarn dev yarn run v1.22.4 warning package.json: No license field $ vite buildStart pre buildStart undefined buildStart post vite v2.6.2 dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ready in 415ms. > Pre > normal > post
Vite 插件 API (钩子)
-
config: return 一个新的 config 与 vite.config.js deepMerge
import { Plugin } from "vite"; export default (enforce?: "pre" | "post"): Plugin => { return { name: "test", // userConfig vite.config.js 中的配置项 config(userConfig) { // return 一个新的 config 与 vite.config.js deepMerge return { resolve: { alias: { "@img": '/src/img' } } } }, }; }; -
configResolved
import { Plugin } from "vite"; export default (enforce?: "pre" | "post"): Plugin => { return { name: "test", // config: 最终的 config configResolved(config){ // 打印 最终 config 中的 plugins console.log(config.plugins) } }; };得到结果
[ { name: 'vite:pre-alias', }, { name: 'alias', }, { name: 'vite:modulepreload-polyfill', }, { name: 'vite:resolve', }, { name: 'vite:html', }, { name: 'vite:css', }, { name: 'vite:esbuild', }, { name: 'vite:json'}, { name: 'vite:wasm', }, { name: 'vite:worker', }, { name: 'vite:asset', }, { name: 'vite:vue', handleHotUpdate: [Function: handleHotUpdate], config: [Function: config], configResolved: [Function: configResolved], configureServer: [Function: configureServer], resolveId: [AsyncFunction: resolveId], load: [Function: load], transform: [Function: transform] }, { name: 'vite:vue-jsx', }, { name: 'test', }, { name: 'vite:define',}, { name: 'vite:css-post', }, { name: 'vite:client-inject',}, { name: 'vite:import-analysis', } ] -
configureServer
configureServer(server){ // 增加中间件 // 会在 Vite 中间件之前执行 server.middlewares.use((req,res,next)=> { if (req.url === "/test") { res.end("Hello Vite Plugin") } else { next() } }) } -
transformIndexHtml
transformIndexHtml(html) { // 在这里可以处理 index.html console.log(html) }<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" href="/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite App</title> </head> <body> <div id="app"><!--APP_HTML--></div> <script type="module" src="/src/main.js"></script> </body> </html>// 处理 html transformIndexHtml(html) { return html.replace('app','root') } -
handleHotUpdate
handleHotUpdate (ctx) { // 文件更新的所有信息 console.log(ctx) }