自定义Vite插件开发实战
1. 插件功能定义
- 场景:解决团队重复性工作
- 插件功能:自动生成路由配置(基于文件系统)
- 输入:
src/pages目录下的.vue文件 - 输出:
src/router/routes.ts动态路由配置
2. 插件完整代码
// vite-plugins/auto-routes.ts
import { Plugin } from 'vite';
import fs from 'fs/promises';
import path from 'path';
interface RouteMeta {
path: string;
component: string;
children?: RouteMeta[];
}
export default function autoRoutes(): Plugin {
return {
name: 'vite-plugin-auto-routes',
// 在构建启动时执行
async buildStart() {
const pagesDir = path.join(process.cwd(), 'src/pages');
const outputFile = path.join(process.cwd(), 'src/router/routes.ts');
// 递归读取pages目录
const generateRoutes = async (dir: string, basePath = ''): Promise<RouteMeta[]> => {
const entries = await fs.readdir(dir, { withFileTypes: true });
const routes: RouteMeta[] = [];
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.isDirectory()) {
// 处理子目录
routes.push({
path: `/${basePath}${entry.name}`,
children: await generateRoutes(fullPath, `${basePath}${entry.name}/`)
});
} else if (entry.name.endsWith('.vue')) {
// 处理vue文件
const name = entry.name.replace('.vue', '');
routes.push({
path: `/${basePath}${name === 'index' ? '' : name}`,
component: `() => import('../pages/${basePath}${entry.name}')`
});
}
}
return routes;
};
const routes = await generateRoutes(pagesDir);
const code = `// Auto-generated by vite-plugin-auto-routes\nexport default ${JSON.stringify(routes, null, 2)}`;
// 写入路由文件
await fs.writeFile(outputFile, code, 'utf-8');
console.log('🚀 Routes generated successfully!');
}
};
}
3. 集成到Vite项目
// vite.config.ts
import autoRoutes from './vite-plugins/auto-routes';
export default defineConfig({
plugins: [
vue(),
autoRoutes() // 启用插件
]
});
4. 效果演示
-
目录结构:
src/ pages/ home/ index.vue about.vue router/ routes.ts (自动生成) -
生成内容:
// routes.ts export default [ { path: "/home", component: () => import('../pages/home/index.vue') }, { path: "/about", component: () => import('../pages/about.vue') } ]
5. 插件进阶能力
-
热更新支持:
// 在插件中添加 configureServer(server) { server.watcher.on('change', async (file) => { if (file.includes('src/pages')) { await this.buildStart(); server.ws.send({ type: 'full-reload' }); } }); } -
类型安全:
生成.d.ts文件补充路由类型定义。 -
配置化:
允许通过参数自定义扫描目录和输出位置:interface Options { pagesDir?: string; outputFile?: string; }