vite-plugin-generoutes 1.1.1 → 2.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +66 -1
- package/README.zh_CN.md +66 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +30 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,6 +14,7 @@ A Vite plugin that automatically generates Vue router configuration based on fil
|
|
|
14
14
|
- 🎨 Customizable route configuration
|
|
15
15
|
- 🧩 Support for route metadata via `defineOptions`
|
|
16
16
|
- 🚦 Route redirection support
|
|
17
|
+
- 🖼️ Layout-based route grouping
|
|
17
18
|
|
|
18
19
|
### 📦 Installation
|
|
19
20
|
|
|
@@ -52,6 +53,7 @@ export default defineConfig({
|
|
|
52
53
|
| Option | Type | Default | Description |
|
|
53
54
|
| --------------- | ---------- | ---------------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
54
55
|
| `pagesFolder` | `string` | `'src/pages'` | Path to pages folder |
|
|
56
|
+
| `layoutsFolder` | `string` | `'src/layouts'` | Path to layouts folder |
|
|
55
57
|
| `ignoreFolders` | `string[]` | `['components']` | Folders to ignore when generating routes |
|
|
56
58
|
| `routesPath` | `string` | Auto-detected | Path to generated routes file. Auto-detected based on `tsconfig.json` presence (`.ts` if exists, otherwise `.js`) |
|
|
57
59
|
| `nested` | `boolean` | `false` | Whether to generate nested routes |
|
|
@@ -119,7 +121,70 @@ defineOptions({
|
|
|
119
121
|
</script>
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
###
|
|
124
|
+
### �️ Layout Routes
|
|
125
|
+
|
|
126
|
+
Routes are automatically grouped by their `meta.layout` property and wrapped with a parent layout route:
|
|
127
|
+
|
|
128
|
+
- Routes with `meta.layout: false` will **not** be wrapped with a layout
|
|
129
|
+
- Routes without `meta.layout` will use the `'default'` layout by default
|
|
130
|
+
- Routes with `meta.layout: 'xxx'` will use the corresponding layout component from `layoutsFolder`
|
|
131
|
+
|
|
132
|
+
```vue
|
|
133
|
+
<!-- src/pages/login.vue - No layout wrapper -->
|
|
134
|
+
<script setup>
|
|
135
|
+
defineOptions({
|
|
136
|
+
name: 'Login',
|
|
137
|
+
meta: {
|
|
138
|
+
layout: false
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
</script>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```vue
|
|
145
|
+
<!-- src/pages/home.vue - Uses 'admin' layout -->
|
|
146
|
+
<script setup>
|
|
147
|
+
defineOptions({
|
|
148
|
+
name: 'Home',
|
|
149
|
+
meta: {
|
|
150
|
+
layout: 'admin'
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
</script>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Generated route structure example:**
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
[
|
|
160
|
+
// Routes with layout: false are not wrapped
|
|
161
|
+
{
|
|
162
|
+
name: 'Login',
|
|
163
|
+
path: '/login',
|
|
164
|
+
component: () => import('/src/pages/login.vue'),
|
|
165
|
+
meta: { layout: false }
|
|
166
|
+
},
|
|
167
|
+
// Routes are grouped by layout
|
|
168
|
+
{
|
|
169
|
+
name: 'LAYOUT_DEFAULT',
|
|
170
|
+
path: '/__layout_default__',
|
|
171
|
+
component: () => import('/src/layouts/default.vue'),
|
|
172
|
+
children: [
|
|
173
|
+
{ name: 'Index', path: '/' }
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: 'LAYOUT_ADMIN',
|
|
178
|
+
path: '/__layout_admin__',
|
|
179
|
+
component: () => import('/src/layouts/admin.vue'),
|
|
180
|
+
children: [
|
|
181
|
+
{ name: 'Home', path: '/home' }
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### �🚀 Complete Example
|
|
123
188
|
|
|
124
189
|
```javascript
|
|
125
190
|
import vue from '@vitejs/plugin-vue'
|
package/README.zh_CN.md
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
- 🎨 可自定义路由配置
|
|
15
15
|
- 🧩 支持通过`defineOptions`设置路由元数据
|
|
16
16
|
- 🚦 支持路由重定向
|
|
17
|
+
- 🖼️ 支持按布局分组路由
|
|
17
18
|
|
|
18
19
|
### 📦 安装
|
|
19
20
|
|
|
@@ -52,6 +53,7 @@ export default defineConfig({
|
|
|
52
53
|
| 选项 | 类型 | 默认值 | 描述 |
|
|
53
54
|
| --------------- | ---------- | ---------------- | ----------------------------------------------------------------------------------------- |
|
|
54
55
|
| `pagesFolder` | `string` | `'src/pages'` | 页面文件夹路径 |
|
|
56
|
+
| `layoutsFolder` | `string` | `'src/layouts'` | 布局组件文件夹路径 |
|
|
55
57
|
| `ignoreFolders` | `string[]` | `['components']` | 生成路由时忽略的文件夹 |
|
|
56
58
|
| `routesPath` | `string` | 自动检测 | 生成的路由文件路径,根据 `tsconfig.json` 是否存在自动检测(存在则为 `.ts`,否则为 `.js`) |
|
|
57
59
|
| `nested` | `boolean` | `false` | 是否生成嵌套路由 |
|
|
@@ -119,7 +121,70 @@ defineOptions({
|
|
|
119
121
|
</script>
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
###
|
|
124
|
+
### �️ 布局路由
|
|
125
|
+
|
|
126
|
+
路由会根据 `meta.layout` 属性自动分组,并包裹在对应的布局父级路由中:
|
|
127
|
+
|
|
128
|
+
- 设置 `meta.layout: false` 的路由**不会**被布局包裹
|
|
129
|
+
- 未设置 `meta.layout` 的路由默认使用 `'default'` 布局
|
|
130
|
+
- 设置 `meta.layout: 'xxx'` 的路由会使用 `layoutsFolder` 中对应的布局组件
|
|
131
|
+
|
|
132
|
+
```vue
|
|
133
|
+
<!-- src/pages/login.vue - 不使用布局包裹 -->
|
|
134
|
+
<script setup>
|
|
135
|
+
defineOptions({
|
|
136
|
+
name: 'Login',
|
|
137
|
+
meta: {
|
|
138
|
+
layout: false
|
|
139
|
+
}
|
|
140
|
+
})
|
|
141
|
+
</script>
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
```vue
|
|
145
|
+
<!-- src/pages/home.vue - 使用 'admin' 布局 -->
|
|
146
|
+
<script setup>
|
|
147
|
+
defineOptions({
|
|
148
|
+
name: 'Home',
|
|
149
|
+
meta: {
|
|
150
|
+
layout: 'admin'
|
|
151
|
+
}
|
|
152
|
+
})
|
|
153
|
+
</script>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**生成的路由结构示例:**
|
|
157
|
+
|
|
158
|
+
```javascript
|
|
159
|
+
[
|
|
160
|
+
// layout: false 的路由不会被包裹
|
|
161
|
+
{
|
|
162
|
+
name: 'Login',
|
|
163
|
+
path: '/login',
|
|
164
|
+
component: () => import('/src/pages/login.vue'),
|
|
165
|
+
meta: { layout: false }
|
|
166
|
+
},
|
|
167
|
+
// 路由按布局分组
|
|
168
|
+
{
|
|
169
|
+
name: 'LAYOUT_DEFAULT',
|
|
170
|
+
path: '/__layout_default__',
|
|
171
|
+
component: () => import('/src/layouts/default.vue'),
|
|
172
|
+
children: [
|
|
173
|
+
{ name: 'Index', path: '/' }
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
name: 'LAYOUT_ADMIN',
|
|
178
|
+
path: '/__layout_admin__',
|
|
179
|
+
component: () => import('/src/layouts/admin.vue'),
|
|
180
|
+
children: [
|
|
181
|
+
{ name: 'Home', path: '/home' }
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### �🚀 完整示例
|
|
123
188
|
|
|
124
189
|
```javascript
|
|
125
190
|
import vue from '@vitejs/plugin-vue'
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ interface RouteMeta {
|
|
|
12
12
|
requiresAuth?: boolean;
|
|
13
13
|
/** Whether the route is enabled */
|
|
14
14
|
enabled?: boolean;
|
|
15
|
+
/** Layout component name, false to disable layout wrapping */
|
|
16
|
+
layout?: string | false;
|
|
15
17
|
/** Custom properties */
|
|
16
18
|
[key: string]: unknown;
|
|
17
19
|
}
|
|
@@ -69,6 +71,12 @@ interface Options {
|
|
|
69
71
|
* @default src/pages
|
|
70
72
|
*/
|
|
71
73
|
pagesFolder: string;
|
|
74
|
+
/**
|
|
75
|
+
* layouts folder
|
|
76
|
+
*
|
|
77
|
+
* @default src/layouts
|
|
78
|
+
*/
|
|
79
|
+
layoutsFolder: string;
|
|
72
80
|
/**
|
|
73
81
|
* ignore folders, ignore these folders when generating routes
|
|
74
82
|
*
|
package/dist/index.js
CHANGED
|
@@ -66,6 +66,7 @@ function VitePluginGeneroutes(options = {}) {
|
|
|
66
66
|
let routesPath;
|
|
67
67
|
let isTypeScript;
|
|
68
68
|
const pagesFolder = options.pagesFolder || "src/pages";
|
|
69
|
+
const layoutsFolder = options.layoutsFolder || "src/layouts";
|
|
69
70
|
const ignoreFolders = options.ignoreFolders || ["components"];
|
|
70
71
|
const nested = options.nested || false;
|
|
71
72
|
const defineOptionsCache = /* @__PURE__ */ new Map();
|
|
@@ -100,10 +101,37 @@ function VitePluginGeneroutes(options = {}) {
|
|
|
100
101
|
console.warn(`Warning: Duplicate names found in routes: ${duplicateNames.join(", ")}`);
|
|
101
102
|
if (duplicatePaths.length)
|
|
102
103
|
console.warn(`Warning: Duplicate paths found in routes: ${duplicatePaths.join(", ")}`);
|
|
104
|
+
const processedRoutes = wrapRoutesWithLayout(nested ? convertToTree(routes) : routes);
|
|
103
105
|
return {
|
|
104
|
-
routes:
|
|
106
|
+
routes: processedRoutes
|
|
105
107
|
};
|
|
106
108
|
}
|
|
109
|
+
function wrapRoutesWithLayout(routes) {
|
|
110
|
+
const layoutGroups = /* @__PURE__ */ new Map();
|
|
111
|
+
const noLayoutRoutes = [];
|
|
112
|
+
for (const route of routes) {
|
|
113
|
+
const layout = route.meta?.layout;
|
|
114
|
+
if (layout === false) {
|
|
115
|
+
noLayoutRoutes.push(route);
|
|
116
|
+
} else {
|
|
117
|
+
const layoutName = layout || "default";
|
|
118
|
+
const group = layoutGroups.get(layoutName);
|
|
119
|
+
if (group) {
|
|
120
|
+
group.push(route);
|
|
121
|
+
} else {
|
|
122
|
+
layoutGroups.set(layoutName, [route]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const layoutRoutes = Array.from(layoutGroups, ([layoutName, children]) => ({
|
|
127
|
+
name: `LAYOUT_${layoutName.toUpperCase()}`,
|
|
128
|
+
path: `/__layout_${layoutName}__`,
|
|
129
|
+
component: `@@layout@@/${layoutsFolder}/${layoutName}.vue@@`,
|
|
130
|
+
meta: {},
|
|
131
|
+
children
|
|
132
|
+
}));
|
|
133
|
+
return [...noLayoutRoutes, ...layoutRoutes];
|
|
134
|
+
}
|
|
107
135
|
async function writerRoutesFile(isInit = false) {
|
|
108
136
|
const { routes } = generateMenusAndRoutes();
|
|
109
137
|
const typeDefinitions = isTypeScript ? `
|
|
@@ -148,6 +176,7 @@ export type GeneratedRoute = RouteRecordRaw & {
|
|
|
148
176
|
export const routes${routesType} = ${JSON.stringify(routes, null, 2)}
|
|
149
177
|
`;
|
|
150
178
|
routesStr = routesStr.replace(/"##(.*)##"/g, (_, p1) => `async () => ({...(await import('${p1.split("@@")[0]}')).default, name: '${p1.split("@@")[1]}'})`);
|
|
179
|
+
routesStr = routesStr.replace(/"@@layout@@(.*)@@"/g, (_, p1) => `() => import('${p1}')`);
|
|
151
180
|
const parser = isTypeScript ? "typescript" : "babel";
|
|
152
181
|
routesStr = await prettier.format(routesStr, { parser, semi: false, singleQuote: true });
|
|
153
182
|
const filePath = path.resolve(rootDir, routesPath);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-generoutes",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0-beta.1",
|
|
5
5
|
"packageManager": "pnpm@10.27.0",
|
|
6
6
|
"description": "A Vite plugin that generate routes based on the file structure, supports dynamic routes, and supports custom meta data for each route.",
|
|
7
7
|
"author": "Ronnie Zhang <zclzone@outlook.com>",
|