;
138 |
139 | /** 获取路由动态路径 */
140 | type GetDynamicPath =
141 | | `${P}/:${string}`
142 | | `${P}/:${string}(${string})`
143 | | `${P}/:${string}(${string})?`;
144 | }
145 |
--------------------------------------------------------------------------------
/src/types/index.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * plugin options
3 | * @translate 插件配置
4 | */
5 | export interface PluginOption {
6 | /**
7 | * relative path to the directory to search for page files
8 | * @default 'src/views'
9 | */
10 | pageDir: string;
11 | /**
12 | * glob to match page files, based on the pageDir property
13 | * @default [ '** /index.{vue,tsx,jsx}', '!** /components/**' ]
14 | * - attention: there is no blank after '**'
15 | * @link the detail syntax: https://github.com/micromatch/micromatch
16 | */
17 | pageGlobs: string[];
18 | /**
19 | * relative path to the directory to generate the route declaration.
20 | * @default 'src/typings/page-route.d.ts'
21 | */
22 | routeDts: string;
23 | /**
24 | * relative path to the directory to generate the code of route module const
25 | * @default src/router/modules
26 | */
27 | routeModuleDir: string;
28 | /**
29 | * the extension to the directory to generate the code of route module const
30 | * @default ts
31 | */
32 | routeModuleExt: string;
33 | /**
34 | * the type declaretion of the generated route module item
35 | * @default AuthRoute.Route
36 | * @example
37 | * ```ts
38 | * const route: AuthRoute.Route = {
39 | * name: 'home',
40 | * path: '/home',
41 | * component: 'self',
42 | * meta: {
43 | * title: 'home',
44 | * singleLayout: 'basic'
45 | * }
46 | * }
47 | * export default route;
48 | * ```
49 | */
50 | routeModuleType: string;
51 | /**
52 | * transform the route name
53 | * @param name
54 | */
55 | routeNameTansformer(name: string): string;
56 | /**
57 | * whether the route is lazy import
58 | * @param name route name
59 | * @example
60 | * - the direct import
61 | * ```ts
62 | * import Home from './views/home/index.vue';
63 | * ```
64 | * - the lazy import
65 | * ```ts
66 | * const Home = import('./views/home/index.vue');
67 | * ```
68 | */
69 | lazyImport(name: string): boolean;
70 | /**
71 | * the route name, which is not tranfromed
72 | * @param name
73 | * @returns whether generate the route module, default is true
74 | */
75 | onRouteModuleGenerate(name: string): boolean;
76 | }
77 |
78 | export interface ContextOption extends PluginOption {
79 | rootDir: string;
80 | }
81 |
82 | /**
83 | * the route name and the import path
84 | */
85 | export interface RouteFile {
86 | name: string;
87 | path: string;
88 | }
89 |
90 | /**
91 | * the route config
92 | */
93 | export interface RouteConfig {
94 | names: string[];
95 | files: RouteFile[];
96 | }
97 |
98 | /**
99 | * the component type of route
100 | * - basic - the basic layout, has common part of page
101 | * - blank - the blank layout
102 | * - multi - the multi degree route layout, when the degree is more than 2,
103 | * exclude the first degree and the last degree, the type of other is multi
104 | * - self - use self layout, which is the last degree route
105 | */
106 | export type RouteComponentType = 'basic' | 'blank' | 'multi' | 'self';
107 |
108 | /**
109 | * the route module
110 | */
111 | export interface RouteModule {
112 | name: string;
113 | path: string;
114 | redirect?: string;
115 | component: RouteComponentType;
116 | meta: {
117 | title: string;
118 | icon: string;
119 | singleLayout?: Extract;
120 | };
121 | children?: RouteModule[];
122 | }
123 |
124 | export type FileWatcherEvent = 'addDir' | 'unlinkDir' | 'add' | 'unlink';
125 |
126 | export interface FileWatcherDispatch {
127 | event: FileWatcherEvent;
128 | path: string;
129 | }
130 |
131 | export interface FileWatcherHooks {
132 | /**
133 | * rename the directory, which includes page files
134 | * @example
135 | * ```
136 | * example1:
137 | * home home-new
138 | * ├── first ├── first
139 | * │ └── index.vue ==> │ └── index.vue
140 | * └── second └── second
141 | * └── index.vue └── index.vue
142 | * example2:
143 | * home home
144 | * └── first ==> └── first-new
145 | * └── index.vue └── index.vue
146 | * ```
147 | */
148 | onRenameDirWithFile(): Promise;
149 | /**
150 | * delete the directory, which includes page files
151 | * * @example
152 | * ```
153 | * example1:
154 | * home
155 | * ├── first
156 | * │ └── index.vue ==> (delete directory home)
157 | * └── second
158 | * └── index.vue
159 | * example2:
160 | * home home
161 | * ├── first ==> └── first
162 | * │ └── index.vue └── index.vue
163 | * └── second
164 | * └── index.vue
165 | * ```
166 | */
167 | onDelDirWithFile(): Promise;
168 | /**
169 | * add a directory, which includes page files, it may be a copy action
170 | * * @example
171 | * ```
172 | * example1:
173 | * home
174 | * ├── first
175 | * (add directory home) ==> │ └── index.vue
176 | * └── second
177 | * └── index.vue
178 | * example2:
179 | * home home
180 | * └── second ├── first
181 | * └── index.vue ==> │ └── index.vue
182 | * └── second
183 | * └── index.vue
184 | * ```
185 | */
186 | onAddDirWithFile(): Promise;
187 | /**
188 | * delete a page file
189 | * @example
190 | * ```
191 | * example1:
192 | * home ==> home
193 | * └── index.vue
194 | * example2:
195 | * home ==> home
196 | * └── first └── first
197 | * └── index.vue
198 | * ```
199 | */
200 | onDelFile(): Promise;
201 | /**
202 | * add a page file
203 | * @example
204 | * ```
205 | * example1:
206 | * home ==> home
207 | * └── index.vue
208 | * example2:
209 | * home ==> home
210 | * └── first └── first
211 | * └── index.vue
212 | * ```
213 | */
214 | onAddFile(): Promise;
215 | }
216 |
--------------------------------------------------------------------------------
/examples/vue/src/styles/css/reset.css:
--------------------------------------------------------------------------------
1 | /*
2 | 1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)
3 | 2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)
4 | */
5 |
6 | *,
7 | ::before,
8 | ::after {
9 | box-sizing: border-box; /* 1 */
10 | border-width: 0; /* 2 */
11 | border-style: solid; /* 2 */
12 | border-color: currentColor; /* 2 */
13 | }
14 |
15 | /*
16 | 1. Use a consistent sensible line-height in all browsers.
17 | 2. Prevent adjustments of font size after orientation changes in iOS.
18 | 3. Use a more readable tab size.
19 | 4. Use the user's configured `sans` font-family by default.
20 | */
21 |
22 | html {
23 | line-height: 1.5; /* 1 */
24 | -webkit-text-size-adjust: 100%; /* 2 */
25 | -moz-tab-size: 4; /* 3 */
26 | tab-size: 4; /* 3 */
27 | font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
28 | "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
29 | "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; /* 4 */
30 | }
31 |
32 | /*
33 | 1. Remove the margin in all browsers.
34 | 2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.
35 | */
36 |
37 | body {
38 | margin: 0; /* 1 */
39 | line-height: inherit; /* 2 */
40 | }
41 |
42 | /*
43 | 1. Add the correct height in Firefox.
44 | 2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)
45 | 3. Ensure horizontal rules are visible by default.
46 | */
47 |
48 | hr {
49 | height: 0; /* 1 */
50 | color: inherit; /* 2 */
51 | border-top-width: 1px; /* 3 */
52 | }
53 |
54 | /*
55 | Add the correct text decoration in Chrome, Edge, and Safari.
56 | */
57 |
58 | abbr:where([title]) {
59 | text-decoration: underline dotted;
60 | }
61 |
62 | /*
63 | Remove the default font size and weight for headings.
64 | */
65 |
66 | h1,
67 | h2,
68 | h3,
69 | h4,
70 | h5,
71 | h6 {
72 | font-size: inherit;
73 | font-weight: inherit;
74 | }
75 |
76 | /*
77 | Reset links to optimize for opt-in styling instead of opt-out.
78 | */
79 |
80 | a {
81 | color: inherit;
82 | text-decoration: inherit;
83 | }
84 |
85 | /*
86 | Add the correct font weight in Edge and Safari.
87 | */
88 |
89 | b,
90 | strong {
91 | font-weight: bolder;
92 | }
93 |
94 | /*
95 | 1. Use the user's configured `mono` font family by default.
96 | 2. Correct the odd `em` font sizing in all browsers.
97 | */
98 |
99 | code,
100 | kbd,
101 | samp,
102 | pre {
103 | font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
104 | "Liberation Mono", "Courier New", monospace; /* 1 */
105 | font-size: 1em; /* 2 */
106 | }
107 |
108 | /*
109 | Add the correct font size in all browsers.
110 | */
111 |
112 | small {
113 | font-size: 80%;
114 | }
115 |
116 | /*
117 | Prevent `sub` and `sup` elements from affecting the line height in all browsers.
118 | */
119 |
120 | sub,
121 | sup {
122 | font-size: 75%;
123 | line-height: 0;
124 | position: relative;
125 | vertical-align: baseline;
126 | }
127 |
128 | sub {
129 | bottom: -0.25em;
130 | }
131 |
132 | sup {
133 | top: -0.5em;
134 | }
135 |
136 | /*
137 | 1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)
138 | 2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)
139 | 3. Remove gaps between table borders by default.
140 | */
141 |
142 | table {
143 | text-indent: 0; /* 1 */
144 | border-color: inherit; /* 2 */
145 | border-collapse: collapse; /* 3 */
146 | }
147 |
148 | /*
149 | 1. Change the font styles in all browsers.
150 | 2. Remove the margin in Firefox and Safari.
151 | 3. Remove default padding in all browsers.
152 | */
153 |
154 | button,
155 | input,
156 | optgroup,
157 | select,
158 | textarea {
159 | font-family: inherit; /* 1 */
160 | font-size: 100%; /* 1 */
161 | line-height: inherit; /* 1 */
162 | color: inherit; /* 1 */
163 | margin: 0; /* 2 */
164 | padding: 0; /* 3 */
165 | }
166 |
167 | /*
168 | Remove the inheritance of text transform in Edge and Firefox.
169 | */
170 |
171 | button,
172 | select {
173 | text-transform: none;
174 | }
175 |
176 | /*
177 | 1. Correct the inability to style clickable types in iOS and Safari.
178 | 2. Remove default button styles.
179 | */
180 |
181 | button,
182 | [type="button"],
183 | [type="reset"],
184 | [type="submit"] {
185 | -webkit-appearance: button; /* 1 */
186 | /* background-color: transparent; 2 */
187 | background-image: none; /* 2 */
188 | }
189 |
190 | /*
191 | Use the modern Firefox focus style for all focusable elements.
192 | */
193 |
194 | :-moz-focusring {
195 | outline: auto;
196 | }
197 |
198 | /*
199 | Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)
200 | */
201 |
202 | :-moz-ui-invalid {
203 | box-shadow: none;
204 | }
205 |
206 | /*
207 | Add the correct vertical alignment in Chrome and Firefox.
208 | */
209 |
210 | progress {
211 | vertical-align: baseline;
212 | }
213 |
214 | /*
215 | Correct the cursor style of increment and decrement buttons in Safari.
216 | */
217 |
218 | ::-webkit-inner-spin-button,
219 | ::-webkit-outer-spin-button {
220 | height: auto;
221 | }
222 |
223 | /*
224 | 1. Correct the odd appearance in Chrome and Safari.
225 | 2. Correct the outline style in Safari.
226 | */
227 |
228 | [type="search"] {
229 | -webkit-appearance: textfield; /* 1 */
230 | outline-offset: -2px; /* 2 */
231 | }
232 |
233 | /*
234 | Remove the inner padding in Chrome and Safari on macOS.
235 | */
236 |
237 | ::-webkit-search-decoration {
238 | -webkit-appearance: none;
239 | }
240 |
241 | /*
242 | 1. Correct the inability to style clickable types in iOS and Safari.
243 | 2. Change font properties to `inherit` in Safari.
244 | */
245 |
246 | ::-webkit-file-upload-button {
247 | -webkit-appearance: button; /* 1 */
248 | font: inherit; /* 2 */
249 | }
250 |
251 | /*
252 | Add the correct display in Chrome and Safari.
253 | */
254 |
255 | summary {
256 | display: list-item;
257 | }
258 |
259 | /*
260 | Removes the default spacing and border for appropriate elements.
261 | */
262 |
263 | blockquote,
264 | dl,
265 | dd,
266 | h1,
267 | h2,
268 | h3,
269 | h4,
270 | h5,
271 | h6,
272 | hr,
273 | figure,
274 | p,
275 | pre {
276 | margin: 0;
277 | }
278 |
279 | fieldset {
280 | margin: 0;
281 | padding: 0;
282 | }
283 |
284 | legend {
285 | padding: 0;
286 | }
287 |
288 | ol,
289 | ul,
290 | menu {
291 | list-style: none;
292 | margin: 0;
293 | padding: 0;
294 | }
295 |
296 | /*
297 | Prevent resizing textareas horizontally by default.
298 | */
299 |
300 | textarea {
301 | resize: vertical;
302 | }
303 |
304 | /*
305 | 1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)
306 | 2. Set the default placeholder color to the user's configured gray 400 color.
307 | */
308 |
309 | input::placeholder,
310 | textarea::placeholder {
311 | opacity: 1; /* 1 */
312 | color: #9ca3af; /* 2 */
313 | }
314 |
315 | /*
316 | Set the default cursor for buttons.
317 | */
318 |
319 | button,
320 | [role="button"] {
321 | cursor: pointer;
322 | }
323 |
324 | /*
325 | Make sure disabled buttons don't get the pointer cursor.
326 | */
327 | :disabled {
328 | cursor: default;
329 | }
330 |
331 | /*
332 | 1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)
333 | 2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)
334 | This can trigger a poorly considered lint error in some tools but is included by design.
335 | */
336 |
337 | img,
338 | svg,
339 | video,
340 | canvas,
341 | audio,
342 | iframe,
343 | embed,
344 | object {
345 | display: block; /* 1 */
346 | vertical-align: middle; /* 2 */
347 | }
348 |
349 | /*
350 | Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)
351 | */
352 |
353 | img,
354 | video {
355 | max-width: 100%;
356 | height: auto;
357 | }
358 |
359 | /*
360 | Ensure the default browser behavior of the `hidden` attribute.
361 | */
362 |
363 | [hidden] {
364 | display: none;
365 | }
366 |
367 | .dark {
368 | color-scheme: dark;
369 | }
370 |
--------------------------------------------------------------------------------
/src/context/fs.ts:
--------------------------------------------------------------------------------
1 | import {
2 | getRenamedDirConfig,
3 | getDelDirConfig,
4 | getAddDirConfig,
5 | getDelFileConfig,
6 | getAddFileConfig,
7 | getRouteModuleNameByRouteName,
8 | getRoutePathFromName,
9 | getRouteModuleNameByGlob,
10 | getRouteModuleWhetherFileExist,
11 | getSingleRouteModulesFromGlob,
12 | mergeFirstDegreeRouteModule,
13 | getRouteNameByGlobWithTransformer,
14 | recurseRemoveModuleByNames,
15 | useFsExtra
16 | } from '../shared';
17 | import type {
18 | ContextOption,
19 | RouteConfig,
20 | FileWatcherDispatch,
21 | FileWatcherHooks,
22 | FileWatcherEvent,
23 | RouteModule
24 | } from '../types';
25 | import { generateRouteModuleCode } from './module';
26 |
27 | export async function fileWatcherHandler(dispatchs: FileWatcherDispatch[], hooks: FileWatcherHooks) {
28 | const dispatchWithCategory: Record = {
29 | addDir: [],
30 | unlinkDir: [],
31 | add: [],
32 | unlink: []
33 | };
34 |
35 | dispatchs.forEach(item => {
36 | dispatchWithCategory[item.event].push(item.path);
37 | });
38 |
39 | const hasAddDir = dispatchWithCategory.addDir.length > 0;
40 | const hasUnlinkDir = dispatchWithCategory.unlinkDir.length > 0;
41 | const hasAdd = dispatchWithCategory.add.length > 0;
42 | const hasUnlink = dispatchWithCategory.unlink.length > 0;
43 |
44 | const { onRenameDirWithFile, onDelDirWithFile, onAddDirWithFile, onDelFile, onAddFile } = hooks;
45 |
46 | const conditions: [boolean, () => Promise][] = [
47 | [hasAddDir && hasUnlinkDir && hasAdd && hasUnlink, onRenameDirWithFile],
48 | [hasUnlinkDir && hasUnlink, onDelDirWithFile],
49 | [hasAddDir && hasAdd, onAddDirWithFile],
50 | [hasUnlink, onDelFile],
51 | [hasAdd, onAddFile]
52 | ];
53 |
54 | const [, callback] = conditions.find(([condition]) => condition) || [true, async () => {}];
55 |
56 | await callback();
57 | }
58 |
59 | export function createFWHooksOfGenDeclarationAndViews(
60 | dispatchs: FileWatcherDispatch[],
61 | routeConfig: RouteConfig,
62 | options: ContextOption
63 | ) {
64 | const hooks: FileWatcherHooks = {
65 | async onRenameDirWithFile() {
66 | const { oldRouteName, newRouteName, oldRouteFilePath, newRouteFilePath } = getRenamedDirConfig(
67 | dispatchs,
68 | options
69 | );
70 |
71 | routeConfig.names = routeConfig.names.map(name => name.replace(oldRouteName, newRouteName));
72 |
73 | routeConfig.files = routeConfig.files.map(item => {
74 | const name = item.name.replace(oldRouteName, newRouteName);
75 | const path = item.path.replace(oldRouteFilePath, newRouteFilePath);
76 |
77 | return {
78 | name,
79 | path
80 | };
81 | });
82 | },
83 | async onDelDirWithFile() {
84 | const { delRouteName } = getDelDirConfig(dispatchs, options);
85 |
86 | routeConfig.names = routeConfig.names.filter(name => !name.includes(delRouteName));
87 | routeConfig.files = routeConfig.files.filter(item => !item.name.includes(delRouteName));
88 | },
89 | async onAddDirWithFile() {
90 | const config = getAddDirConfig(dispatchs, options);
91 |
92 | routeConfig.names = routeConfig.names.concat(config.names).sort();
93 | routeConfig.files = routeConfig.files.concat(config.files).sort((a, b) => (a.name > b.name ? 1 : -1));
94 | },
95 | async onDelFile() {
96 | const { delRouteNames } = getDelFileConfig(dispatchs, options);
97 |
98 | routeConfig.names = routeConfig.names.filter(name => delRouteNames.every(item => !name.includes(item)));
99 | routeConfig.files = routeConfig.files.filter(item => delRouteNames.every(v => !item.name.includes(v)));
100 | },
101 | async onAddFile() {
102 | const config = getAddFileConfig(dispatchs, options);
103 |
104 | routeConfig.names = routeConfig.names.concat(config.names).sort();
105 | routeConfig.files = routeConfig.files.concat(config.files).sort((a, b) => (a.name > b.name ? 1 : -1));
106 | }
107 | };
108 |
109 | return hooks;
110 | }
111 |
112 | export function createFWHooksOfGenModule(
113 | dispatchs: FileWatcherDispatch[],
114 | routeConfig: RouteConfig,
115 | options: ContextOption
116 | ) {
117 | async function getRouteModule(
118 | moduleName: string,
119 | existModuleName: string,
120 | existCallback: (module: RouteModule, filePath: string) => Promise
121 | ) {
122 | return getRouteModuleWhetherFileExist({ moduleName, existModuleName, routeConfig, options, existCallback });
123 | }
124 |
125 | const hooks: FileWatcherHooks = {
126 | async onRenameDirWithFile() {
127 | const { oldRouteName, newRouteName } = getRenamedDirConfig(dispatchs, options);
128 | if (!oldRouteName || !newRouteName) return;
129 | const { remove } = await useFsExtra();
130 |
131 | const oldRoutePath = getRoutePathFromName(oldRouteName);
132 | const newRoutePath = getRoutePathFromName(newRouteName);
133 | const oldModuleName = getRouteModuleNameByRouteName(oldRouteName);
134 | const newModuleName = getRouteModuleNameByRouteName(newRouteName);
135 |
136 | const module = await getRouteModule(newModuleName, oldModuleName, async (routeModule, filePath) => {
137 | const moduleJson = JSON.stringify(routeModule);
138 | const updateModuleJson = moduleJson
139 | .replace(new RegExp(`"${oldRouteName}`, 'g'), `"${newRouteName}`)
140 | .replace(new RegExp(`${oldRoutePath}`, 'g'), newRoutePath);
141 |
142 | const existModule = JSON.parse(updateModuleJson) as RouteModule;
143 |
144 | await remove(filePath);
145 |
146 | return existModule;
147 | });
148 |
149 | if (module) {
150 | await generateRouteModuleCode(newModuleName, module, options);
151 | }
152 | },
153 | async onDelDirWithFile() {
154 | const { remove } = await useFsExtra();
155 | const { delRouteName } = getDelDirConfig(dispatchs, options);
156 | const moduleName = getRouteModuleNameByRouteName(delRouteName);
157 |
158 | const globs = dispatchs.filter(dispatch => dispatch.event === 'unlink').map(dispatch => dispatch.path);
159 | const routeNames = globs.map(glob => getRouteNameByGlobWithTransformer(glob, options));
160 |
161 | const module = await getRouteModule(moduleName, moduleName, async (routeModule, filePath) => {
162 | if (delRouteName === moduleName) {
163 | await remove(filePath);
164 |
165 | return null;
166 | }
167 |
168 | recurseRemoveModuleByNames(routeModule, routeNames);
169 |
170 | return routeModule;
171 | });
172 |
173 | if (module) {
174 | await generateRouteModuleCode(moduleName, module, options);
175 | }
176 | },
177 | async onAddDirWithFile() {
178 | const globs = dispatchs.filter(dispatch => dispatch.event === 'add').map(dispatch => dispatch.path);
179 |
180 | const moduleName = getRouteModuleNameByGlob(globs[0], options);
181 |
182 | const module = await getRouteModule(moduleName, moduleName, async routeModule => {
183 | globs.forEach(glob => {
184 | const modules = getSingleRouteModulesFromGlob(glob, options);
185 | mergeFirstDegreeRouteModule(routeModule, modules);
186 | });
187 |
188 | return routeModule;
189 | });
190 |
191 | if (module) {
192 | await generateRouteModuleCode(moduleName, module, options);
193 | }
194 | },
195 | async onDelFile() {
196 | const { remove } = await useFsExtra();
197 | const { delRouteNames } = getDelFileConfig(dispatchs, options);
198 |
199 | const globs = dispatchs.filter(dispatch => dispatch.event === 'unlink').map(dispatch => dispatch.path);
200 |
201 | delRouteNames.forEach(async delRouteName => {
202 | const moduleName = getRouteModuleNameByRouteName(delRouteName);
203 |
204 | const routeNames = globs.map(glob => getRouteNameByGlobWithTransformer(glob, options));
205 |
206 | const module = await getRouteModule(moduleName, moduleName, async (routeModule, filePath) => {
207 | if (delRouteName === moduleName) {
208 | await remove(filePath);
209 |
210 | return null;
211 | }
212 |
213 | recurseRemoveModuleByNames(routeModule, routeNames);
214 |
215 | return routeModule;
216 | });
217 |
218 | if (module) {
219 | await generateRouteModuleCode(moduleName, module, options);
220 | }
221 | });
222 | },
223 | async onAddFile() {
224 | await this.onAddDirWithFile();
225 | }
226 | };
227 |
228 | return hooks;
229 | }
230 |
--------------------------------------------------------------------------------
/src/shared/route.ts:
--------------------------------------------------------------------------------
1 | import { access } from 'fs/promises';
2 | import { red, bgRed, green, bgYellow, yellow } from 'kolorist';
3 | import { transformFile } from '@swc/core';
4 | import { SPLASH_MARK, PAGE_DEGREE_SPLIT_MARK, ROUTE_NAME_REG, INVALID_ROUTE_NAME, CAMEL_OR_PASCAL } from './constant';
5 | import { getRelativePathOfGlob } from './glob';
6 | import { useFsExtra } from './fs-extra';
7 | import type {
8 | ContextOption,
9 | RouteConfig,
10 | RouteModule,
11 | RouteComponentType,
12 | FileWatcherDispatch,
13 | RouteFile
14 | } from '../types';
15 |
16 | // route config utils
17 | function transformRouteName(glob: string, routeName: string, pageDir: string) {
18 | let name = routeName;
19 |
20 | const filePath = getRelativePathOfGlob(glob, pageDir);
21 |
22 | if (CAMEL_OR_PASCAL.test(routeName)) {
23 | let warning = `${bgYellow('RECOMMEND')} `;
24 | warning += yellow(`the filePath: ${filePath}`);
25 | warning += green(`\n it's recommended to use kebab-case name style`);
26 | warning += green(`\n example: good: user-info bad: userInfo, UserInfo`);
27 | // eslint-disable-next-line no-console
28 | console.info(warning);
29 | }
30 |
31 | if (!ROUTE_NAME_REG.test(name)) {
32 | name = INVALID_ROUTE_NAME;
33 |
34 | let error = `${bgRed('ERROR')} `;
35 | error += red(`the path is invalid: ${filePath} !\n`);
36 | error += red(`routeName: ${routeName} !`);
37 | error += green(
38 | `\n the directory name and file name can only include letter[a-zA-Z], number[0-9], underline[_] and dollar[$]`
39 | );
40 | // eslint-disable-next-line no-console
41 | console.error(error);
42 | }
43 |
44 | return name;
45 | }
46 |
47 | export function getRouteNameByGlob(glob: string, pageDir: string) {
48 | const globSplits = glob.split(SPLASH_MARK);
49 |
50 | const isFile = glob.includes('.');
51 | const sliceLength = isFile ? globSplits.length - 1 : globSplits.length;
52 |
53 | const routeName = globSplits.splice(0, sliceLength).join(PAGE_DEGREE_SPLIT_MARK);
54 |
55 | return transformRouteName(glob, routeName, pageDir);
56 | }
57 |
58 | export function getAllRouteNames(routeName: string) {
59 | const names = routeName.split(PAGE_DEGREE_SPLIT_MARK);
60 |
61 | const namesWithParent: string[] = [];
62 |
63 | for (let i = 1; i <= names.length; i += 1) {
64 | const parentName = names.slice(0, i).reduce((pre, cur) => pre + PAGE_DEGREE_SPLIT_MARK + cur);
65 | namesWithParent.push(parentName);
66 | }
67 |
68 | return namesWithParent;
69 | }
70 |
71 | export function getRouteFilePathByGlob(glob: string) {
72 | return `./${glob}`;
73 | }
74 |
75 | export function getRouteNameByGlobWithTransformer(glob: string, options: ContextOption) {
76 | const routeName = getRouteNameByGlob(glob, options.pageDir);
77 | return options.routeNameTansformer(routeName);
78 | }
79 |
80 | export function getRouteConfigByGlobs(globs: string[], options: ContextOption) {
81 | const config: RouteConfig = {
82 | names: [],
83 | files: []
84 | };
85 |
86 | globs.sort().forEach(glob => {
87 | const routeName = getRouteNameByGlob(glob, options.pageDir);
88 | const names = getAllRouteNames(routeName);
89 | config.names.push(...names);
90 |
91 | const filePath = getRouteFilePathByGlob(glob);
92 | config.files.push({ name: routeName, path: filePath });
93 | });
94 |
95 | config.names = Array.from(new Set([...config.names]))
96 | .map(name => options.routeNameTansformer(name))
97 | .filter(name => Boolean(name) && name !== INVALID_ROUTE_NAME);
98 |
99 | config.files = config.files
100 | .map(({ name, path }) => ({ name: options.routeNameTansformer(name), path }))
101 | .filter(item => item.name !== INVALID_ROUTE_NAME);
102 |
103 | return config;
104 | }
105 |
106 | // route module utils
107 | interface RouteModuleConfig {
108 | component: RouteComponentType;
109 | hasSingleLayout: boolean;
110 | }
111 | function getRouteModuleConfig(index: number, length: number) {
112 | const actions: [boolean, RouteModuleConfig][] = [
113 | [length === 1, { component: 'self', hasSingleLayout: true }],
114 | [length === 2 && index === 0, { component: 'basic', hasSingleLayout: false }],
115 | [length === 2 && index === 1, { component: 'self', hasSingleLayout: false }],
116 | [length >= 3 && index === 0, { component: 'basic', hasSingleLayout: false }],
117 | [length >= 3 && index === length - 1, { component: 'self', hasSingleLayout: false }],
118 | [true, { component: 'multi', hasSingleLayout: false }]
119 | ];
120 |
121 | const config: RouteModuleConfig = {
122 | component: 'self',
123 | hasSingleLayout: false
124 | };
125 |
126 | const findItem = actions.find(([condition]) => condition);
127 |
128 | return findItem?.[1] || config;
129 | }
130 |
131 | export function getRoutePathFromName(routeName: string) {
132 | const PATH_SPLIT_MARK = '/';
133 |
134 | return PATH_SPLIT_MARK + routeName.replace(new RegExp(`${PAGE_DEGREE_SPLIT_MARK}`, 'g'), PATH_SPLIT_MARK);
135 | }
136 |
137 | export function getRouteModuleNameByRouteName(routeName: string) {
138 | const routeNames = getAllRouteNames(routeName);
139 |
140 | if (!routeNames.length) {
141 | throw new Error(`路由名称不正确!`);
142 | }
143 |
144 | return routeNames[0];
145 | }
146 |
147 | export function getRouteModuleNameByGlob(glob: string, options: ContextOption) {
148 | const routeName = getRouteNameByGlobWithTransformer(glob, options);
149 |
150 | const moduleName = getRouteModuleNameByRouteName(routeName);
151 |
152 | return moduleName;
153 | }
154 |
155 | export function checkIsValidRouteModule(data: any): data is RouteModule {
156 | const isObject = Object.prototype.toString.call(data) === '[object Object]';
157 |
158 | return isObject && data.name && data.path && data.component && data.meta;
159 | }
160 |
161 | function getSingleRouteModulesFromRouteName(routeName: string) {
162 | const routeNames = getAllRouteNames(routeName);
163 |
164 | const modules: RouteModule[] = routeNames.map((item, index) => {
165 | const config = getRouteModuleConfig(index, routeNames.length);
166 |
167 | const module: RouteModule = {
168 | name: item,
169 | path: getRoutePathFromName(item),
170 | component: config.component,
171 | meta: {
172 | title: item,
173 | icon: 'mdi:menu'
174 | }
175 | };
176 |
177 | if (config.hasSingleLayout) {
178 | module.meta.singleLayout = 'basic';
179 | }
180 |
181 | return module;
182 | });
183 |
184 | return modules;
185 | }
186 |
187 | export function getSingleRouteModulesFromGlob(glob: string, options: ContextOption) {
188 | const routeName = getRouteNameByGlobWithTransformer(glob, options);
189 | const modules = getSingleRouteModulesFromRouteName(routeName);
190 |
191 | return modules;
192 | }
193 |
194 | function getSingleRouteModulesWithChildren(singleModules: RouteModule[]): RouteModule | null {
195 | const reversedModules = [...singleModules].reverse();
196 |
197 | reversedModules.forEach((module, index) => {
198 | if (index < reversedModules.length - 1) {
199 | reversedModules[index + 1].children = [module];
200 | }
201 | });
202 |
203 | return reversedModules[reversedModules.length - 1] || null;
204 | }
205 |
206 | function recurseMergeModule(modules: RouteModule[], singleModules: RouteModule[], singleRouteLevel: number) {
207 | if (!singleModules.length) return;
208 |
209 | const currentLevelRouteModule = singleModules[singleRouteLevel];
210 |
211 | const findIndex = modules.findIndex(module => module.name === currentLevelRouteModule.name);
212 |
213 | if (findIndex > -1) {
214 | const findModule = modules[findIndex];
215 |
216 | if (!findModule.children) {
217 | findModule.children = [];
218 | }
219 |
220 | recurseMergeModule(findModule.children!, singleModules, singleRouteLevel + 1);
221 | } else {
222 | const pushModule = getSingleRouteModulesWithChildren(singleModules.slice(singleRouteLevel));
223 | if (pushModule) {
224 | modules.push(pushModule);
225 | }
226 | }
227 | }
228 |
229 | export function mergeFirstDegreeRouteModule(firstDegreeRouteModule: RouteModule, singleModules: RouteModule[]) {
230 | if (!firstDegreeRouteModule.children) {
231 | firstDegreeRouteModule.children = [];
232 | }
233 |
234 | recurseMergeModule(firstDegreeRouteModule.children!, singleModules, 1);
235 | }
236 |
237 | export function getTotalRouteModuleFromNames(routeNames: string[]) {
238 | let module: RouteModule;
239 |
240 | routeNames.forEach((routeName, index) => {
241 | const modules = getSingleRouteModulesFromRouteName(routeName);
242 |
243 | const [firstModule] = modules;
244 |
245 | if (index === 0) {
246 | module = firstModule;
247 | }
248 |
249 | if (firstModule.name === module.name && modules.length > 1) {
250 | mergeFirstDegreeRouteModule(module, modules);
251 | }
252 | });
253 |
254 | return module!;
255 | }
256 |
257 | export function getRouteModuleFilePath(moduleName: string, options: ContextOption) {
258 | const { rootDir, routeModuleDir, routeModuleExt } = options;
259 |
260 | const filePath = `${rootDir}/${routeModuleDir}/${moduleName}.${routeModuleExt}`;
261 |
262 | return filePath;
263 | }
264 |
265 | export async function getIsRouteModuleFileExist(moduleName: string, options: ContextOption) {
266 | const filePath = getRouteModuleFilePath(moduleName, options);
267 |
268 | let exist = false;
269 | try {
270 | await access(filePath);
271 | exist = true;
272 | } catch {}
273 |
274 | return {
275 | exist,
276 | filePath
277 | };
278 | }
279 |
280 | function getTheSmallLengthOfStrArr(arr: string[]) {
281 | let name: string = arr[0];
282 |
283 | arr.forEach(item => {
284 | if (name === null) {
285 | name = item;
286 | } else {
287 | name = item.length < name.length ? item : name;
288 | }
289 | });
290 |
291 | return name;
292 | }
293 |
294 | // eslint-disable-next-line max-params
295 | export async function getRouteModuleWhetherFileExist(params: {
296 | moduleName: string;
297 | existModuleName: string;
298 | routeConfig: RouteConfig;
299 | options: ContextOption;
300 | existCallback: (module: RouteModule, filePath: string) => Promise;
301 | }) {
302 | const { moduleName, existModuleName, routeConfig, options, existCallback } = params;
303 |
304 | const { exist, filePath } = await getIsRouteModuleFileExist(existModuleName, options);
305 |
306 | let module: RouteModule | null;
307 |
308 | try {
309 | if (exist) {
310 | const importModule = await getRouteModuleFromFile(filePath, existModuleName, options);
311 |
312 | if (checkIsValidRouteModule(importModule)) {
313 | module = await existCallback(importModule, filePath);
314 | } else {
315 | throw Error('invalid route module!');
316 | }
317 | } else {
318 | throw Error('not exist module file!');
319 | }
320 | } catch (error) {
321 | const routeNames = routeConfig.files.filter(item => item.name.includes(moduleName)).map(item => item.name);
322 |
323 | module = getTotalRouteModuleFromNames(routeNames);
324 | }
325 |
326 | return module;
327 | }
328 |
329 | export function recurseRemoveModuleByName(module: RouteModule, routeName: string) {
330 | if (!module.children) return;
331 |
332 | module.children = module.children.filter(item => item.name !== routeName);
333 |
334 | module.children.forEach(item => {
335 | if (routeName.includes(item.name)) {
336 | recurseRemoveModuleByName(item, routeName);
337 | }
338 | });
339 | }
340 |
341 | export function recurseRemoveModuleByNames(module: RouteModule, routeNames: string[]) {
342 | if (!routeNames.length) return;
343 |
344 | routeNames.forEach(item => {
345 | recurseRemoveModuleByName(module, item);
346 | });
347 | }
348 |
349 | // FSWatcher hooks utils
350 |
351 | export function getRenamedDirConfig(dispatchs: FileWatcherDispatch[], options: ContextOption) {
352 | const unlinkDirs: string[] = [];
353 | const addDirs: string[] = [];
354 |
355 | dispatchs.forEach(dispatch => {
356 | if (dispatch.event === 'unlinkDir') {
357 | unlinkDirs.push(dispatch.path);
358 | }
359 | if (dispatch.event === 'addDir') {
360 | addDirs.push(dispatch.path);
361 | }
362 | });
363 |
364 | const oldDir = getTheSmallLengthOfStrArr(unlinkDirs);
365 | const newDir = getTheSmallLengthOfStrArr(addDirs);
366 |
367 | const oldRouteName = getRouteNameByGlobWithTransformer(oldDir, options);
368 | const oldRouteFilePath = getRouteFilePathByGlob(oldDir);
369 |
370 | const newRouteName = getRouteNameByGlobWithTransformer(newDir, options);
371 | const newRouteFilePath = getRouteFilePathByGlob(newDir);
372 |
373 | return {
374 | oldRouteName,
375 | newRouteName,
376 | oldRouteFilePath,
377 | newRouteFilePath
378 | };
379 | }
380 |
381 | export function getDelDirConfig(dispatchs: FileWatcherDispatch[], options: ContextOption) {
382 | const unlinkDirs: string[] = [];
383 |
384 | dispatchs.forEach(dispatch => {
385 | if (dispatch.event === 'unlinkDir') {
386 | unlinkDirs.push(dispatch.path);
387 | }
388 | });
389 |
390 | const delDir = getTheSmallLengthOfStrArr(unlinkDirs);
391 |
392 | const delRouteName = getRouteNameByGlobWithTransformer(delDir, options);
393 |
394 | return {
395 | delRouteName
396 | };
397 | }
398 |
399 | export function getAddDirConfig(dispatchs: FileWatcherDispatch[], options: ContextOption) {
400 | const globs: string[] = [];
401 |
402 | dispatchs.forEach(dispatch => {
403 | if (dispatch.event === 'add') {
404 | globs.push(dispatch.path);
405 | }
406 | });
407 |
408 | const config = getRouteConfigByGlobs(globs, options);
409 |
410 | return config;
411 | }
412 |
413 | export function getDelFileConfig(dispatchs: FileWatcherDispatch[], options: ContextOption) {
414 | const delRouteNames: string[] = [];
415 |
416 | dispatchs.forEach(dispatch => {
417 | if (dispatch.event === 'unlink') {
418 | const name = getRouteNameByGlobWithTransformer(dispatch.path, options);
419 | delRouteNames.push(name);
420 | }
421 | });
422 |
423 | return {
424 | delRouteNames
425 | };
426 | }
427 |
428 | export function getAddFileConfig(dispatchs: FileWatcherDispatch[], options: ContextOption) {
429 | const addRouteNames: string[] = [];
430 | const addRouteFiles: RouteFile[] = [];
431 |
432 | dispatchs.forEach(dispatch => {
433 | if (dispatch.event === 'add') {
434 | const name = getRouteNameByGlobWithTransformer(dispatch.path, options);
435 | addRouteNames.push(name);
436 |
437 | const path = getRouteFilePathByGlob(dispatch.path);
438 | addRouteFiles.push({ name, path });
439 | }
440 | });
441 |
442 | const config: RouteConfig = {
443 | names: addRouteNames,
444 | files: addRouteFiles
445 | };
446 |
447 | return config;
448 | }
449 |
450 | async function getRouteModuleFromFile(filePath: string, moduleName: string, options: ContextOption) {
451 | const { writeFile, remove } = await useFsExtra();
452 |
453 | const transformedFilePath = filePath.replace(`${moduleName}.${options.routeModuleExt}`, `${moduleName}-swc.js`);
454 | const { code } = await transformFile(filePath, { filename: transformedFilePath, module: { type: 'commonjs' } });
455 |
456 | if (code) {
457 | await writeFile(transformedFilePath, code, 'utf-8');
458 | }
459 | // eslint-disable-next-line @typescript-eslint/no-var-requires
460 | const { default: importModule } = require(transformedFilePath);
461 |
462 | await remove(transformedFilePath);
463 |
464 | return importModule as RouteModule;
465 | }
466 |
467 | export function transformModuleNameToVariable(name: string) {
468 | return name.replace(/-(\w)/g, (_, match: string) => match.toUpperCase());
469 | }
470 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 |
4 | ## [v0.0.6](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v1.0.5...main) (23-06-08)
5 |
6 | ### 🚀 Features
7 |
8 | - **projects**: Add route module code auto generate - by @soybeanjs [(e9edf)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e9edf14)
9 | - **projects**: Add eslint formate code after generate route module - by @soybeanjs [(6cb1d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/6cb1d08)
10 | - **projects**: Perf route generate - by @soybeanjs [(b4de1)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/b4de144)
11 | - **projects**: Add generate route module on FileWatcher hooks - by @soybeanjs [(f46aa)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/f46aad2)
12 | - **projects**: Complete the plugin refactor - by @soybeanjs [(04cd8)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/04cd838)
13 | - **projects**: Support ESM - by @soybeanjs [(72e7d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/72e7d42)
14 |
15 | ### 🐞 Bug Fixes
16 |
17 | - **projects**: Fix some bugs - by @soybeanjs [(e6c38)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e6c389d)
18 | - **projects**: Fix package.json - by @soybeanjs [(8b603)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/8b603b0)
19 | - **projects**: Add plugin fix - by @soybeanjs [(95907)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/959070e)
20 | - **projects**: Use unbuild replace tsup - by @soybeanjs [(cc929)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/cc929ac)
21 |
22 | ### 🔥 Performance
23 |
24 | - **projects**: Perf plugin - by @soybeanjs [(2669c)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/2669c53)
25 | - **projects**: Update plugin default option and update README - by @soybeanjs [(85ea1)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/85ea171)
26 |
27 | ### 💅 Refactors
28 |
29 | - **projects**: Refactor plugin - by @soybeanjs [(ac725)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/ac725e2)
30 | - **projects**: Refactor get directory methord - by @soybeanjs [(a1490)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/a1490e5)
31 | - **projects**: Refactor plugin - by @soybeanjs [(d2853)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d285353)
32 | - **projects**: Refactor generate route module code - by @soybeanjs [(10691)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/106919e)
33 | - **projects**: Import chokidar to watch directory and file change - by @soybeanjs [(96e31)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/96e31c4)
34 | - **projects**: Add different situations of directory or file change - by @soybeanjs [(65996)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/659961a)
35 | - **projects**: Refactor plugin: update plugin options, and update the relative methods of glob - by @soybeanjs [(dab6a)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/dab6a35)
36 | - **projects**: Refactor plugin: add file watcher handler hooks - by @soybeanjs [(35695)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/35695c9)
37 | - **projects**: Refactor plugin: compelte generate declaration and views - by @soybeanjs [(14737)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/147377b)
38 | - **projects**: Update plugin - by @soybeanjs [(9bdda)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/9bddad1)
39 |
40 | ### 📖 Documentation
41 |
42 | - **projects**: Update README - by @soybeanjs [(19c28)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/19c289e)
43 | - **projects**: Update README - by @soybeanjs [(06150)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/0615012)
44 | - **projects**: Update README - by @soybeanjs [(25fba)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/25fbaae)
45 | - **projects**: Add CHANGELOG.md - by @soybeanjs [(d76b0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d76b0f1)
46 |
47 | ### 📦 Build
48 |
49 | - **projects**: Add czg - by @soybeanjs [(1b3f0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/1b3f03d)
50 | - **projects**: Remove husky - by @soybeanjs [(95ff0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/95ff0c5)
51 | - **projects**: Update deps and update package.json - by @soybeanjs [(3c39d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/3c39de2)
52 |
53 | ### 🏡 Chore
54 |
55 | - Release v0.0.3 - by @soybeanjs [(fb987)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/fb98775)
56 | - Release v0.0.4 - by @soybeanjs [(f4ecd)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/f4ecd03)
57 | - Release v0.0.5 - by @soybeanjs [(d6943)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d694304)
58 | - Release v1.0.4 - by @soybeanjs [(e7d45)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e7d4598)
59 | - Release v1.0.5 - by @soybeanjs [(92bd0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/92bd083)
60 |
61 | ### ❤️ Contributors
62 |
63 | [](https://github.com/soybeanjs)
64 |
65 | ## [v1.0.5](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v1.0.4...v1.0.5) (2023-06-04)
66 |
67 | ### 🏡 Chore
68 |
69 | - Release v1.0.5 - by @soybeanjs [(92bd0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/92bd083)
70 |
71 | ### ❤️ Contributors
72 |
73 | [](https://github.com/soybeanjs)
74 |
75 | ## [v1.0.4](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v0.0.5...v1.0.4) (2023-06-02)
76 |
77 | ### 🚀 Features
78 |
79 | - **projects**: Add route module code auto generate - by @soybeanjs [(e9edf)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e9edf14)
80 | - **projects**: Add eslint formate code after generate route module - by @soybeanjs [(6cb1d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/6cb1d08)
81 | - **projects**: Perf route generate - by @soybeanjs [(b4de1)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/b4de144)
82 | - **projects**: Add generate route module on FileWatcher hooks - by @soybeanjs [(f46aa)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/f46aad2)
83 | - **projects**: Complete the plugin refactor - by @soybeanjs [(04cd8)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/04cd838)
84 |
85 | ### 🐞 Bug Fixes
86 |
87 | - **projects**: Fix some bugs - by @soybeanjs [(e6c38)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e6c389d)
88 | - **projects**: Fix package.json - by @soybeanjs [(8b603)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/8b603b0)
89 | - **projects**: Add plugin fix - by @soybeanjs [(95907)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/959070e)
90 |
91 | ### 🔥 Performance
92 |
93 | - **projects**: Perf plugin - by @soybeanjs [(2669c)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/2669c53)
94 | - **projects**: Update plugin default option and update README - by @soybeanjs [(85ea1)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/85ea171)
95 |
96 | ### 💅 Refactors
97 |
98 | - **projects**: Refactor plugin - by @soybeanjs [(ac725)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/ac725e2)
99 | - **projects**: Refactor get directory methord - by @soybeanjs [(a1490)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/a1490e5)
100 | - **projects**: Refactor plugin - by @soybeanjs [(d2853)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d285353)
101 | - **projects**: Refactor generate route module code - by @soybeanjs [(10691)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/106919e)
102 | - **projects**: Import chokidar to watch directory and file change - by @soybeanjs [(96e31)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/96e31c4)
103 | - **projects**: Add different situations of directory or file change - by @soybeanjs [(65996)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/659961a)
104 | - **projects**: Refactor plugin: update plugin options, and update the relative methods of glob - by @soybeanjs [(dab6a)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/dab6a35)
105 | - **projects**: Refactor plugin: add file watcher handler hooks - by @soybeanjs [(35695)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/35695c9)
106 | - **projects**: Refactor plugin: compelte generate declaration and views - by @soybeanjs [(14737)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/147377b)
107 | - **projects**: Update plugin - by @soybeanjs [(9bdda)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/9bddad1)
108 |
109 | ### 📖 Documentation
110 |
111 | - **projects**: Update README - by @soybeanjs [(19c28)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/19c289e)
112 | - **projects**: Update README - by @soybeanjs [(06150)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/0615012)
113 | - **projects**: Update README - by @soybeanjs [(25fba)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/25fbaae)
114 |
115 | ### 📦 Build
116 |
117 | - **projects**: Add czg - by @soybeanjs [(1b3f0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/1b3f03d)
118 | - **projects**: Remove husky - by @soybeanjs [(95ff0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/95ff0c5)
119 | - **projects**: Update deps and update package.json - by @soybeanjs [(3c39d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/3c39de2)
120 |
121 | ### 🏡 Chore
122 |
123 | - Release v0.0.3 - by @soybeanjs [(fb987)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/fb98775)
124 | - Release v0.0.4 - by @soybeanjs [(f4ecd)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/f4ecd03)
125 | - Release v0.0.5 - by @soybeanjs [(d6943)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d694304)
126 | - Release v1.0.4 - by @soybeanjs [(e7d45)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e7d4598)
127 |
128 | ### ❤️ Contributors
129 |
130 | [](https://github.com/soybeanjs)
131 |
132 | ## [v0.0.5](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v0.0.4...v0.0.5) (2023-01-15)
133 |
134 | ### 🐞 Bug Fixes
135 |
136 | - **projects**: Fix package.json - by @soybeanjs [(8b603)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/8b603b0)
137 |
138 | ### 🏡 Chore
139 |
140 | - Release v0.0.5 - by @soybeanjs [(d6943)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d694304)
141 |
142 | ### ❤️ Contributors
143 |
144 | [](https://github.com/soybeanjs)
145 |
146 | ## [v0.0.4](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v0.03...v0.0.4) (2023-01-15)
147 |
148 | ### 🐞 Bug Fixes
149 |
150 | - **projects**: Fix some bugs - by @soybeanjs [(e6c38)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e6c389d)
151 |
152 | ### 🏡 Chore
153 |
154 | - Release v0.0.4 - by @soybeanjs [(f4ecd)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/f4ecd03)
155 |
156 | ### ❤️ Contributors
157 |
158 | [](https://github.com/soybeanjs)
159 |
160 | ## [v0.0.5](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v0.0.2...v0.03) (23-06-08)
161 |
162 | ### 🔥 Performance
163 |
164 | - **projects**: Update plugin default option and update README - by @soybeanjs [(85ea1)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/85ea171)
165 |
166 | ### 🏡 Chore
167 |
168 | - Release v0.0.2 - by @soybeanjs [(013b8)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/013b819)
169 | - Release v0.0.3 - by @soybeanjs [(fb987)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/fb98775)
170 |
171 | ### ❤️ Contributors
172 |
173 | [](https://github.com/soybeanjs)
174 |
175 | ## [v0.0.2](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v1.0.3...v0.0.2) (2023-01-15)
176 |
177 | ### 🚀 Features
178 |
179 | - **projects**: Add route module code auto generate - by @soybeanjs [(e9edf)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e9edf14)
180 | - **projects**: Add eslint formate code after generate route module - by @soybeanjs [(6cb1d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/6cb1d08)
181 | - **projects**: Perf route generate - by @soybeanjs [(b4de1)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/b4de144)
182 | - **projects**: Add generate route module on FileWatcher hooks - by @soybeanjs [(f46aa)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/f46aad2)
183 | - **projects**: Complete the plugin refactor - by @soybeanjs [(04cd8)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/04cd838)
184 |
185 | ### 🔥 Performance
186 |
187 | - **projects**: Perf plugin - by @soybeanjs [(2669c)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/2669c53)
188 |
189 | ### 💅 Refactors
190 |
191 | - **projects**: Refactor plugin - by @soybeanjs [(ac725)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/ac725e2)
192 | - **projects**: Refactor get directory methord - by @soybeanjs [(a1490)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/a1490e5)
193 | - **projects**: Refactor plugin - by @soybeanjs [(d2853)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/d285353)
194 | - **projects**: Refactor generate route module code - by @soybeanjs [(10691)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/106919e)
195 | - **projects**: Import chokidar to watch directory and file change - by @soybeanjs [(96e31)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/96e31c4)
196 | - **projects**: Add different situations of directory or file change - by @soybeanjs [(65996)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/659961a)
197 | - **projects**: Refactor plugin: update plugin options, and update the relative methods of glob - by @soybeanjs [(dab6a)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/dab6a35)
198 | - **projects**: Refactor plugin: add file watcher handler hooks - by @soybeanjs [(35695)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/35695c9)
199 | - **projects**: Refactor plugin: compelte generate declaration and views - by @soybeanjs [(14737)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/147377b)
200 | - **projects**: Update plugin - by @soybeanjs [(9bdda)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/9bddad1)
201 |
202 | ### 📖 Documentation
203 |
204 | - **projects**: Update README - by @soybeanjs [(19c28)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/19c289e)
205 | - **projects**: Update README - by @soybeanjs [(06150)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/0615012)
206 | - **projects**: Update README - by @soybeanjs [(25fba)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/25fbaae)
207 |
208 | ### 📦 Build
209 |
210 | - **projects**: Add czg - by @soybeanjs [(1b3f0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/1b3f03d)
211 | - **projects**: Remove husky - by @soybeanjs [(95ff0)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/95ff0c5)
212 | - **projects**: Update deps and update package.json - by @soybeanjs [(3c39d)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/3c39de2)
213 |
214 | ### 🏡 Chore
215 |
216 | - Release v0.0.2 - by @soybeanjs [(013b8)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/013b819)
217 |
218 | ### ❤️ Contributors
219 |
220 | [](https://github.com/soybeanjs)
221 |
222 | ## [v1.0.3](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v1.0.2...v1.0.3) (2022-11-07)
223 |
224 | ### 🐞 Bug Fixes
225 |
226 | - **projects**: Fix views order - by @soybeanjs [(b11bf)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/b11bf3a)
227 |
228 | ### 🏡 Chore
229 |
230 | - Release v1.0.3 - by @soybeanjs [(4969f)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/4969f04)
231 |
232 | ### ❤️ Contributors
233 |
234 | [](https://github.com/soybeanjs)
235 |
236 | ## [v1.0.2](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v1.0.1...v1.0.2) (2022-11-07)
237 |
238 | ### 🐞 Bug Fixes
239 |
240 | - **projects**: Fix import key error - by @soybeanjs [(ed151)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/ed151b2)
241 |
242 | ### 🏡 Chore
243 |
244 | - Release v1.0.2 - by @soybeanjs [(98120)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/981208a)
245 |
246 | ### ❤️ Contributors
247 |
248 | [](https://github.com/soybeanjs)
249 |
250 | ## [v1.0.1](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v1.0.0...v1.0.1) (2022-11-07)
251 |
252 | ### 🚀 Features
253 |
254 | - **projects**: Add lazy import or not lazy - by @soybeanjs [(9bc59)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/9bc59a9)
255 |
256 | ### 🏡 Chore
257 |
258 | - Release v1.0.1 - by @soybeanjs [(971f7)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/971f728)
259 |
260 | ### ❤️ Contributors
261 |
262 | [](https://github.com/soybeanjs)
263 |
264 | ## [v1.0.0](https://github.com/soybeanjs/vite-plugin-vue-page-route/compare/v0.1.0...v1.0.0) (2022-11-07)
265 |
266 | ### 🚀 Features
267 |
268 | - **projects**: Add generate all views module import statement - by @soybeanjs [(46ec7)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/46ec7d5)
269 |
270 | ### 🐞 Bug Fixes
271 |
272 | - **projects**: Complete plugin - by @soybeanjs [(e35d5)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/e35d502)
273 |
274 | ### 🏡 Chore
275 |
276 | - Release v0.2.0 - by @soybeanjs [(ab8d3)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/ab8d3d6)
277 | - Release v1.0.0 - by @soybeanjs [(b2062)](https://github.com/soybeanjs/vite-plugin-vue-page-route/commit/b2062b2)
278 |
279 | ### ❤️ Contributors
280 |
281 | [](https://github.com/soybeanjs)
282 |
--------------------------------------------------------------------------------