中文 | English
基于文件系统的 Vue.js 自动路由生成工具,简化路由配置,提升开发效率。
[!WARNING] 注意: 旧版本的代码和文档已迁移至 legacy 分支。旧版本的包名为
@elegant-router/vue
,而新版本的包名为elegant-router
。如果您正在使用旧版本或需要参考旧版本的文档,请访问该分支。
ElegantRouter 是一款为 Vue.js 应用设计的创新路由管理工具,专为简化 Vue Router 的配置而设计。它基于文件系统结构自动生成路由,消除了手动配置路由的繁琐过程,使开发人员能够专注于应用功能的实现。
通过 ElegantRouter,您只需按照约定的命名规则创建 Vue 页面文件,系统会自动:
这种基于约定的路由生成方式不仅提高了开发效率,还增强了项目的可维护性和可扩展性。无需在单独的配置文件中手动定义每个路由,路由结构会随着文件系统的变化自动更新,确保路由配置与实际页面结构保持同步。
传统 Vue Router 配置方式通常需要开发者手动完成多个步骤:导入布局组件、导入页面组件、定义路由配置等。这些步骤虽然简单,但在大型项目中会变得繁琐且容易出错。特别是当需要维护大量路由时,路由名称和路径的一致性维护成为一项挑战,容易导致路由定义混乱和难以管理。
ElegantRouter 旨在解决这些问题,通过基于文件系统的约定简化 Vue 应用的路由配置过程。与其他类似工具相比,ElegantRouter 的独特优势在于:
简化配置 - 其他工具往往有繁多的配置规则,且路由数据作为黑盒难以自定义;而 ElegantRouter 采用白盒设计,使路由数据透明且易于扩展。
API 优先 - 遵循 API-first 原则,将路由配置过程完全自动化,减少手动干预。
使用 ElegantRouter,只需按照约定创建文件,系统会自动识别并生成对应的路由配置,极大提高了 Vue 应用开发效率并降低了维护成本。
ElegantRouter 提供了一系列强大的特性,使路由管理变得简单高效:
ElegantRouter 的核心功能设计围绕简化开发流程和提高效率:
使用包管理器安装 ElegantRouter:
pnpm install elegant-router
ElegantRouter 提供了命令行工具,可以帮助您快速创建、删除和管理路由。
# 全局安装
npm install -g elegant-router
# 使用命令
er --help
如果您已经在项目中安装了 ElegantRouter,可以通过 npx 使用命令行工具:
npx er --help
ElegantRouter CLI 提供以下命令:
命令 | 简写 | 描述 |
---|---|---|
er gen |
er -g |
生成路由配置文件 |
er add |
er -a |
交互式添加新路由文件 |
er rm |
er -r |
交互式删除现有路由文件 |
er --help |
er -h |
显示帮助信息 |
er --version |
er -v |
显示版本信息 |
您可以在项目根目录创建 elegant-router.config.ts
文件来配置 CLI 工具的行为:
// elegant-router.config.ts
import { defineConfig } from 'elegant-router';
export default defineConfig({
// 配置选项
pageDir: 'src/views',
layouts: {
base: 'src/layouts/base/index.vue',
blank: 'src/layouts/blank/index.vue'
}
});
# 根据当前文件结构生成路由配置
er gen
# 交互式添加新路由
er add
这将启动交互式命令行界面,引导您:
CLI 工具会自动创建文件并更新路由配置。
# 交互式删除路由
er rm
这将显示当前所有路由列表,让您选择要删除的路由。确认后,CLI 工具会删除相应的文件并更新路由配置。
ElegantRouter 支持多种主流构建工具,以适应不同的项目环境需求。无论您使用哪种构建工具,ElegantRouter 都能提供一致的路由自动生成体验。
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import ElegantRouter from "elegant-router/vite";
export default defineConfig({
plugins: [
vue(),
ElegantRouter({
// 配置选项
}),
]
});
// webpack.config.js
const ElegantRouter = require('elegant-router/webpack');
module.exports = {
// 其他配置...
plugins: [
new ElegantRouter({
// 配置选项
})
]
};
// rollup.config.js
import ElegantRouter from 'elegant-router/rollup';
export default {
// 其他配置...
plugins: [
ElegantRouter({
// 配置选项
})
]
};
// esbuild.config.js
const { build } = require('esbuild');
const ElegantRouter = require('elegant-router/esbuild');
build({
// 其他配置...
plugins: [
ElegantRouter({
// 配置选项
})
]
});
ElegantRouter 还提供了 UnPlugins 通用接口,可以在支持 UnPlugins 的构建工具中使用:
import { createUnplugin } from 'elegant-router/unplugin';
const ElegantRouterUnplugin = createUnplugin({
// 配置选项
});
// 然后根据不同构建工具使用相应的方法
// ElegantRouterUnplugin.vite()
// ElegantRouterUnplugin.webpack()
// ElegantRouterUnplugin.rollup()
// 等等...
将 ElegantRouter 插件添加到您的 Vite 配置中:
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import ElegantRouter from "elegant-router/vite";
export default defineConfig({
plugins: [
vue(),
ElegantRouter(), // 使用默认配置
]
});
在路由文件中引入生成的路由数据:
// src/router/index.ts
import { createRouter, createWebHistory } from 'vue-router';
import { routes } from './_generated/routes';
import { layouts, views } from './_generated/imports';
import { transformToVueRoutes } from './_generated/transformer';
// 转换路由
const vueRoutes = transformToVueRoutes(routes, layouts, views);
const router = createRouter({
history: createWebHistory(),
routes: vueRoutes
});
export default router;
ElegantRouter 基于文件系统约定创建路由,遵循简单直观的规则。新版本设计更加灵活,不强制目录结构,但提供清晰的文件命名约定。
创建普通页面组件,自动生成对应路由:
文件路径: src/views/home/index.vue
生成路由:
{
name: 'Home',
path: '/home',
layout: 'base',
component: 'Home'
}
layout
属性指定页面使用的布局组件,component
属性标识视图组件。转换器会根据这些信息构建最终的嵌套路由结构。
您可以在生成的路由对象上添加其他属性,如
meta
,props
,beforeEnter
等,以满足特定需求。
使用方括号语法创建带参数的路由:
文件路径: src/views/list/[id].vue
生成路由:
{
name: 'ListId',
path: '/list/:id',
layout: 'base',
component: 'ListId'
}
使用双方括号语法创建带可选参数的路由:
文件路径: src/views/list/detail-[[id]]-[[userId]].vue
生成路由:
{
name: 'ListDetailIdUserId',
path: '/list/detail-:id?-:userId?',
layout: 'base',
component: 'ListDetailIdUserId'
}
使用下划线分隔多个参数:
文件路径: src/views/list/detail_[id]_[userId].vue
生成路由:
{
name: 'ListDetailIdUserId',
path: '/list/detail/:id/:userId',
layout: 'base',
component: 'ListDetailIdUserId'
}
使用圆括号创建不影响路由路径的分组:
文件路径: src/views/(group)/demo/index.vue
生成路由:
{
name: 'Demo',
path: '/demo',
component: 'Demo'
}
对于特殊需求,支持配置自定义路由:
ElegantRouter({
customRoutes: {
'CustomRoute': '/custom-route',
'NotFound': '/:pathMatch(.*)*'
},
});
{
name: "CustomRoute",
path: "/custom-route",
layout: "base",
component: "wip", // 使用已有的页面路由文件
}
在启动项目时,插件会初始化文件监听器,实时监控页面文件的变化。当检测到文件有新增、删除或重命名操作时,插件会自动重新生成路由相关内容,无需手动干预或重启服务。这确保了路由配置始终与实际文件结构保持同步,极大提升了开发体验。
监听器的主要功能包括:
通过 watchFile
配置项可以控制是否启用文件监听功能,fileUpdateDuration
配置项则用于设置防抖延迟时间。
插件会自动将路由名称注入到路由文件组件中,这对于 Vue Router 的 KeepAlive 功能至关重要。KeepAlive 依赖于组件名称来正确缓存和恢复组件状态。
支持的组件类型:
注入规则:
例如,对于文件 src/views/home/index.vue
,会自动注入:
<script setup>
const _sfc_main = {
name: 'Home', // 自动注入的组件名称
// ... 其他组件选项
}
</script>
对于 TSX/JSX 组件:
export default defineComponent({
name: 'Home', // 自动注入的组件名称
setup() {
return () => <div>Home</div>;
}
});
启动项目后,ElegantRouter 会在配置的目录(默认为 src/router/_generated
)下生成以下文件:
ElegantRouter 采用一级路由到嵌套路由的转换流程,简化路由管理:
// 生成的一级路由(简洁直观)
{
name: 'Home',
path: '/home',
layout: 'base',
component: 'Home'
}
// 转换后的嵌套路由(按布局分组)
{
path: '/base-layout',
component: () => import('@/layouts/base/index.vue'),
children: [
{
name: 'Home',
path: '/home',
component: () => import('@/views/home/index.vue')
}
// ...同一布局下的其他路由
]
}
ElegantRouter 提供了丰富的配置选项,使您能够根据项目需求自定义路由生成行为:
interface AutoRouterOptions {
/**
* 项目根目录
*
* @default process.cwd()
*/
cwd?: string;
/**
* 是否监听文件
*
* @default true
*/
watchFile?: boolean;
/**
* 文件更新时间
*
* @default 500 ms
*/
fileUpdateDuration?: number;
/**
* 页面目录
*
* @default "['src/views']"
*/
pageDir?: MaybeArray<string>;
/**
* 页面 glob
*
* @default '**/*.vue'
*/
pageInclude?: MaybeArray<string>;
/**
* 页面 glob 排除
*
* @default ['**/components/**', '**/modules/**']
*/
pageExclude?: MaybeArray<string>;
/**
* 生成的路由类型声明文件路径
*
* @default 'src/typings/elegant-router.d.ts'
*/
dts?: string;
/**
* vue-router 类型声明文件路径
*
* @default 'src/typings/typed-router.d.ts'
*/
vueRouterDts?: string;
/**
* tsconfig 文件路径
*
* @default 'tsconfig.json'
*/
tsconfig?: string;
/**
* 项目别名
*
* @default 'get the alias from the tsconfig'
*/
alias?: Record<string, string>;
/**
* 路由自动生成的目录
*
* @default 'src/router/_generated'
*/
routerGeneratedDir?: string;
/**
* 路由布局
*
* @default "{
* base: 'src/layouts/base/index.vue',
* blank: 'src/layouts/blank/index.vue',
* }"
*/
layouts?: Record<string, string>;
/**
* 布局懒加载
*
* @default true
*/
layoutLazy?: (layout: string) => boolean;
/**
* 自定义路由配置
*
* 您可以通过 map 配置名称与路径的映射,或通过 paths 提供路径列表
* 系统将自动为每条路径创建对应的路由节点
*
* @example
* ```ts
* customRoute: {
* map: {
* Home: '/home',
* About: '/about'
* },
* paths: ['/home2', '/about2']
* }
* ```
*/
customRoute?: Partial<CustomRoute>;
/**
* 根路由重定向路径
*
* @default '/home'
*/
rootRedirect?: string;
/**
* 404 路由组件
*
* @default '404'
*/
notFoundRouteComponent?: string;
/**
* 默认自定义路由组件
*
* @default 'wip'
*/
defaultCustomRouteComponent?: string;
/**
* 路由路径获取函数
*
* @default 'src/router/auto-router'
*/
getRoutePath?: (node: AutoRouterNode) => string;
/**
* 路由名称获取函数
*
* @default transform the path to the route name
*/
getRouteName?: (node: AutoRouterNode) => string;
/**
* 路由布局映射,用于 `getRouteLayout`
*
* 如果设置,将根据路由文件路径查找布局
*/
routeLayoutMap?: Record<string, string>;
/**
* 路由布局获取函数
*
* @default get the first key of the layouts
*/
getRouteLayout?: (node: AutoRouterNode) => string;
/**
* 路由懒加载函数
*
* @default true
*/
routeLazy?: (node: AutoRouterNode) => boolean;
}
ElegantRouter 现在提供了内置的基础路由支持,包括:
这些内置路由无需额外配置即可使用,系统会自动将它们添加到路由列表中。您可以通过配置选项自定义它们的行为:
rootRedirect
- 设置根路由的重定向目标notFoundRouteComponent
- 指定 404 路由使用的组件除了基于文件系统的路由外,ElegantRouter 还支持以两种方式创建自定义路由:
customRoute.map
配置名称与路径的映射关系:customRoute: {
map: {
Dashboard: '/dashboard',
UserProfile: '/user/profile'
}
}
customRoute.paths
提供路径列表,系统将自动推导路由名称:customRoute: {
paths: ['/settings', '/user/settings']
}
自定义路由默认使用 defaultCustomRouteComponent
配置中指定的组件(默认为 'wip')。
与旧版本 @elegant-router/vue
相比,新版本 elegant-router
进行了许多改进:
功能 | 旧版本 | 新版本 |
---|---|---|
架构设计 | 黑盒设计,路由数据处理逻辑不透明 | 白盒设计,路由数据完全透明可访问 |
处理流程 | 复杂的流程,难以扩展 | 清晰的处理步骤,便于自定义和扩展 |
文件解析 | 受限的文件解析能力 | 更强大的文件系统解析,支持多种命名约定 |
类型安全 | 基本的类型支持 | 完整的类型定义和自动生成的类型声明 |
自定义路由 | 有限的自定义能力 | 全面支持自定义路由,包括映射表和路径列表 |
内置路由 | 需要手动配置基础路由 | 内置根路由和404路由,简化配置 |
layout.base$view.about
)表示组件关系layout
和 component
字段清晰表示组件关系// 单级路由
{
name: 'about',
path: '/about',
component: 'layout.base$view.about',
meta: { title: 'about' }
}
// 多级路由
{
name: 'list',
path: '/list',
component: 'layout.base',
meta: { title: 'list' },
children: [
{
name: 'list_home',
path: '/list/home',
component: 'view.list_home',
meta: { title: 'list_home' }
}
]
}
// 统一的一级路由结构
{
name: 'Home',
path: '/home',
layout: 'base',
component: 'Home'
}
{
name: 'ListHome',
path: '/list/home',
layout: 'base',
component: 'ListHome'
}
// 单级路由转换后
{
path: '/about',
component: BaseLayout,
children: [
{
name: 'about',
path: '',
component: () => import('@/views/about/index.vue'),
meta: { title: 'about' }
}
]
}
// 多级路由转换后
{
name: 'list',
path: '/list',
component: BaseLayout,
redirect: { name: 'list_home' },
meta: { title: 'list' },
children: [
{
name: 'list_home',
path: '/list/home',
component: () => import('@/views/list/home/index.vue'),
meta: { title: 'list_home' }
}
]
}
// 按布局分组的路由结构
{
path: '/base-layout',
component: () => import('@/layouts/base/index.vue'),
children: [
{
name: 'Home',
path: '/home',
component: () => import('@/views/home/index.vue')
},
{
name: 'ListHome',
path: '/list/home',
component: () => import('@/views/list/home/index.vue')
}
// ...同一布局下的其他路由
]
}
新版 ElegantRouter 带来了多方面的提升:
根据项目情况,您可以参考以下建议选择合适的版本:
为了充分发挥 ElegantRouter 的优势,推荐以下开发实践:
利用 ElegantRouter 内置的根路由和 404 路由简化配置:
// vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import ElegantRouter from "elegant-router/vite";
export default defineConfig({
plugins: [
vue(),
ElegantRouter({
rootRedirect: '/dashboard', // 自定义根路由重定向
notFoundRouteComponent: 'NotFound' // 自定义404组件名
})
]
});
混合使用基于文件系统的自动路由和自定义路由,灵活应对各种场景:
ElegantRouter({
customRoute: {
map: {
Dashboard: '/dashboard',
Settings: '/settings'
},
paths: [
'/profile',
'/account/details'
]
},
defaultCustomRouteComponent: 'WorkInProgress'
})
index.vue
或有明确含义的文件名[param]
,可选参数使用 [[param]]
detail_[id]_[userId]
来提高可读性layouts
选项,确保每个页面都有适当的布局layout
属性控制页面的布局,相同布局的页面会自动分组dynamicImport
配置,控制组件导入方式通过遵循这些最佳实践,您可以充分发挥 ElegantRouter 的强大功能,创建高效、可维护的路由系统。