一个类似Umi的约定式路由Vite插件,可以自动根据文件结构生成路由配置,减少80%路由样板代码,降低90%的路由BUG。
- 📁 约定式路由 - 根据文件目录结构自动生成路由配置
- 🔄 动态路由 - 支持
[param]语法的动态路由参数,支持多个参数嵌套 - 🚀 懒加载 - 默认支持路由组件懒加载,提升应用性能
- 🔍 类型安全 - 自动生成TypeScript类型声明
- 🔌 易于集成 - 与Vue Router无缝集成
- 🔥 热更新 - 支持路由文件的热更新
- 🧩 排除目录 - 支持排除特定目录,如组件库目录不生成路由
- 📋 布局组件 - 支持
_layout.vue作为父路由的布局组件,实现嵌套路由 - 📋 路由元数据 - 支持路由元数据配置(通过配置文件或组件内定义)
# 使用npm
npm install vite-plugin-convention-routes --save-dev
# 使用yarn
yarn add vite-plugin-convention-routes --dev
# 使用pnpm
pnpm add vite-plugin-convention-routes -D// vite.config.js / vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import conventionRoutes from 'vite-plugin-convention-routes'
export default defineConfig({
plugins: [
vue(),
conventionRoutes({
// 路由文件所在目录
routesDir: 'src/views',
// 是否生成类型声明文件
generateDeclaration: true,
// 是否在控制台打印路由信息
verbose: true,
// 是否开启路由懒加载
isLazy: true,
// 需要排除的目录
excludes: ['components', 'common'],
// 布局文件名
layoutName: '_layout'
})
]
})// src/router/index.js 或 src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
// 这里的routes数组会被插件自动替换为约定式路由
const routes = []
export const router = createRouter({
history: createWebHistory(),
routes
})
export default routersrc/views/
├── index.vue # 路由: /
├── about.vue # 路由: /about
├── users/
│ ├── _layout.vue # 布局组件: /users 的布局
│ ├── index.vue # 路由: /users
│ ├── [id].vue # 路由: /users/:id
│ └── [id]/
│ ├── index.vue # 路由: /users/:id
│ ├── profile.vue # 路由: /users/:id/profile
│ └── settings.vue # 路由: /users/:id/settings
├── exam/
│ ├── _layout.vue # 布局组件: /exam 的布局
│ ├── index.vue # 路由: /exam
│ └── [courseId]/
│ ├── index.vue # 路由: /exam/:courseId
│ └── [chapterId]/
│ └── index.vue # 路由: /exam/:courseId/:chapterId
├── posts/
│ ├── index.vue # 路由: /posts
│ └── [id].vue # 路由: /posts/:id
└── components/ # 默认被排除,不生成路由
├── Header.vue # 不会生成路由
└── Footer.vue # 不会生成路由
以上文件结构将生成如下路由配置:
[
{
"path": "/",
"component": "() => Component",
"name": "home"
},
{
"path": "/about",
"component": "() => Component",
"name": "about",
"originalFilePath": "/src/views/about.vue"
},
{
"path": "/exam",
"component": "() => Component",
"children": [
{
"path": ":courseId/:chapterId",
"component": "() => Component",
"name": "exam-courseId-chapterId",
"originalFilePath": "/src/views/exam/[courseId]/[chapterId]/index.vue"
},
{
"path": ":courseId",
"component": "() => Component",
"name": "exam-courseId",
"originalFilePath": "/src/views/exam/[courseId]/index.vue"
},
{
"path": "",
"component": "() => Component",
"name": "exam",
"originalFilePath": "/src/views/exam/index.vue"
}
]
},
{
"path": "/users",
"component": "() => Component",
"children": [
{
"path": ":id",
"component": "() => Component",
"name": "users-id",
"originalFilePath": "/src/views/users/[id].vue"
},
{
"path": "",
"component": "() => Component",
"name": "users",
"originalFilePath": "/src/views/users/index.vue"
}
]
}
]注意:实际生成的路由配置中,"() => Component" 是真实的组件引用函数,这里只是为了展示而简化。
布局组件是一种特殊的组件,用于为特定目录下的所有路由提供共享布局。布局组件命名为 _layout.vue,放置在需要应用布局的目录中。
例如,src/views/users/_layout.vue 将作为 /users 路径下所有路由的布局组件,所有 /users/ 开头的路由都将嵌套在这个布局组件内。布局组件需要包含 <router-view></router-view> 标签来显示子路由内容。
<!-- src/views/users/_layout.vue -->
<template>
<div class="users-layout">
<h1>用户模块</h1>
<nav>
<router-link to="/users">用户列表</router-link>
<!-- 其他导航链接 -->
</nav>
<!-- 子路由内容将在这里渲染 -->
<router-view></router-view>
</div>
</template>index.vue文件映射到父路径[param].vue文件映射到动态路由参数:param- 支持多个动态参数嵌套,如
/exam/[courseId]/[chapterId]映射为/exam/:courseId/:chapterId - 其他文件名直接映射到路由路径
| 选项 | 类型 | 默认值 | 描述 |
|---|---|---|---|
routesDir |
string |
'src/views' |
路由文件所在目录 |
extensions |
string[] |
['.vue'] |
要处理的文件扩展名 |
generateDeclaration |
boolean |
true |
是否生成路由声明文件 |
declarationPath |
string |
'src/router/routes.d.ts' |
路由声明文件输出路径 |
verbose |
boolean |
false |
是否在控制台打印路由信息 |
isLazy |
boolean |
true |
是否开启路由懒加载 |
excludes |
string[] |
['components'] |
需要排除的目录,这些目录下的文件不会被添加到路由配置中 |
layoutName |
string |
'_layout' |
布局文件名,用于识别布局组件 |
metaConfigPath |
string |
'src/router/route-meta.js' |
路由元数据配置文件路径 |
enableInComponentMeta |
boolean |
true |
是否启用组件内定义元数据 |
可以创建专门的配置文件来定义路由元数据:
// src/router/route-meta.js
export default {
'/': {
title: '首页',
icon: 'home',
keepAlive: true
},
'/users': {
title: '用户管理',
permissions: ['admin'],
icon: 'user-group'
},
'/users/:id': {
title: '用户详情',
parentPath: '/users',
breadcrumb: true
}
}可以使用两种方式在组件内定义元数据:
使用特定格式的注释块来定义元数据:
<template>
<div>用户列表页面</div>
</template>
<script>
/* route-meta
{
"title": "用户管理",
"icon": "user-group",
"permissions": ["admin"],
"keepAlive": true
}
*/
export default {
name: 'UserList'
}
</script>通过导出 routeMeta 变量来定义元数据:
<template>
<div>关于页面</div>
</template>
<script>
// 使用导出变量的方式定义路由元数据
export const routeMeta = {
title: '关于我们',
icon: 'info-circle',
isPublic: true,
noCache: true
}
export default {
name: 'AboutPage'
}
</script>如果同一个路由在多个地方定义了元数据,优先级如下:
- 组件内定义的元数据(最高优先级)
- 配置文件中定义的元数据
- 默认元数据(如果有)
# 安装依赖
pnpm install
# 开发模式
pnpm run dev
# 构建插件
pnpm run build
# 运行测试
pnpm test查看 example 目录中的示例项目,了解如何使用此插件。示例中包含了多级路由参数的实际应用,如 /exam/:courseId/:chapterId。
MIT