vite-plugin-generoutes 1.1.1 → 2.0.0-beta.2
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 +68 -5
- package/README.zh_CN.md +68 -5
- package/dist/index.d.ts +24 -44
- package/dist/index.js +40 -47
- 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,9 +53,9 @@ 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
|
-
| `nested` | `boolean` | `false` | Whether to generate nested routes |
|
|
58
59
|
|
|
59
60
|
### 📘 TypeScript Support
|
|
60
61
|
|
|
@@ -105,7 +106,7 @@ defineOptions({
|
|
|
105
106
|
|
|
106
107
|
### 🌲 Nested Routes
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
Use the `parent` property to set nested route relationships (handled automatically):
|
|
109
110
|
|
|
110
111
|
```vue
|
|
111
112
|
<script setup>
|
|
@@ -119,7 +120,70 @@ defineOptions({
|
|
|
119
120
|
</script>
|
|
120
121
|
```
|
|
121
122
|
|
|
122
|
-
###
|
|
123
|
+
### �️ Layout Routes
|
|
124
|
+
|
|
125
|
+
Routes are automatically grouped by their `meta.layout` property and wrapped with a parent layout route:
|
|
126
|
+
|
|
127
|
+
- Routes with `meta.layout: false` will **not** be wrapped with a layout
|
|
128
|
+
- Routes without `meta.layout` will use the `'default'` layout by default
|
|
129
|
+
- Routes with `meta.layout: 'xxx'` will use the corresponding layout component from `layoutsFolder`
|
|
130
|
+
|
|
131
|
+
```vue
|
|
132
|
+
<!-- src/pages/login.vue - No layout wrapper -->
|
|
133
|
+
<script setup>
|
|
134
|
+
defineOptions({
|
|
135
|
+
name: 'Login',
|
|
136
|
+
meta: {
|
|
137
|
+
layout: false
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
</script>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```vue
|
|
144
|
+
<!-- src/pages/home.vue - Uses 'admin' layout -->
|
|
145
|
+
<script setup>
|
|
146
|
+
defineOptions({
|
|
147
|
+
name: 'Home',
|
|
148
|
+
meta: {
|
|
149
|
+
layout: 'admin'
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
</script>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**Generated route structure example:**
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
[
|
|
159
|
+
// Routes with layout: false are not wrapped
|
|
160
|
+
{
|
|
161
|
+
name: 'Login',
|
|
162
|
+
path: '/login',
|
|
163
|
+
component: () => import('/src/pages/login.vue'),
|
|
164
|
+
meta: { layout: false }
|
|
165
|
+
},
|
|
166
|
+
// Routes are grouped by layout
|
|
167
|
+
{
|
|
168
|
+
name: 'LAYOUT_DEFAULT',
|
|
169
|
+
path: '/__layout_default__',
|
|
170
|
+
component: () => import('/src/layouts/default.vue'),
|
|
171
|
+
children: [
|
|
172
|
+
{ name: 'Index', path: '/' }
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'LAYOUT_ADMIN',
|
|
177
|
+
path: '/__layout_admin__',
|
|
178
|
+
component: () => import('/src/layouts/admin.vue'),
|
|
179
|
+
children: [
|
|
180
|
+
{ name: 'Home', path: '/home' }
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### �🚀 Complete Example
|
|
123
187
|
|
|
124
188
|
```javascript
|
|
125
189
|
import vue from '@vitejs/plugin-vue'
|
|
@@ -132,8 +196,7 @@ export default defineConfig({
|
|
|
132
196
|
generoutes({
|
|
133
197
|
pagesFolder: 'src/views',
|
|
134
198
|
ignoreFolders: ['components', 'assets'],
|
|
135
|
-
routesPath: 'src/router/routes.js'
|
|
136
|
-
nested: true
|
|
199
|
+
routesPath: 'src/router/routes.js'
|
|
137
200
|
})
|
|
138
201
|
]
|
|
139
202
|
})
|
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,9 +53,9 @@ 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
|
-
| `nested` | `boolean` | `false` | 是否生成嵌套路由 |
|
|
58
59
|
|
|
59
60
|
### 📘 TypeScript 支持
|
|
60
61
|
|
|
@@ -105,7 +106,7 @@ defineOptions({
|
|
|
105
106
|
|
|
106
107
|
### 🌲 嵌套路由
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
使用 `parent` 属性即可建立嵌套路由关系(无需额外开关,自动生效):
|
|
109
110
|
|
|
110
111
|
```vue
|
|
111
112
|
<script setup>
|
|
@@ -119,7 +120,70 @@ defineOptions({
|
|
|
119
120
|
</script>
|
|
120
121
|
```
|
|
121
122
|
|
|
122
|
-
###
|
|
123
|
+
### �️ 布局路由
|
|
124
|
+
|
|
125
|
+
路由会根据 `meta.layout` 属性自动分组,并包裹在对应的布局父级路由中:
|
|
126
|
+
|
|
127
|
+
- 设置 `meta.layout: false` 的路由**不会**被布局包裹
|
|
128
|
+
- 未设置 `meta.layout` 的路由默认使用 `'default'` 布局
|
|
129
|
+
- 设置 `meta.layout: 'xxx'` 的路由会使用 `layoutsFolder` 中对应的布局组件
|
|
130
|
+
|
|
131
|
+
```vue
|
|
132
|
+
<!-- src/pages/login.vue - 不使用布局包裹 -->
|
|
133
|
+
<script setup>
|
|
134
|
+
defineOptions({
|
|
135
|
+
name: 'Login',
|
|
136
|
+
meta: {
|
|
137
|
+
layout: false
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
</script>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
```vue
|
|
144
|
+
<!-- src/pages/home.vue - 使用 'admin' 布局 -->
|
|
145
|
+
<script setup>
|
|
146
|
+
defineOptions({
|
|
147
|
+
name: 'Home',
|
|
148
|
+
meta: {
|
|
149
|
+
layout: 'admin'
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
</script>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**生成的路由结构示例:**
|
|
156
|
+
|
|
157
|
+
```javascript
|
|
158
|
+
[
|
|
159
|
+
// layout: false 的路由不会被包裹
|
|
160
|
+
{
|
|
161
|
+
name: 'Login',
|
|
162
|
+
path: '/login',
|
|
163
|
+
component: () => import('/src/pages/login.vue'),
|
|
164
|
+
meta: { layout: false }
|
|
165
|
+
},
|
|
166
|
+
// 路由按布局分组
|
|
167
|
+
{
|
|
168
|
+
name: 'LAYOUT_DEFAULT',
|
|
169
|
+
path: '/__layout_default__',
|
|
170
|
+
component: () => import('/src/layouts/default.vue'),
|
|
171
|
+
children: [
|
|
172
|
+
{ name: 'Index', path: '/' }
|
|
173
|
+
]
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: 'LAYOUT_ADMIN',
|
|
177
|
+
path: '/__layout_admin__',
|
|
178
|
+
component: () => import('/src/layouts/admin.vue'),
|
|
179
|
+
children: [
|
|
180
|
+
{ name: 'Home', path: '/home' }
|
|
181
|
+
]
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### �🚀 完整示例
|
|
123
187
|
|
|
124
188
|
```javascript
|
|
125
189
|
import vue from '@vitejs/plugin-vue'
|
|
@@ -132,8 +196,7 @@ export default defineConfig({
|
|
|
132
196
|
generoutes({
|
|
133
197
|
pagesFolder: 'src/views',
|
|
134
198
|
ignoreFolders: ['components', 'assets'],
|
|
135
|
-
routesPath: 'src/router/routes.js'
|
|
136
|
-
nested: true
|
|
199
|
+
routesPath: 'src/router/routes.js'
|
|
137
200
|
})
|
|
138
201
|
],
|
|
139
202
|
})
|
package/dist/index.d.ts
CHANGED
|
@@ -1,39 +1,31 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
+
import { RouteRecordRaw } from 'vue-router';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Route meta information
|
|
5
6
|
*/
|
|
6
7
|
interface RouteMeta {
|
|
7
|
-
/**
|
|
8
|
+
/** Page title */
|
|
8
9
|
title?: string;
|
|
9
|
-
/**
|
|
10
|
+
/** Page icon */
|
|
10
11
|
icon?: string;
|
|
12
|
+
/** Page code */
|
|
13
|
+
code?: string;
|
|
14
|
+
/** Page layout */
|
|
15
|
+
layout?: string | false;
|
|
11
16
|
/** Whether authentication is required */
|
|
12
|
-
|
|
17
|
+
requireAuth?: boolean;
|
|
18
|
+
/** Whether to keep alive */
|
|
19
|
+
keepAlive?: boolean;
|
|
13
20
|
/** Whether the route is enabled */
|
|
14
21
|
enabled?: boolean;
|
|
22
|
+
/** Whether it's the home page */
|
|
23
|
+
isHome?: boolean;
|
|
24
|
+
/** Whether it's a login page */
|
|
25
|
+
isLogin?: boolean;
|
|
15
26
|
/** Custom properties */
|
|
16
27
|
[key: string]: unknown;
|
|
17
28
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Internal route representation used during generation
|
|
20
|
-
*/
|
|
21
|
-
interface InternalRoute {
|
|
22
|
-
/** Route name */
|
|
23
|
-
name: string;
|
|
24
|
-
/** Route path */
|
|
25
|
-
path: string;
|
|
26
|
-
/** Redirect path */
|
|
27
|
-
redirect?: string;
|
|
28
|
-
/** Route component placeholder */
|
|
29
|
-
component?: string;
|
|
30
|
-
/** Route meta information */
|
|
31
|
-
meta: RouteMeta;
|
|
32
|
-
/** Parent route name (for nested routes) */
|
|
33
|
-
parent?: string;
|
|
34
|
-
/** Child routes */
|
|
35
|
-
children?: InternalRoute[];
|
|
36
|
-
}
|
|
37
29
|
|
|
38
30
|
/**********************************
|
|
39
31
|
* @Author: Ronnie Zhang
|
|
@@ -46,22 +38,10 @@ interface InternalRoute {
|
|
|
46
38
|
/**
|
|
47
39
|
* Generated route record with proper typing for vue-router
|
|
48
40
|
*/
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
name: string;
|
|
52
|
-
/** Route path */
|
|
53
|
-
path: string;
|
|
54
|
-
/** Redirect path */
|
|
55
|
-
redirect?: string;
|
|
56
|
-
/** Route component */
|
|
57
|
-
component?: () => Promise<any>;
|
|
58
|
-
/** Route meta information */
|
|
59
|
-
meta: RouteMeta;
|
|
60
|
-
/** Parent route name (for nested routes) */
|
|
61
|
-
parent?: string;
|
|
62
|
-
/** Child routes */
|
|
41
|
+
type GeneratedRoute = RouteRecordRaw & {
|
|
42
|
+
meta?: RouteMeta;
|
|
63
43
|
children?: GeneratedRoute[];
|
|
64
|
-
}
|
|
44
|
+
};
|
|
65
45
|
interface Options {
|
|
66
46
|
/**
|
|
67
47
|
* pages folder
|
|
@@ -69,6 +49,12 @@ interface Options {
|
|
|
69
49
|
* @default src/pages
|
|
70
50
|
*/
|
|
71
51
|
pagesFolder: string;
|
|
52
|
+
/**
|
|
53
|
+
* layouts folder
|
|
54
|
+
*
|
|
55
|
+
* @default src/layouts
|
|
56
|
+
*/
|
|
57
|
+
layoutsFolder: string;
|
|
72
58
|
/**
|
|
73
59
|
* ignore folders, ignore these folders when generating routes
|
|
74
60
|
*
|
|
@@ -82,13 +68,7 @@ interface Options {
|
|
|
82
68
|
* @default src/router/routes.ts (if tsconfig.json exists) or src/router/routes.js
|
|
83
69
|
*/
|
|
84
70
|
routesPath: string;
|
|
85
|
-
/**
|
|
86
|
-
* nested routes
|
|
87
|
-
*
|
|
88
|
-
* @default false
|
|
89
|
-
*/
|
|
90
|
-
nested: boolean;
|
|
91
71
|
}
|
|
92
72
|
declare function VitePluginGeneroutes(options?: Partial<Options>): Plugin;
|
|
93
73
|
|
|
94
|
-
export { type GeneratedRoute, type
|
|
74
|
+
export { type GeneratedRoute, type Options, type RouteMeta, VitePluginGeneroutes, VitePluginGeneroutes as default };
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ function toPascalCase(str) {
|
|
|
13
13
|
return p1.toUpperCase();
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
|
-
function
|
|
16
|
+
function nestRoutes(routes) {
|
|
17
17
|
const nodeMap = {};
|
|
18
18
|
const result = [];
|
|
19
19
|
routes.forEach((route) => {
|
|
@@ -66,80 +66,72 @@ 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
|
-
const nested = options.nested || false;
|
|
71
71
|
const defineOptionsCache = /* @__PURE__ */ new Map();
|
|
72
72
|
function detectTypeScriptProject() {
|
|
73
73
|
const tsconfigPath = path.resolve(rootDir, "tsconfig.json");
|
|
74
74
|
return fs.existsSync(tsconfigPath);
|
|
75
75
|
}
|
|
76
|
-
function
|
|
76
|
+
function generateRoutes() {
|
|
77
77
|
const pages = globSync(`${pagesFolder}/**/*.vue`, { ignore: ignoreFolders.map((folder) => `${pagesFolder}/**/${folder}/**`) });
|
|
78
|
-
const routes =
|
|
78
|
+
const routes = [];
|
|
79
|
+
for (let filePath of pages) {
|
|
79
80
|
filePath = slash(filePath);
|
|
80
81
|
const defineOptions = parseDefineOptions(filePath) || {};
|
|
81
82
|
defineOptionsCache.set(filePath, JSON.stringify(defineOptions));
|
|
82
83
|
const meta = defineOptions.meta || {};
|
|
83
84
|
if (meta.enabled === false)
|
|
84
|
-
|
|
85
|
+
continue;
|
|
85
86
|
const pathSegments = filePath.replace(`${pagesFolder}`, "").replace(".vue", "").replace("index", "").split("/").filter((item) => !!item && !/^\(.*\)$/.test(item));
|
|
86
87
|
const name = defineOptions.name || pathSegments.map((item) => toPascalCase(item)).join("_") || "Index";
|
|
87
88
|
const component = `##/${filePath}@@${name}##`;
|
|
88
89
|
const routePath = `/${pathSegments.map((item) => item.replace(/\[(.*?)\]/g, (_, p1) => p1 === "...all" ? ":pathMatch(.*)*" : p1.split(",").map((i) => `:${i}`).join("/"))).join("/")}`;
|
|
89
|
-
|
|
90
|
+
routes.push({
|
|
90
91
|
name,
|
|
91
92
|
path: routePath,
|
|
92
93
|
redirect: defineOptions.redirect,
|
|
94
|
+
parent: defineOptions.parent,
|
|
93
95
|
component: defineOptions.redirect ? void 0 : component,
|
|
94
|
-
meta
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
}).filter((route) => route !== null);
|
|
96
|
+
meta
|
|
97
|
+
});
|
|
98
|
+
}
|
|
98
99
|
const { duplicateNames, duplicatePaths } = findDuplicateRoutes(routes);
|
|
99
100
|
if (duplicateNames.length)
|
|
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(", ")}`);
|
|
103
|
-
return
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
return wrapRoutesWithLayout(nestRoutes(routes));
|
|
105
|
+
}
|
|
106
|
+
function wrapRoutesWithLayout(routes) {
|
|
107
|
+
const layoutGroups = /* @__PURE__ */ new Map();
|
|
108
|
+
const noLayoutRoutes = [];
|
|
109
|
+
for (const route of routes) {
|
|
110
|
+
const layout = route.meta?.layout;
|
|
111
|
+
if (layout === false) {
|
|
112
|
+
noLayoutRoutes.push(route);
|
|
113
|
+
} else {
|
|
114
|
+
const layoutName = layout || "default";
|
|
115
|
+
const group = layoutGroups.get(layoutName);
|
|
116
|
+
if (group) {
|
|
117
|
+
group.push(route);
|
|
118
|
+
} else {
|
|
119
|
+
layoutGroups.set(layoutName, [route]);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const layoutRoutes = Array.from(layoutGroups, ([layoutName, children]) => ({
|
|
124
|
+
name: `__LAYOUT_${layoutName.toUpperCase()}__`,
|
|
125
|
+
path: `/__layout_${layoutName}__`,
|
|
126
|
+
component: `@@layout@@/${layoutsFolder}/${layoutName}.vue@@`,
|
|
127
|
+
children
|
|
128
|
+
}));
|
|
129
|
+
return layoutRoutes.concat(noLayoutRoutes);
|
|
106
130
|
}
|
|
107
131
|
async function writerRoutesFile(isInit = false) {
|
|
108
|
-
const
|
|
132
|
+
const routes = generateRoutes();
|
|
109
133
|
const typeDefinitions = isTypeScript ? `
|
|
110
|
-
import type {
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* Route meta information
|
|
114
|
-
*/
|
|
115
|
-
export interface RouteMeta {
|
|
116
|
-
/** Page title */
|
|
117
|
-
title?: string
|
|
118
|
-
/** Page icon */
|
|
119
|
-
icon?: string
|
|
120
|
-
/** Page code */
|
|
121
|
-
code?: string
|
|
122
|
-
/** Page layout */
|
|
123
|
-
layout?: string | false
|
|
124
|
-
/** Whether authentication is required */
|
|
125
|
-
requireAuth?: boolean
|
|
126
|
-
/** Whether to keep alive */
|
|
127
|
-
keepAlive?: boolean
|
|
128
|
-
/** Whether it's the home page */
|
|
129
|
-
isHome?: boolean
|
|
130
|
-
/** Whether it's a login page */
|
|
131
|
-
isLogin?: boolean
|
|
132
|
-
/** Custom properties */
|
|
133
|
-
[key: string]: unknown
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Generated route type with proper typing
|
|
138
|
-
*/
|
|
139
|
-
export type GeneratedRoute = RouteRecordRaw & {
|
|
140
|
-
meta?: RouteMeta
|
|
141
|
-
children?: GeneratedRoute[]
|
|
142
|
-
}
|
|
134
|
+
import type { GeneratedRoute } from 'vite-plugin-generoutes'
|
|
143
135
|
` : "";
|
|
144
136
|
const routesType = isTypeScript ? ": GeneratedRoute[]" : "";
|
|
145
137
|
let routesStr = `
|
|
@@ -148,6 +140,7 @@ export type GeneratedRoute = RouteRecordRaw & {
|
|
|
148
140
|
export const routes${routesType} = ${JSON.stringify(routes, null, 2)}
|
|
149
141
|
`;
|
|
150
142
|
routesStr = routesStr.replace(/"##(.*)##"/g, (_, p1) => `async () => ({...(await import('${p1.split("@@")[0]}')).default, name: '${p1.split("@@")[1]}'})`);
|
|
143
|
+
routesStr = routesStr.replace(/"@@layout@@(.*)@@"/g, (_, p1) => `() => import('${p1}')`);
|
|
151
144
|
const parser = isTypeScript ? "typescript" : "babel";
|
|
152
145
|
routesStr = await prettier.format(routesStr, { parser, semi: false, singleQuote: true });
|
|
153
146
|
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.2",
|
|
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>",
|