vite-plugin-generoutes 0.2.0 → 0.2.3

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/dist/index.d.ts CHANGED
@@ -10,13 +10,29 @@ import { Plugin } from 'vite';
10
10
 
11
11
  interface Options {
12
12
  /**
13
- * default: `src/router/pages`
13
+ * pages 文件夹
14
+ *
15
+ * default: `src/pages`
14
16
  */
15
17
  pagesFolder: string;
16
18
  /**
17
- * default: `src/router/generoutes.js`
19
+ * 忽略文件夹
20
+ *
21
+ * default: `['components']`
22
+ */
23
+ ignoreFolders: string[];
24
+ /**
25
+ * 路由文件路径
26
+ *
27
+ * default: `${pagesFolder}/generoutes.js`
18
28
  */
19
29
  routesPath?: string;
30
+ /**
31
+ * 是否嵌套
32
+ *
33
+ * default: false
34
+ */
35
+ nested: boolean;
20
36
  }
21
37
  declare function VitePluginGeneroutes(options?: Partial<Options>): Plugin<any>;
22
38
 
package/dist/index.js CHANGED
@@ -6,52 +6,86 @@ import { parse } from "@vue/compiler-sfc";
6
6
  import { debounce, slash } from "@antfu/utils";
7
7
  import chokidar from "chokidar";
8
8
  import prettier from "prettier";
9
+
10
+ // src/utils.ts
9
11
  function toPascalCase(str) {
10
12
  return str.toLowerCase().replace(/(?:^|-)([a-z])/g, (_, p1) => {
11
13
  return p1.toUpperCase();
12
14
  });
13
15
  }
16
+ function convertToTree(routes) {
17
+ const nodeMap = {};
18
+ const result = [];
19
+ routes.forEach((route) => {
20
+ const { parent, ...node } = route;
21
+ nodeMap[node.name] = node;
22
+ });
23
+ routes.forEach((route) => {
24
+ if (route.parent) {
25
+ const parentNode = nodeMap[route.parent];
26
+ if (parentNode) {
27
+ if (!parentNode.children) {
28
+ parentNode.children = [];
29
+ }
30
+ parentNode.children.push(nodeMap[route.name]);
31
+ }
32
+ } else {
33
+ result.push(nodeMap[route.name]);
34
+ }
35
+ });
36
+ return result;
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
+ }
60
+
61
+ // src/index.ts
14
62
  var defaultOptions = {
15
- pagesFolder: "src/pages"
63
+ pagesFolder: "src/pages",
64
+ ignoreFolders: ["components"],
65
+ nested: false
16
66
  };
17
67
  function VitePluginGeneroutes(options = {}) {
18
68
  if (options.routesPath && ![".ts", ".js"].includes(path.extname(options.routesPath)))
19
69
  throw new Error("routesPath must be a js or ts file path, such as src/router/generoutes.js");
20
- const defineOptionsCache = /* @__PURE__ */ new Map();
21
70
  let rootDir;
22
71
  const pagesFolder = options.pagesFolder || defaultOptions.pagesFolder;
23
- const routesPath = options.routesPath || path.resolve(pagesFolder, "generoutes.js");
24
- async function writerRoutesFile() {
25
- const { routes } = generateMenusAndRoutes();
26
- let routesStr = `
27
- // ! \u6B64\u6587\u4EF6\u7531 vite-plugin-generoutes \u81EA\u52A8\u751F\u6210\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u5230 .gitignore\uFF0C\u8BF7\u52FF\u76F4\u63A5\u5728\u6B64\u6587\u4EF6\u4FEE\u6539!!!
28
- // ! This file is generated by vite-plugin-generoutes, it is recommended to add it to .gitignore, do not modify it directly in this file!!!
29
-
30
- export const routes = ${JSON.stringify(routes, null, 2)}
31
- `;
32
- routesStr = routesStr.replace(/"##(.*)##"/g, (_, p1) => `() => import('${p1}')`);
33
- routesStr = await prettier.format(routesStr, { parser: "babel", semi: false, singleQuote: true });
34
- fs.writeFileSync(`${path.resolve(rootDir, routesPath)}`, routesStr);
35
- }
36
- const debounceWriter = debounce(500, writerRoutesFile);
72
+ const routesPath = options.routesPath || path.join(pagesFolder, "generoutes.js");
73
+ const nested = options.nested || defaultOptions.nested;
74
+ const ignoreFolders = options.ignoreFolders || defaultOptions.ignoreFolders;
75
+ const defineOptionsCache = /* @__PURE__ */ new Map();
37
76
  function generateMenusAndRoutes() {
38
- const pages = globSync(`${pagesFolder}/**/index.vue`).concat(globSync(`${pagesFolder}/**/\\[...all\\].vue`));
77
+ const pages = globSync(`${pagesFolder}/**/*.vue`, { ignore: ignoreFolders.map((folder) => `${pagesFolder}/**/${folder}/**`) });
39
78
  const routes = pages.map((filePath) => {
40
79
  filePath = slash(filePath);
41
- const defineOptions = parseDefineOptions(filePath);
80
+ const defineOptions = parseDefineOptions(filePath) || {};
42
81
  defineOptionsCache.set(filePath, JSON.stringify(defineOptions));
43
82
  const meta = defineOptions?.meta || {};
44
83
  if (meta.enabled === false)
45
84
  return null;
46
- const fileName = path.basename(filePath);
47
- const pathSegments = path.dirname(filePath).replace(`${pagesFolder}`, "").split("/").filter((item) => !!item && !/^\(.*\)$/.test(item));
48
- 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";
49
87
  const component = `##/${filePath}##`;
50
- let routePath = `/${pathSegments.map((item) => item.replace(/\[(.*?)\]/g, (_, p1) => p1.split(",").map((i) => `:${i}`).join("/"))).join("/")}`;
51
- if (fileName === "[...all].vue") {
52
- name = `${name}_[...all]`;
53
- routePath = routePath === "/" ? "/:pathMatch(.*)*" : `${routePath}/:pathMatch(.*)*`;
54
- }
88
+ const routePath = `/${pathSegments.map((item) => item.replace(/\[(.*?)\]/g, (_, p1) => p1 === "...all" ? ":pathMatch(.*)*" : p1.split(",").map((i) => `:${i}`).join("/"))).join("/")}`;
55
89
  if (!("title" in meta))
56
90
  meta.title = name;
57
91
  if (!("show" in meta))
@@ -61,17 +95,40 @@ function VitePluginGeneroutes(options = {}) {
61
95
  name,
62
96
  path: routePath,
63
97
  component,
64
- meta
98
+ meta,
99
+ parent: defineOptions?.parent
65
100
  };
66
101
  }).filter(Boolean);
102
+ const { duplicateNames, duplicatePaths } = findDuplicateRoutes(routes);
103
+ if (duplicateNames.length)
104
+ console.warn(`Warning: Duplicate names found in routes: ${duplicateNames.join(", ")}`);
105
+ if (duplicatePaths.length)
106
+ console.warn(`Warning: Duplicate paths found in routes: ${duplicatePaths.join(", ")}`);
67
107
  return {
68
- routes
108
+ routes: nested ? convertToTree(routes) : routes
69
109
  };
70
110
  }
111
+ async function writerRoutesFile() {
112
+ const { routes } = generateMenusAndRoutes();
113
+ let routesStr = `
114
+ // ! \u6B64\u6587\u4EF6\u7531 vite-plugin-generoutes \u81EA\u52A8\u751F\u6210\uFF0C\u5EFA\u8BAE\u6DFB\u52A0\u5230 .gitignore\uFF0C\u8BF7\u52FF\u76F4\u63A5\u5728\u6B64\u6587\u4EF6\u4FEE\u6539!!!
115
+ // ! This file is generated by vite-plugin-generoutes, it is recommended to add it to .gitignore, do not modify it directly in this file!!!
116
+
117
+ export const routes = ${JSON.stringify(routes, null, 2)}
118
+ `;
119
+ routesStr = routesStr.replace(/"##(.*)##"/g, (_, p1) => `() => import('${p1}')`);
120
+ routesStr = await prettier.format(routesStr, { parser: "babel", semi: false, singleQuote: true });
121
+ const filePath = path.resolve(rootDir, routesPath);
122
+ await fs.ensureDir(path.dirname(filePath));
123
+ fs.writeFileSync(filePath, routesStr);
124
+ }
125
+ const debounceWriter = debounce(500, writerRoutesFile);
71
126
  function createWatcher() {
72
- const watcher = chokidar.watch([`${pagesFolder}/**/index.vue`, `${pagesFolder}/**/[...all].vue`], { ignoreInitial: true });
127
+ const watcher = chokidar.watch(`${pagesFolder}/**/*.vue`, { ignoreInitial: true });
73
128
  return watcher.on("all", async (event, path2) => {
74
- if ((path2.endsWith("index.vue") || path2.endsWith("[...all].vue")) && (event === "add" || event === "unlink")) {
129
+ if (ignoreFolders.some((folder) => slash(path2).includes(`/${folder}/`)))
130
+ return;
131
+ if (path2.endsWith(".vue") && (event === "add" || event === "unlink")) {
75
132
  debounceWriter();
76
133
  await watcher.close();
77
134
  createWatcher();
@@ -82,20 +139,15 @@ function VitePluginGeneroutes(options = {}) {
82
139
  name: "vite-plugin-generoutes",
83
140
  async configResolved(config) {
84
141
  rootDir = config.root;
85
- await fs.ensureDir(path.dirname(routesPath));
86
142
  await writerRoutesFile();
87
143
  config.command !== "build" && createWatcher();
88
144
  },
89
145
  async handleHotUpdate({ file, read }) {
90
- if (file.includes("src/pages") && (file.endsWith("index.vue") || file.endsWith("[...all].vue"))) {
146
+ if (file.includes(pagesFolder) && !ignoreFolders.some((folder) => file.includes(`/${folder}/`)) && file.endsWith(".vue")) {
91
147
  const prevDefineOptions = defineOptionsCache.get(slash(path.relative(rootDir, file)));
92
- if (!prevDefineOptions) {
148
+ const defineOptions = JSON.stringify(parseDefineOptions(file, await read()));
149
+ if (prevDefineOptions !== defineOptions) {
93
150
  debounceWriter();
94
- } else {
95
- const defineOptions = JSON.stringify(parseDefineOptions(file, await read()));
96
- if (prevDefineOptions !== defineOptions) {
97
- debounceWriter();
98
- }
99
151
  }
100
152
  }
101
153
  }
@@ -106,16 +158,16 @@ function parseDefineOptions(filePath, content) {
106
158
  const { descriptor } = parse(content);
107
159
  const setupScript = descriptor.scriptSetup?.content;
108
160
  if (setupScript) {
109
- const defineOptionsMatch = setupScript.match(/defineOptions\(([^)]+)\)/);
161
+ const defineOptionsMatch = setupScript.match(/defineOptions\s*\(\s*(\{[\s\S]*?\})\s*\)/);
110
162
  if (defineOptionsMatch) {
111
163
  try {
112
164
  return new Function(`return ${defineOptionsMatch[1]}`)();
113
165
  } catch (e) {
114
- console.error(`Failed to parse defineOptions in ${filePath}:`, e);
166
+ throw new Error(`Failed to parse defineOptions in ${filePath}: ${e}`);
115
167
  }
116
168
  }
117
169
  }
118
- return null;
170
+ return {};
119
171
  }
120
172
  var src_default = VitePluginGeneroutes;
121
173
  export {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "vite-plugin-generoutes",
3
3
  "type": "module",
4
- "version": "0.2.0",
4
+ "version": "0.2.3",
5
5
  "packageManager": "pnpm@9.1.1",
6
6
  "description": "_description_",
7
7
  "author": "Ronnie Zhang <zclzone@outlook.com>",
@@ -78,4 +78,4 @@
78
78
  "lint-staged": {
79
79
  "*": "eslint --fix"
80
80
  }
81
- }
81
+ }