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 CHANGED
@@ -423,17 +423,18 @@ export const router = createRouter({ routes })
423
423
 
424
424
  ### 文件路由配置选项
425
425
 
426
- | 选项 | 类型 | 默认值 | 说明 |
427
- |------------------|---------------------------------------|---------------|----------|
428
- | `pages` | `PageSource \| readonly PageSource[]` | `'src/pages'` | 页面来源配置 |
429
- | `pathStrategy` | `'kebab' \| 'lowercase' \| 'raw'` | `'kebab'` | 路径命名策略 |
430
- | `importMode` | `'lazy' \| 'sync'` | `'lazy'` | 组件导入模式 |
431
- | `injectImports` | `readonly string[]` | - | 自定义导入语句 |
432
- | `dts` | `boolean \| string` | `false` | 类型声明文件配置 |
433
- | `layoutFileName` | `string` | `'_layout'` | 布局文件名 |
434
- | `configFileName` | `string` | `'_config'` | 分组配置文件名 |
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''sync'`);
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
- return Array.from(importLines.values()).concat(codeLines).join('\n');
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.4",
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",