vite-plugin-generoutes 0.2.1 → 0.2.4

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 CHANGED
@@ -1,135 +1,135 @@
1
- # vite-plugin-generoutes
2
-
3
- A Vite plugin that generates routes based on the file structure, supports dynamic routes, and supports custom meta data for each route.
4
-
5
- ## Usage
6
-
7
- 1. Install the plugin:
8
-
9
- ```bash
10
- npm install vite-plugin-generoutes
11
- ```
12
-
13
- 2. Add the plugin to your `vite.config.js`:
14
-
15
- ```js
16
- import { defineConfig } from 'vite'
17
- import generoutes from 'vite-plugin-generoutes'
18
-
19
- export default defineConfig({
20
- plugins: [
21
- generoutes()
22
- // ... other plugins
23
- ]
24
- })
25
- ```
26
-
27
- 3. Create your page files(`index.vue` or `[...all].vue`) in the `src/pages` directory. Each file in this directory will be treated as a route.
28
-
29
- ```
30
- src/routes/pages
31
- ├── index.vue
32
- ├── [...all].vue
33
- ├── user/
34
- │ ├── index.vue
35
- │ ├── [id]
36
- │ │ └── index.vue
37
- └── post
38
- ├── index.vue
39
- └── [...all].vue
40
- ```
41
-
42
- The above example will generate the routes file `src/router/generoutes/index.js` with the following content:
43
- ```js
44
- export const routes = [
45
- {
46
- name: 'Index',
47
- path: '/',
48
- component: () => import('/src/pages/index.vue'),
49
- meta: {
50
- title: 'Index',
51
- show: true,
52
- keepAlive: false,
53
- },
54
- },
55
- {
56
- name: 'User',
57
- path: '/user',
58
- component: () => import('/src/pages/user/index.vue'),
59
- meta: {
60
- title: 'User',
61
- show: true,
62
- keepAlive: false,
63
- },
64
- },
65
- {
66
- name: 'User_[id]',
67
- path: '/user/:id',
68
- component: () => import('/src/pages/user/[id]/index.vue'),
69
- meta: {
70
- title: 'User_[id]',
71
- show: true,
72
- keepAlive: false,
73
- },
74
- },
75
- {
76
- name: 'User_Post',
77
- path: '/user/post',
78
- component: () => import('/src/pages/user/post/index.vue'),
79
- meta: {
80
- title: 'User_Post',
81
- show: true,
82
- keepAlive: false,
83
- },
84
- },
85
- {
86
- name: 'Index_[...all]',
87
- path: '/:pathMatch(.*)*',
88
- component: () => import('/src/pages/[...all].vue'),
89
- meta: {
90
- title: '404 Not Found',
91
- show: true,
92
- keepAlive: false,
93
- },
94
- },
95
- {
96
- name: 'User_Post_[...all]',
97
- path: '/user/post/:pathMatch(.*)*',
98
- component: () => import('/src/pages/user/post/[...all].vue'),
99
- meta: {
100
- title: 'User_Post_[...all]',
101
- show: true,
102
- keepAlive: false,
103
- },
104
- },
105
- ]
106
- ```
107
-
108
- 4. Import the generated routes and create a router instance:
109
-
110
- ```js
111
- import { createRouter, createWebHashHistory } from 'vue-router'
112
- import { routes } from './generoutes'
113
-
114
- const router = createRouter({
115
- history: createWebHashHistory(),
116
- routes,
117
- })
118
-
119
- export default router
120
- ```
121
-
122
- ## Features
123
-
124
- - Generate routes based on the file structure.
125
- - Support dynamic routes.
126
- - Support multiple NotFound routes.
127
- - Support custom meta data for each route.
128
- - Support ghost paths, For example, the (admin) folder will not be part of the route path, which is very useful for folder grouping.
129
- - Support immediate update of the routes file when the file structure or defineOptions changes.
130
-
131
- ## Custom route info,including name and meta
132
-
133
- You can define `name` and `meta` fields in the `defineOptions` of your `.vue` file, which will be used to override the default properties of the generated route. The `name` field will be used as the route name, which is very useful for `KeepAlive`. Any property in `defineOptions.meta` will be used as a property of the route `meta`, which makes the route metadata very flexible.
134
-
135
- When you make any changes that may affect the route result, the `src/router/generoutes/index.js` file will be updated immediately, and the page will be refreshed without restarting the server.
1
+ # vite-plugin-generoutes
2
+
3
+ A Vite plugin that generates routes based on the file structure, supports dynamic routes, and supports custom meta data for each route.
4
+
5
+ ## Usage
6
+
7
+ 1. Install the plugin:
8
+
9
+ ```bash
10
+ npm install vite-plugin-generoutes
11
+ ```
12
+
13
+ 2. Add the plugin to your `vite.config.js`:
14
+
15
+ ```js
16
+ import { defineConfig } from 'vite'
17
+ import generoutes from 'vite-plugin-generoutes'
18
+
19
+ export default defineConfig({
20
+ plugins: [
21
+ generoutes()
22
+ // ... other plugins
23
+ ]
24
+ })
25
+ ```
26
+
27
+ 3. Create your page files(`index.vue` or `[...all].vue`) in the `src/pages` directory. Each file in this directory will be treated as a route.
28
+
29
+ ```
30
+ src/routes/pages
31
+ ├── index.vue
32
+ ├── [...all].vue
33
+ ├── user/
34
+ │ ├── index.vue
35
+ │ ├── [id]
36
+ │ │ └── index.vue
37
+ └── post
38
+ ├── index.vue
39
+ └── [...all].vue
40
+ ```
41
+
42
+ The above example will generate the routes file `src/router/generoutes/index.js` with the following content:
43
+ ```js
44
+ export const routes = [
45
+ {
46
+ name: 'Index',
47
+ path: '/',
48
+ component: () => import('/src/pages/index.vue'),
49
+ meta: {
50
+ title: 'Index',
51
+ show: true,
52
+ keepAlive: false,
53
+ },
54
+ },
55
+ {
56
+ name: 'User',
57
+ path: '/user',
58
+ component: () => import('/src/pages/user/index.vue'),
59
+ meta: {
60
+ title: 'User',
61
+ show: true,
62
+ keepAlive: false,
63
+ },
64
+ },
65
+ {
66
+ name: 'User_[id]',
67
+ path: '/user/:id',
68
+ component: () => import('/src/pages/user/[id]/index.vue'),
69
+ meta: {
70
+ title: 'User_[id]',
71
+ show: true,
72
+ keepAlive: false,
73
+ },
74
+ },
75
+ {
76
+ name: 'User_Post',
77
+ path: '/user/post',
78
+ component: () => import('/src/pages/user/post/index.vue'),
79
+ meta: {
80
+ title: 'User_Post',
81
+ show: true,
82
+ keepAlive: false,
83
+ },
84
+ },
85
+ {
86
+ name: 'Index_[...all]',
87
+ path: '/:pathMatch(.*)*',
88
+ component: () => import('/src/pages/[...all].vue'),
89
+ meta: {
90
+ title: '404 Not Found',
91
+ show: true,
92
+ keepAlive: false,
93
+ },
94
+ },
95
+ {
96
+ name: 'User_Post_[...all]',
97
+ path: '/user/post/:pathMatch(.*)*',
98
+ component: () => import('/src/pages/user/post/[...all].vue'),
99
+ meta: {
100
+ title: 'User_Post_[...all]',
101
+ show: true,
102
+ keepAlive: false,
103
+ },
104
+ },
105
+ ]
106
+ ```
107
+
108
+ 4. Import the generated routes and create a router instance:
109
+
110
+ ```js
111
+ import { createRouter, createWebHashHistory } from 'vue-router'
112
+ import { routes } from './generoutes'
113
+
114
+ const router = createRouter({
115
+ history: createWebHashHistory(),
116
+ routes,
117
+ })
118
+
119
+ export default router
120
+ ```
121
+
122
+ ## Features
123
+
124
+ - Generate routes based on the file structure.
125
+ - Support dynamic routes.
126
+ - Support multiple NotFound routes.
127
+ - Support custom meta data for each route.
128
+ - Support ghost paths, For example, the (admin) folder will not be part of the route path, which is very useful for folder grouping.
129
+ - Support immediate update of the routes file when the file structure or defineOptions changes.
130
+
131
+ ## Custom route info,including name and meta
132
+
133
+ You can define `name` and `meta` fields in the `defineOptions` of your `.vue` file, which will be used to override the default properties of the generated route. The `name` field will be used as the route name, which is very useful for `KeepAlive`. Any property in `defineOptions.meta` will be used as a property of the route `meta`, which makes the route metadata very flexible.
134
+
135
+ When you make any changes that may affect the route result, the `src/router/generoutes/index.js` file will be updated immediately, and the page will be refreshed without restarting the server.
package/dist/index.d.ts CHANGED
@@ -15,6 +15,12 @@ interface Options {
15
15
  * default: `src/pages`
16
16
  */
17
17
  pagesFolder: string;
18
+ /**
19
+ * 忽略文件夹
20
+ *
21
+ * default: `['components']`
22
+ */
23
+ ignoreFolders: string[];
18
24
  /**
19
25
  * 路由文件路径
20
26
  *
package/dist/index.js CHANGED
@@ -35,10 +35,33 @@ function convertToTree(routes) {
35
35
  });
36
36
  return result;
37
37
  }
38
+ function findDuplicateRoutes(routes) {
39
+ const nameSet = /* @__PURE__ */ new Set();
40
+ const pathSet = /* @__PURE__ */ new Set();
41
+ const duplicateNames = [];
42
+ const duplicatePaths = [];
43
+ for (const route of routes) {
44
+ if (nameSet.has(route.name)) {
45
+ duplicateNames.push(route.name);
46
+ } else {
47
+ nameSet.add(route.name);
48
+ }
49
+ if (pathSet.has(route.path)) {
50
+ duplicatePaths.push(route.path);
51
+ } else {
52
+ pathSet.add(route.path);
53
+ }
54
+ }
55
+ return {
56
+ duplicateNames,
57
+ duplicatePaths
58
+ };
59
+ }
38
60
 
39
61
  // src/index.ts
40
62
  var defaultOptions = {
41
63
  pagesFolder: "src/pages",
64
+ ignoreFolders: ["components"],
42
65
  nested: false
43
66
  };
44
67
  function VitePluginGeneroutes(options = {}) {
@@ -48,9 +71,10 @@ function VitePluginGeneroutes(options = {}) {
48
71
  const pagesFolder = options.pagesFolder || defaultOptions.pagesFolder;
49
72
  const routesPath = options.routesPath || path.join(pagesFolder, "generoutes.js");
50
73
  const nested = options.nested || defaultOptions.nested;
74
+ const ignoreFolders = options.ignoreFolders || defaultOptions.ignoreFolders;
51
75
  const defineOptionsCache = /* @__PURE__ */ new Map();
52
76
  function generateMenusAndRoutes() {
53
- const pages = globSync(`${pagesFolder}/**/index.vue`).concat(globSync(`${pagesFolder}/**/\\[...all\\].vue`));
77
+ const pages = globSync(`${pagesFolder}/**/*.vue`, { ignore: ignoreFolders.map((folder) => `${pagesFolder}/**/${folder}/**`) });
54
78
  const routes = pages.map((filePath) => {
55
79
  filePath = slash(filePath);
56
80
  const defineOptions = parseDefineOptions(filePath) || {};
@@ -58,20 +82,10 @@ function VitePluginGeneroutes(options = {}) {
58
82
  const meta = defineOptions?.meta || {};
59
83
  if (meta.enabled === false)
60
84
  return null;
61
- const fileName = path.basename(filePath);
62
- const pathSegments = path.dirname(filePath).replace(`${pagesFolder}`, "").split("/").filter((item) => !!item && !/^\(.*\)$/.test(item));
63
- let name = defineOptions?.name || pathSegments.map((item) => toPascalCase(item)).join("_") || "Index";
85
+ const pathSegments = filePath.replace(`${pagesFolder}`, "").replace(".vue", "").replace("index", "").split("/").filter((item) => !!item && !/^\(.*\)$/.test(item));
86
+ const name = defineOptions?.name || pathSegments.map((item) => toPascalCase(item)).join("_") || "Index";
64
87
  const component = `##/${filePath}##`;
65
- let routePath = `/${pathSegments.map((item) => item.replace(/\[(.*?)\]/g, (_, p1) => p1.split(",").map((i) => `:${i}`).join("/"))).join("/")}`;
66
- if (fileName === "[...all].vue") {
67
- name = `${name}_[...all]`;
68
- routePath = routePath === "/" ? "/:pathMatch(.*)*" : `${routePath}/:pathMatch(.*)*`;
69
- }
70
- if (!("title" in meta))
71
- meta.title = name;
72
- if (!("show" in meta))
73
- meta.show = true;
74
- meta.keepAlive = !!defineOptions?.name && meta.keepAlive !== false;
88
+ const routePath = `/${pathSegments.map((item) => item.replace(/\[(.*?)\]/g, (_, p1) => p1 === "...all" ? ":pathMatch(.*)*" : p1.split(",").map((i) => `:${i}`).join("/"))).join("/")}`;
75
89
  return {
76
90
  name,
77
91
  path: routePath,
@@ -80,6 +94,11 @@ function VitePluginGeneroutes(options = {}) {
80
94
  parent: defineOptions?.parent
81
95
  };
82
96
  }).filter(Boolean);
97
+ const { duplicateNames, duplicatePaths } = findDuplicateRoutes(routes);
98
+ if (duplicateNames.length)
99
+ console.warn(`Warning: Duplicate names found in routes: ${duplicateNames.join(", ")}`);
100
+ if (duplicatePaths.length)
101
+ console.warn(`Warning: Duplicate paths found in routes: ${duplicatePaths.join(", ")}`);
83
102
  return {
84
103
  routes: nested ? convertToTree(routes) : routes
85
104
  };
@@ -100,9 +119,11 @@ function VitePluginGeneroutes(options = {}) {
100
119
  }
101
120
  const debounceWriter = debounce(500, writerRoutesFile);
102
121
  function createWatcher() {
103
- const watcher = chokidar.watch([`${pagesFolder}/**/index.vue`, `${pagesFolder}/**/[...all].vue`], { ignoreInitial: true });
122
+ const watcher = chokidar.watch(`${pagesFolder}/**/*.vue`, { ignoreInitial: true });
104
123
  return watcher.on("all", async (event, path2) => {
105
- if ((path2.endsWith("index.vue") || path2.endsWith("[...all].vue")) && (event === "add" || event === "unlink")) {
124
+ if (ignoreFolders.some((folder) => slash(path2).includes(`/${folder}/`)))
125
+ return;
126
+ if (path2.endsWith(".vue") && (event === "add" || event === "unlink")) {
106
127
  debounceWriter();
107
128
  await watcher.close();
108
129
  createWatcher();
@@ -117,15 +138,11 @@ function VitePluginGeneroutes(options = {}) {
117
138
  config.command !== "build" && createWatcher();
118
139
  },
119
140
  async handleHotUpdate({ file, read }) {
120
- if (file.includes(pagesFolder) && (file.endsWith("index.vue") || file.endsWith("[...all].vue"))) {
141
+ if (file.includes(pagesFolder) && !ignoreFolders.some((folder) => file.includes(`/${folder}/`)) && file.endsWith(".vue")) {
121
142
  const prevDefineOptions = defineOptionsCache.get(slash(path.relative(rootDir, file)));
122
- if (!prevDefineOptions) {
143
+ const defineOptions = JSON.stringify(parseDefineOptions(file, await read()));
144
+ if (prevDefineOptions !== defineOptions) {
123
145
  debounceWriter();
124
- } else {
125
- const defineOptions = JSON.stringify(parseDefineOptions(file, await read()));
126
- if (prevDefineOptions !== defineOptions) {
127
- debounceWriter();
128
- }
129
146
  }
130
147
  }
131
148
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vite-plugin-generoutes",
3
3
  "type": "module",
4
- "version": "0.2.1",
4
+ "version": "0.2.4",
5
5
  "packageManager": "pnpm@9.1.1",
6
6
  "description": "_description_",
7
7
  "author": "Ronnie Zhang <zclzone@outlook.com>",