@hf-/vite-plugin-auto-router
Version:
A Vite plugin for auto-generating Vue router configuration based on file system
102 lines (89 loc) • 3.39 kB
JavaScript
// src/index.ts
import { resolve as resolve2 } from "path";
// src/utils/fs.ts
import { dirname } from "path";
import { promises as fs } from "fs";
async function ensureDir(dir) {
try {
await fs.access(dir);
} catch {
await fs.mkdir(dir, { recursive: true });
}
}
async function writeFile(filePath, content) {
const dir = dirname(filePath);
await ensureDir(dir);
await fs.writeFile(filePath, content, "utf-8");
}
// src/index.ts
function autoRouter(options = {}) {
const {
viewsDir = "src/views",
outputPath = "src/router/routes.ts",
dynamicRouteFromUnderscore = true,
removeRedundantSegments = true
} = options;
return {
name: "vite-plugin-auto-router",
configureServer(server) {
server.watcher.add(resolve2(server.config.root, viewsDir));
server.watcher.on("add", () => generateRoutes());
server.watcher.on("unlink", () => generateRoutes());
},
async buildStart() {
await generateRoutes();
}
};
async function generateRoutes() {
const routeTemplate = `
// \u6B64\u6587\u4EF6\u7531 vite-plugin-auto-router \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
import { RouteRecordRaw } from 'vue-router'
// \u52A8\u6001\u5BFC\u5165\u6240\u6709\u9875\u9762\u7EC4\u4EF6
const modules = import.meta.glob('${viewsDir}/**/*.vue', { eager: false })
// \u52A8\u6001\u5BFC\u5165\u6240\u6709\u5143\u6570\u636E\u6587\u4EF6
const metaModules = import.meta.glob('${viewsDir}/**/*.meta.js', { eager: true })
// \u751F\u6210\u8DEF\u7531\u914D\u7F6E
const routes: RouteRecordRaw[] = Object.keys(modules).map((filePath) => {
// \u751F\u6210\u8DEF\u7531\u8DEF\u5F84
let routePath = filePath
.replace('${viewsDir}/', '')
.replace(/.vue$/, '')
${dynamicRouteFromUnderscore ? ".replace(/\\/_/g, '/:')" : ""} // \u5C06\u6587\u4EF6\u540D\u4E2D\u7684\u4E0B\u5212\u7EBF\u8F6C\u6362\u4E3A\u52A8\u6001\u8DEF\u7531\u53C2\u6570
// \u62C6\u5206\u8DEF\u5F84\u5E76\u5904\u7406
const parts = routePath.split('/').filter(Boolean)
${removeRedundantSegments ? `
// \u79FB\u9664\u91CD\u590D\u7684\u76EE\u5F55\u540D\u548C\u6587\u4EF6\u540D
if (parts.length > 1 && parts[parts.length - 1] === parts[parts.length - 2]) {
parts.pop()
}
if (parts.length > 1 && parts[parts.length - 1].toLowerCase() === 'index') {
parts.pop()
}
` : ""}
routePath = '/' + parts.join('/').toLowerCase()
// \u5BFC\u5165\u5143\u6570\u636E\u6587\u4EF6
const metaFilePath = filePath.replace('.vue', '.meta.js')
const meta = metaModules[metaFilePath] ? metaModules[metaFilePath].default : {}
return {
path: routePath,
component: modules[filePath],
...meta
}
})
// \u786E\u4FDD\u6709\u4E00\u4E2A\u6839\u8DEF\u5F84\uFF08'/'\uFF09\u7684\u8DEF\u7531
if (!routes.some((route) => route.path === '/')) {
routes.push({
path: '/',
component: () => import('${viewsDir}/Home/Home.vue'),
meta: { title: 'Home' }
})
}
export default routes
`;
const outputFilePath = resolve2(process.cwd(), outputPath);
await writeFile(outputFilePath, routeTemplate);
}
}
export {
autoRouter as default
};