@onoxm/vite-plugin-auto-router
@onoxm/vite-plugin-auto-router
A Vite plugin for automatically generating React or Vue route files.
English | 中文
Features
- Auto-generate route configuration, no manual maintenance needed
- Supports both React and Vue frameworks
- Convention-based routing, automatically mapped by directory structure
- Supports dynamic route
[id]syntax homepage path automatically converted to/(configurable)__root__page as root route container (configurable)- Configurable lazy loading and hot module replacement
- Supports page-level configuration files
- TypeScript type safety
Installation
npm install -D @onoxm/vite-plugin-auto-router
Usage Guide
Page Component Identification Rules
The plugin identifies page components based on the following rules:
React Project
- Page components: Components with default export (
export default) in the pages directory - Regular components: Components with named export (
export const) in the pages directory
Vue Project
- Page components:
- Direct child components in the views directory (e.g.,
src/views/about.vue) - In nested directories, only
index.vueis considered a page component (e.g.,src/views/a/b/index.vue)
- Direct child components in the views directory (e.g.,
- Regular components: Non-
index.vuefiles in nested directories (e.g.,src/views/a/b.vue)
React Project
Install Dependencies
npm install react-router
Configure Vite
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import autoRouter from '@onoxm/vite-plugin-auto-router/react'
export default defineConfig({
plugins: [
react(),
autoRouter({
onGenerated: async filePaths => {
for (const filePath of filePaths) {
console.log('Generated:', filePath)
}
}
})
]
})
Directory Structure
src/
├── pages/
│ ├── index.tsx
│ ├── __root__.tsx
│ ├── 404.tsx
│ └── user/
│ ├── index.tsx
│ ├── index.config.ts
│ ├── [id].tsx
│ └── [id].config.ts
Special Pages
homepage: Path automatically converted to/, used as home route__root__page: Used as root route container, wrapping all other routes404ornotfoundpage: Path automatically converted to/*, used as 404 route
Page Configuration
Inherits from React Router RouteObject, with the following modifications:
- Removed:
Component,element,children - Added:
type?: 'single' | 'wrap'
type: 'single'
When type is set to single, the page component will be generated as an independent route:
// src/pages/user/index.config.ts
import { defineConfig } from '../../router/autoRouter'
export default defineConfig({
type: 'single'
})
Generated route structure:
// src/router/autoRouter.tsx
import type { RouteObject } from 'react-router'
import Pages404 from './../pages/404.tsx'
import Pages from './../pages/index.tsx'
import PagesRoot from './../pages/__root__.tsx'
import PagesUser from './../pages/user/index.tsx'
import PagesUserId from './../pages/user/[id]/index.tsx'
type PageConfig = Partial<
Omit<RouteObject, 'Component' | 'element' | 'children'> & {
type?: 'single' | 'wrap'
}
>
export const defineConfig = (config: PageConfig) => config
export const routes: RouteObject[] = [
{
path: '/',
element: <PagesRoot />,
children: [
{
path: '/',
element: <Pages />
},
{
path: '/user',
children: [
{
path: '',
index: true,
element: <PagesUser />
},
{
path: ':id',
children: [
{
path: '',
index: true,
action: async () => {},
loader: async ({ params }) => await { params },
element: <PagesUserId />
}
]
}
]
}
]
},
{
path: '/*',
element: <Pages404 />
}
]
type: 'wrap'
When type is set to wrap, the page component will act as a parent route container wrapping its child routes:
// src/pages/user/index.config.ts
import { defineConfig } from '../../router/autoRouter'
export default defineConfig({
type: 'wrap'
})
Generated route structure:
// src/router/autoRouter.tsx
import type { RouteObject } from 'react-router'
import Pages404 from './../pages/404.tsx'
import Pages from './../pages/index.tsx'
import PagesRoot from './../pages/__root__.tsx'
import PagesUser from './../pages/user/index.tsx'
import PagesUserId from './../pages/user/[id]/index.tsx'
type PageConfig = Partial<
Omit<RouteObject, 'Component' | 'element' | 'children'> & {
type?: 'single' | 'wrap'
}
>
export const defineConfig = (config: PageConfig) => config
export const routes: RouteObject[] = [
{
path: '/',
element: <PagesRoot />,
children: [
{
path: '/',
element: <Pages />
},
{
path: '/user',
element: <PagesUser />,
children: [
{
path: ':id',
children: [
{
path: '',
index: true,
action: async () => {},
loader: async ({ params }) => await { params },
element: <PagesUserId />
}
]
}
]
}
]
},
{
path: '/*',
element: <Pages404 />
}
]
Vue Project
Install Dependencies
npm install vue-router
Configure Vite
// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import autoRouter from '@onoxm/vite-plugin-auto-router/vue'
export default defineConfig({
plugins: [
vue(),
autoRouter({
pagesDir: './src/views',
configPattern: '/**/*.meta.ts',
onGenerated: async filePaths => {
for (const filePath of filePaths) {
console.log('Generated:', filePath)
}
}
})
]
})
Directory Structure
src/
├── views/
│ ├── 404.vue
│ ├── home/
│ │ ├── index.vue
│ │ └── index.meta.ts
│ └── user/
│ ├── index.vue
│ ├── index.meta.ts
│ ├── [id].vue
│ └── [id].meta.ts
Special Pages
homepage: Path automatically converted to/, used as home route__root__page: Used as root route container, wrapping all other routes404ornotfoundpage: Path automatically converted to/:pathMatch(.*)*, used as 404 route
Page Configuration
Inherits from Vue Router RouteRecordRaw, with the following modifications:
- Removed:
component,children - Added:
type?: 'single' | 'wrap'
type: 'single'
When type is set to single, the page component will be generated as an independent route:
// src/views/user/index.meta.ts
import { defineConfig } from '../../router/autoRouter'
export default defineConfig({
type: 'single'
})
Generated route structure:
// src/router/autoRouter.ts
import type { RouteRecordRaw } from 'vue-router'
import Views404 from './../views/404.vue'
import ViewsHome from './../views/home/index.vue'
import ViewsUser from './../views/user/index.vue'
import ViewsUserId from './../views/user/[id]/index.vue'
type PageConfig = Partial<
Omit<RouteRecordRaw, 'component' | 'children'> & {
type?: 'single' | 'wrap'
}
>
export const defineConfig = (config: PageConfig) => config
export const routes: RouteRecordRaw[] = [
{
path: '/',
children: [
{
path: '',
name: 'home',
component: ViewsHome
}
]
},
{
path: '/user',
children: [
{
path: '',
component: ViewsUser
},
{
path: ':id',
children: [
{
path: '',
component: ViewsUserId
}
]
}
]
},
{
path: '/:pathMatch(.*)*',
children: [
{
path: '',
component: Views404
}
]
}
]
type: 'wrap'
When type is set to wrap, the page component will act as a parent route container wrapping its child routes:
// src/views/user/index.meta.ts
import { defineConfig } from '../../router/autoRouter'
export default defineConfig({
type: 'wrap'
})
Generated route structure:
// src/router/autoRouter.ts
import type { RouteRecordRaw } from 'vue-router'
import Views404 from './../views/404.vue'
import ViewsHome from './../views/home/index.vue'
import ViewsUser from './../views/user/index.vue'
import ViewsUserId from './../views/user/[id]/index.vue'
type PageConfig = Partial<
Omit<RouteRecordRaw, 'component' | 'children'> & {
type?: 'single' | 'wrap'
}
>
export const defineConfig = (config: PageConfig) => config
export const routes: RouteRecordRaw[] = [
{
path: '/',
children: [
{
path: '',
name: 'home',
component: ViewsHome
}
]
},
{
path: '/user',
component: ViewsUser,
children: [
{
path: ':id',
children: [
{
path: '',
component: ViewsUserId
}
]
}
]
},
{
path: '/:pathMatch(.*)*',
children: [
{
path: '',
component: Views404
}
]
}
]
Configuration Options
Plugin Configuration
| Option | Type | Default | Description |
|---|---|---|---|
framework |
'react' | 'vue' |
'react' |
Framework type |
pagesDir |
string |
'./src/pages' |
Pages directory |
routesFile |
string |
undefined |
Generated route file path |
keepHome |
boolean |
false |
Whether to keep home page path |
keepRoot |
boolean |
false |
Whether to keep __root__ page path |
lazy |
boolean |
true |
Whether to enable lazy loading |
hmr |
boolean |
true |
Whether to enable/disable HMR |
configPattern |
string |
/**/*.config.{js,ts} |
Config file format |
onGenerated |
(filePaths: string[]) => Promise<void> | void |
undefined |
Callback after routes generated |
Page Configuration
| Option | Type | Default | Description |
|---|---|---|---|
type |
'single' | 'wrap' |
'single' |
Route type |
path |
string |
undefined |
Route path, supports [currentPath] placeholder to reference current path |
* |
any |
any |
Inherits from router config |
path Usage Example
Use the [currentPath] placeholder to reference the current path when replacing:
// src/pages/user/index.config.ts
import { defineConfig } from '../../router/autoRouter'
export default defineConfig({
// Replace /user with /users/v2
path: '/users/v2'
})
// Or use the placeholder to add a suffix to the current path
export default defineConfig({
// Replace /user with /user/v2
path: '[currentPath]/v2'
})
License
MIT