vitarx-router 4.0.0-beta.4 → 4.0.0-beta.5
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 +12 -11
- package/dist/file-router/config/resolve.d.ts +15 -1
- package/dist/file-router/config/resolve.js +1 -8
- package/dist/file-router/config/validate.js +3 -1
- package/dist/file-router/generator/generateRoutes.js +13 -10
- package/dist/file-router/index.d.ts +1 -0
- package/dist/file-router/index.js +6 -1
- package/dist/file-router/types/options.d.ts +54 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -423,17 +423,18 @@ export const router = createRouter({ routes })
|
|
|
423
423
|
|
|
424
424
|
### 文件路由配置选项
|
|
425
425
|
|
|
426
|
-
| 选项 | 类型
|
|
427
|
-
|
|
428
|
-
| `pages` | `PageSource \| readonly PageSource[]`
|
|
429
|
-
| `pathStrategy` | `'kebab' \| 'lowercase' \| 'raw'`
|
|
430
|
-
| `importMode` | `'lazy' \| 'sync'`
|
|
431
|
-
| `injectImports` | `readonly string[]`
|
|
432
|
-
| `dts` | `boolean \| string`
|
|
433
|
-
| `layoutFileName` | `string`
|
|
434
|
-
| `configFileName` | `string`
|
|
435
|
-
| `transform` | `CodeTransformHook`
|
|
436
|
-
| `extendRoute` | `ExtendRouteHook`
|
|
426
|
+
| 选项 | 类型 | 默认值 | 说明 |
|
|
427
|
+
|------------------|--------------------------------------------|---------------|----------|
|
|
428
|
+
| `pages` | `PageSource \| readonly PageSource[]` | `'src/pages'` | 页面来源配置 |
|
|
429
|
+
| `pathStrategy` | `'kebab' \| 'lowercase' \| 'raw'` | `'kebab'` | 路径格式化策略 |
|
|
430
|
+
| `importMode` | `'lazy' \| 'sync' \| ImportModeFunction` | `'lazy'` | 组件导入模式 |
|
|
431
|
+
| `injectImports` | `readonly string[]` | - | 自定义导入语句 |
|
|
432
|
+
| `dts` | `boolean \| string` | `false` | 类型声明文件配置 |
|
|
433
|
+
| `layoutFileName` | `string` | `'_layout'` | 布局文件名 |
|
|
434
|
+
| `configFileName` | `string` | `'_config'` | 分组配置文件名 |
|
|
435
|
+
| `transform` | `CodeTransformHook` | - | 代码转换钩子 |
|
|
436
|
+
| `extendRoute` | `ExtendRouteHook` | - | 路由扩展钩子 |
|
|
437
|
+
| `pathParser` | `PathParser` | - | 自定义路径解析器 |
|
|
437
438
|
|
|
438
439
|
详细配置请参考 [File Router 文档](src/file-router/README.md)。
|
|
439
440
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CodeTransformHook, ExtendRouteHook, FileRouterOptions, ImportMode, PageDirOptions, PathParser, PathStrategy } from '../types/index.js';
|
|
1
|
+
import type { CodeTransformHook, ExtendRouteHook, FileRouterOptions, ImportMode, PageDirOptions, PageSource, PathParser, PathStrategy } from '../types/index.js';
|
|
2
2
|
export type PageDirConfig = Required<PageDirOptions>;
|
|
3
3
|
/**
|
|
4
4
|
* 规范化后的配置
|
|
@@ -16,6 +16,20 @@ export interface ResolvedConfig {
|
|
|
16
16
|
extendRoute?: ExtendRouteHook;
|
|
17
17
|
pathParser?: PathParser;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* 将 pages 配置规范化为 PageConfig 数组
|
|
21
|
+
*
|
|
22
|
+
* 支持四种输入格式:
|
|
23
|
+
* 1. 字符串:单个目录路径
|
|
24
|
+
* 2. 对象:单个目录配置
|
|
25
|
+
* 3. 字符串数组:多个目录路径
|
|
26
|
+
* 4. 对象数组:每个目录独立配置
|
|
27
|
+
*
|
|
28
|
+
* @param pages - 用户配置的 pages
|
|
29
|
+
* @param root - 项目根目录路径(用于解析相对路径)
|
|
30
|
+
* @returns - 规范化后的目录配置数组
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolvePageConfigs(pages: PageSource | readonly PageSource[], root: string): PageDirConfig[];
|
|
19
33
|
/**
|
|
20
34
|
* 规范化文件路由配置
|
|
21
35
|
*
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
* 提供页面目录配置的处理和文件检查功能。
|
|
5
5
|
* 与构建工具无关,可在任何 Node.js 环境中使用。
|
|
6
6
|
*/
|
|
7
|
-
import { accessSync, constants } from 'node:fs';
|
|
8
7
|
import path from 'node:path';
|
|
9
8
|
import { DEFAULT_CONFIG_FILE, DEFAULT_DTS_FILE, DEFAULT_EXCLUDE, DEFAULT_INCLUDE, DEFAULT_LAYOUT_FILE, DEFAULT_PAGES_DIR } from '../constants.js';
|
|
10
9
|
const DEFAULT_PAGE_CONFIG = {
|
|
@@ -26,7 +25,7 @@ const DEFAULT_PAGE_CONFIG = {
|
|
|
26
25
|
* @param root - 项目根目录路径(用于解析相对路径)
|
|
27
26
|
* @returns - 规范化后的目录配置数组
|
|
28
27
|
*/
|
|
29
|
-
function resolvePageConfigs(pages, root) {
|
|
28
|
+
export function resolvePageConfigs(pages, root) {
|
|
30
29
|
const list = Array.isArray(pages) ? pages : [pages];
|
|
31
30
|
return list.map(page => {
|
|
32
31
|
const config = typeof page === 'string' ? { dir: page } : page;
|
|
@@ -38,12 +37,6 @@ function resolvePageConfigs(pages, root) {
|
|
|
38
37
|
if (resolved.prefix !== '/' && !resolved.prefix.startsWith('/')) {
|
|
39
38
|
resolved.prefix = '/' + resolved.prefix;
|
|
40
39
|
}
|
|
41
|
-
try {
|
|
42
|
-
accessSync(resolved.dir, constants.R_OK | constants.W_OK);
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
throw new Error(`File router: Pages directory "${resolved.dir}" does not exist or is not accessible`);
|
|
46
|
-
}
|
|
47
40
|
return resolved;
|
|
48
41
|
});
|
|
49
42
|
}
|
|
@@ -84,9 +84,11 @@ function validateRoot(opts) {
|
|
|
84
84
|
function validateImportMode(opts) {
|
|
85
85
|
if (opts.importMode === undefined)
|
|
86
86
|
return;
|
|
87
|
+
if (typeof opts.importMode === 'function')
|
|
88
|
+
return;
|
|
87
89
|
const validModes = ['lazy', 'sync'];
|
|
88
90
|
if (!validModes.includes(opts.importMode)) {
|
|
89
|
-
throw new Error(`options.importMode 必须是 'lazy'
|
|
91
|
+
throw new Error(`options.importMode 必须是 'lazy'、'sync' 或函数`);
|
|
90
92
|
}
|
|
91
93
|
}
|
|
92
94
|
/**
|
|
@@ -115,7 +115,6 @@ function buildRoutes(pages, extendRoute, parent) {
|
|
|
115
115
|
* @returns 格式化后的组件表达式代码
|
|
116
116
|
*/
|
|
117
117
|
function formatComponent(component, importMode, importLines) {
|
|
118
|
-
// 处理命名视图
|
|
119
118
|
const entries = Object.entries(component).map(([name, file]) => {
|
|
120
119
|
const importPath = JSON.stringify(file);
|
|
121
120
|
let expr;
|
|
@@ -123,9 +122,16 @@ function formatComponent(component, importMode, importLines) {
|
|
|
123
122
|
expr = pathToUniqueName(file);
|
|
124
123
|
importLines.add(`import ${expr} from ${importPath}`);
|
|
125
124
|
}
|
|
126
|
-
else {
|
|
125
|
+
else if (importMode === 'lazy') {
|
|
127
126
|
expr = `lazy(() => import(${importPath}))`;
|
|
128
127
|
}
|
|
128
|
+
else {
|
|
129
|
+
expr = importMode({
|
|
130
|
+
importPath,
|
|
131
|
+
filePath: file,
|
|
132
|
+
addImport: statement => importLines.add(statement)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
129
135
|
return `${JSON.stringify(name)}: ${expr}`;
|
|
130
136
|
});
|
|
131
137
|
return `{ ${entries.join(', ')} }`;
|
|
@@ -215,26 +221,23 @@ function generateRouteCode(route, indent, isLast, importMode, importLines) {
|
|
|
215
221
|
function generateRoutesCode(routes, importMode = 'lazy', customImports, indent = ' ') {
|
|
216
222
|
const importLines = new Set();
|
|
217
223
|
const codeLines = [];
|
|
218
|
-
// 添加 lazy 导入(如果需要)
|
|
219
224
|
if (importMode === 'lazy') {
|
|
220
225
|
importLines.add(`import { lazy } from 'vitarx'`);
|
|
221
226
|
}
|
|
222
|
-
// 添加自定义导入语句
|
|
223
227
|
if (customImports && customImports.length > 0) {
|
|
224
228
|
customImports.forEach(imp => importLines.add(imp));
|
|
225
229
|
}
|
|
226
|
-
// 添加空行
|
|
227
|
-
if (importMode === 'lazy' || (customImports && customImports.length > 0)) {
|
|
228
|
-
codeLines.push('');
|
|
229
|
-
}
|
|
230
|
-
// 生成路由数组
|
|
231
230
|
codeLines.push('export default [');
|
|
232
231
|
for (let i = 0; i < routes.length; i++) {
|
|
233
232
|
const route = routes[i];
|
|
234
233
|
codeLines.push(...generateRouteCode(route, indent, i === routes.length - 1, importMode, importLines));
|
|
235
234
|
}
|
|
236
235
|
codeLines.push(']');
|
|
237
|
-
|
|
236
|
+
const allImports = Array.from(importLines.values());
|
|
237
|
+
if (allImports.length > 0) {
|
|
238
|
+
allImports.push('');
|
|
239
|
+
}
|
|
240
|
+
return allImports.concat(codeLines).join('\n');
|
|
238
241
|
}
|
|
239
242
|
/**
|
|
240
243
|
* 生成路由配置代码
|
|
@@ -11,6 +11,7 @@ import { type FilterOptions } from './parser/index.js';
|
|
|
11
11
|
import type { FileRouterOptions, ParsedNode } from './types/index.js';
|
|
12
12
|
export type * from './types/index.js';
|
|
13
13
|
export * from './utils/logger.js';
|
|
14
|
+
export { resolvePageConfigs } from './config/resolve.js';
|
|
14
15
|
/**
|
|
15
16
|
* 文件路由管理器
|
|
16
17
|
*/
|
|
@@ -17,8 +17,9 @@ import { generateRoutes } from './generator/index.js';
|
|
|
17
17
|
import { isEqualPageOptions, mergePageOptions, parseDefinePage, removeDefinePage } from './macros/index.js';
|
|
18
18
|
import { checkDefaultExport, isPageFile, isPageFileInDirs } from './parser/index.js';
|
|
19
19
|
import { parseRoutePath } from './parser/parsePage.js';
|
|
20
|
-
import { applyPathStrategy, info, normalizePathSeparator, readFileContent, resolvePathVariable, validateOptions } from './utils/index.js';
|
|
20
|
+
import { applyPathStrategy, info, normalizePathSeparator, readFileContent, resolvePathVariable, validateOptions, warn } from './utils/index.js';
|
|
21
21
|
export * from './utils/logger.js';
|
|
22
|
+
export { resolvePageConfigs } from './config/resolve.js';
|
|
22
23
|
/**
|
|
23
24
|
* 文件路由管理器
|
|
24
25
|
*/
|
|
@@ -98,6 +99,10 @@ export class FileRouter {
|
|
|
98
99
|
scanPages() {
|
|
99
100
|
const pages = [];
|
|
100
101
|
for (const page of this.config.pages) {
|
|
102
|
+
if (!existsSync(page.dir)) {
|
|
103
|
+
warn(`Directory ${page.dir} does not exist, please check your configuration.`);
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
101
106
|
if (page.group && page.prefix) {
|
|
102
107
|
const route = {
|
|
103
108
|
filePath: page.dir,
|
|
@@ -1,11 +1,46 @@
|
|
|
1
1
|
import type { CodeTransformHook, ExtendRouteHook } from './hooks.js';
|
|
2
|
+
/**
|
|
3
|
+
* 自定义导入模式函数的上下文
|
|
4
|
+
*/
|
|
5
|
+
export interface ImportModeContext {
|
|
6
|
+
/**
|
|
7
|
+
* 组件文件路径(已 JSON.stringify)
|
|
8
|
+
*/
|
|
9
|
+
importPath: string;
|
|
10
|
+
/**
|
|
11
|
+
* 组件文件原始路径
|
|
12
|
+
*/
|
|
13
|
+
filePath: string;
|
|
14
|
+
/**
|
|
15
|
+
* 添加导入语句
|
|
16
|
+
* 用于向生成的代码顶部添加 import 语句
|
|
17
|
+
*/
|
|
18
|
+
addImport: (statement: string) => void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* 自定义导入模式函数
|
|
22
|
+
*
|
|
23
|
+
* @param context - 导入上下文
|
|
24
|
+
* @returns 组件表达式代码
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* // 自定义导入模式:使用 React.lazy
|
|
29
|
+
* (context) => {
|
|
30
|
+
* context.addImport(`import { lazy } from 'react'`)
|
|
31
|
+
* return `lazy(() => import(${context.importPath}))`
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export type ImportModeFunction = (context: ImportModeContext) => string;
|
|
2
36
|
/**
|
|
3
37
|
* 组件导入模式。
|
|
4
38
|
*
|
|
5
|
-
* - 'lazy': 生成懒加载表达式
|
|
6
|
-
* - 'sync':
|
|
39
|
+
* - 'lazy': 生成懒加载表达式 `lazy(() => import(path))`
|
|
40
|
+
* - 'sync': 同步加载组件,生成 `import` 语句
|
|
41
|
+
* - 函数: 自定义导入逻辑
|
|
7
42
|
*/
|
|
8
|
-
export type ImportMode = 'lazy' | 'sync';
|
|
43
|
+
export type ImportMode = 'lazy' | 'sync' | ImportModeFunction;
|
|
9
44
|
/**
|
|
10
45
|
* 生成路径的策略。
|
|
11
46
|
*/
|
|
@@ -88,6 +123,22 @@ export interface FileRouterOptions {
|
|
|
88
123
|
/**
|
|
89
124
|
* 组件导入模式
|
|
90
125
|
*
|
|
126
|
+
* - 'lazy': 生成懒加载表达式 `lazy(() => import(path))`
|
|
127
|
+
* - 'sync': 同步加载组件,生成 `import` 语句
|
|
128
|
+
* - 函数: 自定义导入逻辑
|
|
129
|
+
*
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* // 使用预设模式
|
|
133
|
+
* importMode: 'lazy'
|
|
134
|
+
*
|
|
135
|
+
* // 使用自定义函数
|
|
136
|
+
* importMode: (context) => {
|
|
137
|
+
* context.addImport(`import { lazy } from 'react'`)
|
|
138
|
+
* return `lazy(() => import(${context.importPath}))`
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*
|
|
91
142
|
* @default 'lazy'
|
|
92
143
|
*/
|
|
93
144
|
importMode?: ImportMode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vitarx-router",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.5",
|
|
4
4
|
"description": "Official routing solution for Vitarx framework with declarative routing, navigation guards, dynamic routes, file-based routing with HMR, and full TypeScript support.",
|
|
5
5
|
"author": "ZhuChonglin <8210856@qq.com>",
|
|
6
6
|
"license": "MIT",
|