@uni-helper/vite-plugin-uni-pages 0.5.0 → 0.6.0

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.
Files changed (4) hide show
  1. package/README.md +550 -54
  2. package/dist/index.d.mts +621 -282
  3. package/dist/index.mjs +2690 -468
  4. package/package.json +13 -8
package/dist/index.d.mts CHANGED
@@ -1,9 +1,9 @@
1
+ import fs from "node:fs";
1
2
  import { FSWatcher } from "chokidar";
2
3
  import { Logger, Plugin, ViteDevServer } from "vite";
3
- import Debug from "debug";
4
4
  import { LoadConfigSource } from "unconfig";
5
- import fs from "node:fs";
6
5
  import { CallExpression } from "@babel/types";
6
+ import Debug from "debug";
7
7
  import { SFCDescriptor, SFCParseOptions } from "@vue/compiler-sfc";
8
8
  import { PageItem, PagesConfig, SubPackages, TabBar, TabBarItem, UserPagesConfig } from "@uni-helper/uni-pages-types";
9
9
  export type * from "@uni-helper/uni-pages-types";
@@ -22,7 +22,7 @@ export type * from "@uni-helper/uni-pages-types";
22
22
  * 用户在函数式 definePage 里通过 define() 创建。分支按写的顺序生效,
23
23
  * 后写的同名键会盖掉先写的。
24
24
  */
25
- declare class DefineConditional {
25
+ export declare class DefineConditional {
26
26
  /** 所有平台共用的基础配置 */
27
27
  private readonly base;
28
28
  /** 按写的顺序记下的条件分支 */
@@ -40,14 +40,14 @@ declare class DefineConditional {
40
40
  resolve(platform: string): Record<string, any>;
41
41
  }
42
42
  /** 判断宏求值的结果是不是一个条件定义 */
43
- declare function isConditional(obj: unknown): obj is DefineConditional;
43
+ export declare function isConditional(obj: unknown): obj is DefineConditional;
44
44
  /**
45
45
  * 把条件定义算成某个平台的普通配置
46
46
  *
47
47
  * 简单包了一层 {@link DefineConditional.resolve},调用方不用导入
48
48
  * 这个类。
49
49
  */
50
- declare function resolveConditional(cond: DefineConditional, platform: string): Record<string, any>;
50
+ export declare function resolveConditional(cond: DefineConditional, platform: string): Record<string, any>;
51
51
  //#endregion
52
52
  //#region src/logger.d.ts
53
53
  /**
@@ -55,14 +55,14 @@ declare function resolveConditional(cond: DefineConditional, platform: string):
55
55
  * 基于 debug 包做分级日志输出
56
56
  * 通过环境变量 DEBUG=vite-plugin-uni-pages:* 开启
57
57
  */
58
- declare const debug: {
58
+ export declare const debug: {
59
59
  /** HMR 相关日志 */
60
60
  hmr: Debug.Debugger;
61
61
  /** 配置项相关日志 */
62
62
  options: Debug.Debugger;
63
63
  /** 主包页面扫描日志 */
64
64
  pages: Debug.Debugger;
65
- /** 子包页面扫描日志 */
65
+ /** 分包页面扫描日志 */
66
66
  subPages: Debug.Debugger;
67
67
  /** 错误日志 */
68
68
  error: Debug.Debugger;
@@ -74,260 +74,121 @@ declare const debug: {
74
74
  definePage: Debug.Debugger;
75
75
  };
76
76
  //#endregion
77
- //#region src/context.d.ts
78
- /**
79
- * 页面上下文:负责扫描页面、加载配置、合并页面信息、生成 pages.json
80
- *
81
- * 做的事情按固定顺序是:加载用户配置 → 扫描页面文件 → 合并页面
82
- * 信息 → 写入 pages.json。这个顺序由 {@link updatePagesJSON}(完整
83
- * 流程)或 {@link scanAndMerge}(只算不写)管理,调用方不用关心
84
- * 内部步骤。
85
- */
86
- declare class PageContext {
87
- private _server;
88
- /** 从用户配置文件(pages.config.ts)解析出的配置对象 */
89
- pagesGlobConfig: PagesConfig | undefined;
90
- /** 用户配置文件的来源路径列表 */
91
- pagesConfigSourcePaths: string[];
92
- /** 主包页面映射,键为页面文件的绝对路径 */
93
- pages: Map<string, Page>;
94
- /** 子包页面映射,键为子包根目录,值为该子包下的页面映射 */
95
- subPages: Map<string, Map<string, Page>>;
96
- /** 主包页面配置数组,用于生成 pages.json 的 pages 字段 */
97
- pageMetaData: InternalPages;
98
- /** 子包页面配置数组,用于生成 pages.json 的 subPackages 字段 */
99
- subPageMetaData: SubPackages;
100
- /**
101
- * 最近一次合并出的 tabBar(配置文件与 definePage 声明的合体)。
102
- * 类型声明生成 tab 页列表时用它,definePage 声明的 tabBar 页才能
103
- * 一起从 navigateTo 的 url 类型里排除
104
- */
105
- tabBar: TabBar | undefined;
106
- /** 生成的 pages.json 文件路径 */
107
- resolvedPagesJSONPath: string;
108
- /** 项目根目录 */
109
- root: string;
110
- /** 解析后的配置项 */
111
- options: ResolvedOptions;
112
- /** 当前平台标识,如 'mp-weixin';由调用方传入,不依赖模块加载时冻结的环境 */
113
- readonly platform: string;
114
- logger?: Logger;
115
- /** 是否与 vite-plugin-uni-platform 插件协同工作 */
116
- withUniPlatform: boolean;
117
- /** pages.json 中页面路径的解析基准路径 */
118
- private get basePath();
119
- /**
120
- * 创建 PageContext 实例
121
- * @param userOptions - 用户配置项
122
- * @param viteRoot - Vite 项目根目录,默认为当前工作目录
123
- * @param platform - 当前平台标识,默认取 uni-env 的平台
124
- */
125
- constructor(userOptions: UserOptions, viteRoot?: string, platform?: string);
126
- /**
127
- * 设置 Vite logger
128
- * @param logger - Vite logger 实例
129
- */
130
- setLogger(logger: Logger): void;
131
- /**
132
- * 加载用户页面配置文件(如 pages.config.ts)
133
- * 使用 unconfig 加载配置,支持多种配置文件格式
134
- */
135
- loadUserPagesConfig(): Promise<void>;
136
- /**
137
- * 按顺序跑完扫描与合并:先扫描主包和子包的页面,再合并它们的
138
- * 信息。步骤顺序只维护在这里,调用方和测试都不用关心。
139
- */
140
- scanAndMerge(): Promise<void>;
141
- /**
142
- * 设置 Vite 开发服务器,用于 HMR 与文件监听
143
- * @param server - Vite 开发服务器实例
144
- */
145
- setupViteServer(server: ViteDevServer): void;
146
- /**
147
- * 设置文件监听器,监听页面文件与配置文件变更
148
- * 页面文件或配置文件变化时自动更新 pages.json
149
- * @param watcher - chokidar 文件监听器实例
150
- */
151
- setupWatcher(watcher: FSWatcher): Promise<void>;
152
- /**
153
- * 页面更新回调,页面文件或配置变化时触发
154
- * 负责使虚拟模块失效并通知浏览器整页刷新
155
- */
156
- onUpdate(): void;
157
- /**
158
- * 更新 pages.json 文件
159
- * 这是负责协调整个页面配置生成流程的核心方法:
160
- * 1. 检查文件变更(指定 filepath 时)
161
- * 2. 加载用户配置
162
- * 3. 扫描页面文件
163
- * 4. 合并页面配置
164
- * 5. 生成并写入 pages.json
165
- * @param filepath - 发生变更的文件路径,用于增量更新判断
166
- * @returns pages.json 是否成功更新
167
- */
168
- updatePagesJSON(filepath?: string): Promise<boolean>;
169
- /**
170
- * 生成虚拟模块内容
171
- * 返回包含 pages 与 subPackages 导出的 JavaScript 代码
172
- * @returns 虚拟模块代码字符串
173
- */
174
- virtualModule(): string;
175
- /**
176
- * 将主包路由数据解析为 JSON 字符串
177
- * @returns 主包页面配置的 JSON 字符串
178
- */
179
- resolveRoutes(): string;
180
- /**
181
- * 将子包路由数据解析为 JSON 字符串
182
- * @returns 子包页面配置的 JSON 字符串
183
- */
184
- resolveSubRoutes(): string;
185
- /**
186
- * 解析 tabBar 配置
187
- * 将页面定义的 tabBar 项与配置文件定义的 tabBar 合并
188
- * @returns 合并后的 tabBar 配置对象,无 tabBar 时为 undefined
189
- */
190
- resolveTabBar(): Promise<TabBar | undefined>;
191
- /**
192
- * 生成 TypeScript 声明文件
193
- * 为页面路径生成类型定义,导航时提供类型提示
194
- */
195
- generateDeclaration(): Promise<void> | undefined;
196
- /**
197
- * 扫描主包页面目录并收集所有页面文件路径
198
- * 根据配置的 dirs 选项扫描对应目录
199
- */
200
- private scanPages;
201
- /**
202
- * 按页面文件绝对路径查找被跟踪的页面(主包或任一子包)
203
- * @param filepath - 页面文件的绝对路径
204
- * @returns 被跟踪的页面,文件未被跟踪时为 undefined
205
- */
206
- private findPage;
207
- /**
208
- * 扫描子包页面目录并收集所有子包页面文件路径
209
- * 根据配置的 subPackages 选项扫描对应目录
210
- */
211
- private scanSubPages;
212
- /**
213
- * 解析 pages 规则并设置页面类型
214
- * @param pages 页面路径映射
215
- * @param packageType 页面包类型(主包或子包)
216
- * @param overrides 自定义页面配置
217
- * @returns pages 规则
218
- */
219
- private parsePages;
220
- /**
221
- * 设置首页
222
- * @param result pages 规则数组
223
- * @returns pages 规则
224
- */
225
- private setHomePage;
226
- /**
227
- * 合并主包页面配置
228
- * 过滤掉属于子包的页面,再解析页面配置并与用户配置合并
229
- */
230
- private mergePageMetaData;
231
- /**
232
- * 合并子包页面配置
233
- * 为每个子包解析页面配置并处理子包配置继承
234
- * 保留用户配置中子包级别的属性(如 plugins)
235
- */
236
- private mergeSubPageMetaData;
237
- }
238
- /**
239
- * 应用 vite-plugin-uni-platform 的页面文件名后缀规则(如 `index.h5.vue`
240
- * 对应页面 `index`):丢弃其他平台的后缀页面,保留当前平台的并把文件名
241
- * 里的后缀剥掉。
242
- *
243
- * 带点的判断只看路径最后一段(文件名),和 vite-plugin-uni-platform
244
- * 自己的规则一致(它也只在文件名上判断后缀),目录名里的点(如
245
- * `pages/v1.2/detail`)不算平台后缀。
246
- *
247
- * 注意后缀匹配仍是原始的 `path.includes(platform)`,没有做 definePage
248
- * 那边 h5/web 的别名换算(见 condition.ts 的 platformMatches):
249
- * UNI_PLATFORM=web 时,`.h5` 后缀的页面会被过滤掉。这是一直以来的
250
- * 行为,为了和 vite-plugin-uni-platform 自己的命名规则保持一致而保留。
251
- *
252
- * @param pages - 合并后的主包页面配置
253
- * @param platform - 当前平台标识
254
- * @returns 过滤并剥掉后缀的新数组,入参不被修改
255
- */
256
- declare function filterPlatformSuffixPages(pages: InternalPages, platform: string): InternalPages;
257
- //#endregion
258
77
  //#region src/page.d.ts
78
+ /** Page 读取页面内容所需的环境;不再依赖整个 PageContext */
79
+ export interface PageEnvironment {
80
+ platform: string;
81
+ /** 读取时取得当前 logger,覆盖 setLogger 在 Page 创建之后才发生的情况 */
82
+ getLogger?: () => Logger | undefined;
83
+ }
84
+ /** 一次页面读取的结果;缓存和变更检测都留在 Page 内部 */
85
+ export interface PageSnapshot {
86
+ /** 用于合并的页面元数据,path 已按 uri 补齐 */
87
+ meta: InternalPageItem;
88
+ /** definePage 声明的 tabBar 项,已补齐 pagePath 和 index */
89
+ tabBar?: TabBarItem & {
90
+ index: number;
91
+ };
92
+ /** 页面在当前平台通过 definePage(null) 退出 */
93
+ skipped: boolean;
94
+ /** 与上一次成功读取相比内容或跳过状态是否变化 */
95
+ changed: boolean;
96
+ }
259
97
  /**
260
- * 表示一个 Vue 页面文件的 Page 类
98
+ * 表示一个 Vue 页面文件的读取适配器
261
99
  *
262
- * 职责:
263
- * 1. 读取页面文件内容
264
- * 2. 解析 definePage 宏定义的页面配置
265
- * 3. 提供 tabBar 配置信息
266
- * 4. 跟踪页面文件变更状态
100
+ * 调用方只需要 `load()`:文件读取、宏求值、跳过状态、tabBar 补全和
101
+ * 变更检测都在快照里返回。`getPageMeta` / `getTabBar` 保留为兼容入口。
267
102
  */
268
- declare class Page {
269
- /** 页面上下文实例 */
270
- ctx: PageContext;
103
+ export declare class Page {
104
+ private readonly environment;
271
105
  /** 页面路径信息,包含相对路径与绝对路径 */
272
106
  path: PagePath;
273
107
  /** 页面 URI,用于 pages.json 的 path 字段 */
274
108
  uri: string;
275
- /** 页面是否发生变化,用于增量更新判断 */
276
- changed: boolean;
277
- /**
278
- * 页面是否通过 `definePage(null)` 或函数式宏在当前平台返回 null 而
279
- * 退出了 pages.json
280
- */
281
- skipped: boolean;
282
- /** 页面文件是否至少被读取过一次 */
109
+ private snapshot;
110
+ /** 当前读取缓存是否有效 */
283
111
  private loaded;
284
- /** 页面配置的原始 JSON 字符串,用于变更检测 */
112
+ /** 当前缓存是否已尝试读取;失败后等下次失效再重试 */
113
+ private readAttempted;
114
+ /** 上一次成功读取的配置,用于变更检测 */
285
115
  private raw;
286
- /** 解析后的页面配置 */
287
- private meta;
116
+ constructor(environment: PageEnvironment, path: PagePath);
117
+ /** 页面是否通过 definePage(null) 退出 */
118
+ get skipped(): boolean;
119
+ /** 页面内容是否相对上次成功读取发生变化 */
120
+ get changed(): boolean;
288
121
  /**
289
- * 创建页面实例
290
- * @param ctx - 页面上下文实例
291
- * @param path - 页面路径信息
292
- */
293
- constructor(ctx: PageContext, path: PagePath);
294
- /**
295
- * 获取页面配置
296
- * 解析 definePage 宏定义的配置并返回用于 pages.json 的配置
122
+ * 读取页面并返回快照
297
123
  *
298
- * @param forceUpdate - 是否强制更新,忽略缓存
299
- * @returns 页面配置对象
124
+ * @param forceUpdate - 忽略缓存强制重读
300
125
  */
301
- getPageMeta(forceUpdate?: boolean): Promise<InternalPageItem>;
126
+ load(forceUpdate?: boolean): Promise<PageSnapshot>;
302
127
  /**
303
- * 获取页面 tabBar 配置
304
- * 从 definePage 宏中提取 tabBar 相关配置
128
+ * 获取页面配置,保留给既有调用方
305
129
  *
306
- * @param forceUpdate - 是否强制更新,忽略缓存
307
- * @returns tabBar 配置对象,页面未定义 tabBar 时返回 undefined
130
+ * 返回副本:合并阶段会原地写 `type: 'home'`,不能让首页标记留在
131
+ * 读取快照里,否则增量更新会继续把旧首页当成首页。
308
132
  */
133
+ getPageMeta(forceUpdate?: boolean): Promise<InternalPageItem>;
134
+ /** 获取 tabBar 项,保留给既有调用方 */
309
135
  getTabBar(forceUpdate?: boolean): Promise<TabBarItem & {
310
136
  index: number;
311
137
  } | undefined>;
312
- /**
313
- * 确保页面文件至少被读取过一次,使 `skipped` 与缓存的配置反映
314
- * 当前文件内容
315
- */
138
+ /** 加载尚未读取的页面配置,缓存失效前不重复尝试失败的读取 */
316
139
  ensureLoaded(): Promise<void>;
317
140
  /**
318
- * 检查页面是否发生变化
319
- * @returns 页面是否发生变化
141
+ * 使页面读取缓存失效
142
+ *
143
+ * @description 下次访问时重新读取,保留上次成功快照作为读取失败时的回退
320
144
  */
145
+ invalidate(): void;
146
+ /** 检查页面是否发生变化 */
321
147
  hasChanged(): boolean;
322
148
  /**
323
149
  * 读取页面文件并解析配置
324
- * 从 Vue SFC 中提取 definePage 宏定义的配置
150
+ *
151
+ * @description 成功后替换快照;失败时保留上次成功快照,只记录警告
325
152
  */
326
153
  read(): Promise<void>;
154
+ private createSnapshot;
155
+ /** 读取失败且从未成功时的默认快照,保持页面仍以 uri 参与生成 */
156
+ private fallbackSnapshot;
327
157
  private readPageMetaFromFile;
328
158
  }
329
159
  //#endregion
330
160
  //#region src/types.d.ts
161
+ /** 提前生成页面配置所需的运行环境 */
162
+ interface PrepareOptions {
163
+ /**
164
+ * Vite 项目根目录,相对路径以当前工作目录为基准
165
+ *
166
+ * @default process.env.VITE_ROOT_DIR || process.cwd()
167
+ */
168
+ root?: string;
169
+ /** 是否采用 UniPlatform 文件名后缀规则,必须与最终插件列表一致 */
170
+ platformSuffix: boolean;
171
+ }
172
+ /**
173
+ * 支持提前生成页面配置的 Vite 插件实例
174
+ *
175
+ * @description 同一实例可在构建或开发服务器关闭后顺序复用;重叠运行的构建和服务器须各自创建实例
176
+ */
177
+ interface UniPagesPlugin extends Plugin {
178
+ /**
179
+ * 等待页面配置与已启用的声明文件生成,返回当前插件实例
180
+ *
181
+ * @description
182
+ * - 在创建需要读取 pages.json 的下游插件之前等待此方法完成
183
+ * - 使用调用时的 UNI_PLATFORM;根目录、平台和后缀规则必须与 Vite 初始化一致
184
+ * - 当前准备期间相同参数的并发或重复调用共享结果,首次 Vite 接管复用该结果
185
+ * - Vite 会话关闭后再次调用会重新生成;成功准备过的根目录、平台和后缀约束持续有效
186
+ * - 生成失败后可重试
187
+ *
188
+ * @throws 参数冲突、编译平台缺失、实例正在关闭或生成失败时拒绝 Promise
189
+ */
190
+ prepare: (options: PrepareOptions) => Promise<UniPagesPlugin>;
191
+ }
331
192
  /**
332
193
  * 从对象类型中排除索引签名键,仅保留显式键
333
194
  */
@@ -442,7 +303,7 @@ interface Options {
442
303
  /**
443
304
  * 页面配置文件的加载来源
444
305
  *
445
- * 基于 unconfig,支持合并多个配置来源
306
+ * @description 基于 unconfig,按来源顺序加载首个有效配置
446
307
  *
447
308
  * @default 'pages.config'
448
309
  * @since 0.2.7
@@ -478,9 +339,11 @@ interface Options {
478
339
  */
479
340
  dir: string;
480
341
  /**
481
- * uni-app 分包加载的子包页面目录
342
+ * uni-app 分包加载的页面目录
482
343
  *
483
- * 支持字符串形式(目录路径)或对象形式(pages.json 中的自定义 root)
344
+ * @description
345
+ * 支持字符串或对象形式的目录 glob,开发期间自动发现新增、删除和重命名的目录
346
+ * 对象的 root 可用同步回调根据匹配目录计算
484
347
  *
485
348
  * monorepo 项目中页面可能位于项目根目录之外。使用对象形式指定
486
349
  * 出现在 pages.json 中的自定义 root,避免生成的 root 路径含 '..'。
@@ -500,11 +363,15 @@ interface Options {
500
363
  */
501
364
  outDir: string;
502
365
  /**
503
- * 排除的文件/目录模式
366
+ * 页面排除的文件或目录模式
504
367
  *
505
- * 基于 [tinyglobby 的 ignore 选项](https://superchupu.dev/tinyglobby/documentation#ignore)
368
+ * @description
369
+ * - 相对模式基于 Vite root,绝对模式直接匹配对应路径;命中目录时排除整个子树
370
+ * - 主包、分包的扫描与页面事件使用相同规则
371
+ * - 自定义数组替换默认值,空数组禁用默认页面排除,空字符串忽略
372
+ * - 不接受 `!foo` 否定规则,`!(keep).vue` 等 extglob 有效
506
373
  *
507
- * @default ['node_modules', '.git', '**\/__*__/**']
374
+ * @default ['**\/node_modules/**', '**\/.git/**', '**\/__*__/**']
508
375
  * @since 0.0.4
509
376
  */
510
377
  exclude: string[];
@@ -566,9 +433,9 @@ interface Options {
566
433
  type UserOptions = Partial<Options>;
567
434
  /**
568
435
  * 解析后的配置项接口
569
- * 经 resolveOptions 处理的配置,所有路径均解析为绝对路径
436
+ * 保留原始扫描规则、展开后的目录和生成选项
570
437
  */
571
- interface ResolvedOptions extends Omit<Options, 'dir' | 'homePage' | 'configSource' | 'dts' | 'subPackages'> {
438
+ interface ResolvedOptions extends Omit<Options, 'homePage' | 'configSource' | 'dts' | 'subPackages'> {
572
439
  /**
573
440
  * 解析为 Vite 配置中的 `root` 值。
574
441
  * @default config.root
@@ -585,17 +452,20 @@ interface ResolvedOptions extends Omit<Options, 'dir' | 'homePage' | 'configSour
585
452
  homePage: string[];
586
453
  configSource: LoadConfigSource<PagesConfig>[];
587
454
  /**
588
- * 解析后的子包目录列表
455
+ * 解析后的分包目录列表
589
456
  */
590
457
  subPackages: string[];
458
+ /** 原始分包目录规则,用于重新发现目录 */
459
+ subPackagePatterns: (string | SubPackageConfig)[];
591
460
  /**
592
- * 子包的自定义 root 映射(目录 -> root)
593
- * 用于 monorepo 支持,指定 pages.json 中的自定义 root 路径
461
+ * 分包目录的 root 映射(目录 -> 最终 root)
462
+ *
463
+ * @description 未登记的目录继续使用相对 outDir 的默认 root
594
464
  */
595
465
  subPackageRootMap: Map<string, string>;
596
466
  }
597
467
  /**
598
- * 子包配置接口
468
+ * 分包配置接口
599
469
  * 为 monorepo 支持,允许自定义 pages.json 中的 root 路径
600
470
  *
601
471
  * monorepo 项目中页面可能位于项目根目录之外(如 ../../packages/login/src/pages)。
@@ -613,10 +483,38 @@ interface ResolvedOptions extends Omit<Options, 'dir' | 'homePage' | 'configSour
613
483
  * ```
614
484
  */
615
485
  interface SubPackageConfig {
616
- /** 扫描页面文件的实际物理目录路径 */
486
+ /** 扫描页面文件的物理目录或 glob,相对 Vite root 解析 */
617
487
  dir: string;
618
- /** 出现在 pages.json subPackages.root 中的自定义根路径 */
619
- root: string;
488
+ /**
489
+ * 出现在 pages.json subPackages.root 中的自定义根路径
490
+ *
491
+ * @description
492
+ * 回调同步接收相对 Vite root、使用 `/` 分隔且无末尾斜杠的匹配目录
493
+ * 返回值须为非空相对路径,不能包含 `..`;每次重新发现目录时会再次调用
494
+ */
495
+ root: string | ((dir: string) => string);
496
+ }
497
+ /** 最终分包 root 的决议来源 */
498
+ interface ScanSourceOrigin {
499
+ /** 提供 root 的词法目录,与对应分包目录来源的 dir 一致 */
500
+ dir: string;
501
+ /** 提供 root 的声明在 subPackagePatterns 中的索引,从 0 开始 */
502
+ ruleIndex: number;
503
+ /** 提供 root 的声明是否为显式来源 */
504
+ explicitRoot: boolean;
505
+ }
506
+ /** 扫描来源的词法目录及声明位置 */
507
+ interface ScanSourceCoordinate {
508
+ /** 扫描目录的词法路径,保留符号链接别名;相对路径以 Vite root 为基准 */
509
+ dir: string;
510
+ /** 当前声明是否显式提供 root,与是否继承其他声明的显式 root 无关 */
511
+ explicitRoot: boolean;
512
+ /** 主包为 0,分包为 subPackagePatterns 中的从零索引;hook 页面未关联声明时为 -1 */
513
+ ruleIndex: number;
514
+ /** 声明内从零开始的目录匹配索引;glob 按路径排序,无匹配记录时为 0 */
515
+ matchIndex: number;
516
+ /** 最终分包 root 的决议来源,可能来自另一声明;主包及未关联声明的 hook 页面无此值 */
517
+ rootSource?: ScanSourceOrigin;
620
518
  }
621
519
  /**
622
520
  * 页面路径信息接口
@@ -637,23 +535,460 @@ interface PagePath {
637
535
  * @param config - 页面配置对象
638
536
  * @returns 配置对象
639
537
  */
640
- declare function defineUniPages(config: UserPagesConfig): UserPagesConfig;
538
+ export declare function defineUniPages(config: UserPagesConfig): UserPagesConfig;
641
539
  //#endregion
642
540
  //#region src/constant.d.ts
643
541
  /** Vite 模块解析用的虚拟模块标识 */
644
- declare const MODULE_ID_VIRTUAL = "virtual:uni-pages";
542
+ export declare const MODULE_ID_VIRTUAL = "virtual:uni-pages";
645
543
  /** 加 \0 前缀解析后的虚拟模块标识,避免与其他模块冲突 */
646
- declare const RESOLVED_MODULE_ID_VIRTUAL = "\0virtual:uni-pages";
544
+ export declare const RESOLVED_MODULE_ID_VIRTUAL = "\0virtual:uni-pages";
647
545
  /** 输出文件名,即 uni-app 的页面配置文件 */
648
- declare const OUTPUT_NAME = "pages.json";
546
+ export declare const OUTPUT_NAME = "pages.json";
649
547
  /** 支持的页面文件扩展名 */
650
- declare const FILE_EXTENSIONS: string[];
548
+ export declare const FILE_EXTENSIONS: string[];
549
+ //#endregion
550
+ //#region src/pages-snapshot.d.ts
551
+ /**
552
+ * 一次生成的完整路由快照。
553
+ *
554
+ * 虚拟模块、路由字符串和声明文件都从这里取值。生成过程本身仍可以使用
555
+ * 可变的工作字段;创建快照时复制容器,后续工作字段的增删不会改变这次的结果,便于测试与虚拟模块读取保持一致。
556
+ */
557
+ interface PagesSnapshot {
558
+ pages: InternalPages;
559
+ subPackages: SubPackages;
560
+ tabBar?: TabBar;
561
+ globConfig?: PagesConfig;
562
+ homePath?: string;
563
+ }
564
+ //#endregion
565
+ //#region src/context.d.ts
566
+ /**
567
+ * 页面上下文:负责扫描页面、加载配置、合并页面信息、生成 pages.json
568
+ *
569
+ * 做的事情按固定顺序是:加载用户配置 → 扫描页面文件 → 合并页面
570
+ * 信息 → 写入 pages.json。这个顺序由 {@link updatePagesJSON}(完整
571
+ * 流程)或 {@link scanAndMerge}(只算不写)管理,调用方不用关心
572
+ * 内部步骤。
573
+ */
574
+ export declare class PageContext {
575
+ private _server;
576
+ private readonly configLoader;
577
+ private readonly watchers;
578
+ private readonly watchedConfigPaths;
579
+ /** 当前配置依赖与恢复范围;事件判定和路径展开都从这里取 */
580
+ private readonly configWatch;
581
+ /** 生成物(pages.json、d.ts)的绝对路径,只在首次事件时算一次 */
582
+ private generatedPathsCache;
583
+ private pendingUpdate;
584
+ private disposed;
585
+ private disposal;
586
+ /** 本轮扫描的目录、分包来源与规则;扫描和监听共用 */
587
+ private scanPlan;
588
+ /** 最近一次生成的完整快照;虚拟模块、路由与声明都读它 */
589
+ private generatedSnapshot;
590
+ /** 随扫描更新的 Page 来源,用于复用检查和冲突诊断 */
591
+ private readonly pageSources;
592
+ /** 扫描候选独立于归属裁剪后的输出映射,保留非代表来源的内容缓存 */
593
+ private mainPageCandidates;
594
+ private subPageCandidates;
595
+ private readonly pageWatcher;
596
+ /** 待处理的页面更新:生成期间到达的事件合并到下一轮 */
597
+ private pendingPageUpdate;
598
+ /** 当前事件更新循环;dispose 时等待它排空 */
599
+ private pendingPageFlush;
600
+ /** 页面监听启动参数;初始化失败时保留,后续生成会重试 */
601
+ private pageWatcherStart;
602
+ /** 当前配置本地依赖及加载失败后仍需监听的恢复路径 */
603
+ pagesConfigDependencyPaths: string[];
604
+ /** 从用户配置文件(pages.config.ts)解析出的配置对象 */
605
+ pagesGlobConfig: PagesConfig | undefined;
606
+ /** 用户配置文件的来源路径列表 */
607
+ pagesConfigSourcePaths: string[];
608
+ /** 主包页面映射,键为页面文件的词法绝对路径 */
609
+ pages: Map<string, Page>;
610
+ /** 分包页面映射,外层键为词法扫描目录,内层键为页面文件的词法绝对路径 */
611
+ subPages: Map<string, Map<string, Page>>;
612
+ /** 主包页面配置数组,用于生成 pages.json 的 pages 字段 */
613
+ pageMetaData: InternalPages;
614
+ /** 分包页面配置数组,用于生成 pages.json 的 subPackages 字段 */
615
+ subPageMetaData: SubPackages;
616
+ /**
617
+ * 最近一次合并出的 tabBar(配置文件与 definePage 声明的合体)。
618
+ * 类型声明生成 tab 页列表时用它,definePage 声明的 tabBar 页才能
619
+ * 一起从 navigateTo 的 url 类型里排除
620
+ */
621
+ tabBar: TabBar | undefined;
622
+ /** 生成的 pages.json 文件路径 */
623
+ resolvedPagesJSONPath: string;
624
+ /** 项目根目录 */
625
+ root: string;
626
+ /** 解析后的配置项 */
627
+ options: ResolvedOptions;
628
+ /** 当前平台标识,如 'mp-weixin';由调用方传入,不依赖模块加载时冻结的环境 */
629
+ readonly platform: string;
630
+ logger?: Logger;
631
+ /** 是否与 vite-plugin-uni-platform 插件协同工作 */
632
+ withUniPlatform: boolean;
633
+ /** pages.json 中页面路径的解析基准路径 */
634
+ private get basePath();
635
+ /**
636
+ * 创建 PageContext 实例
637
+ * @param userOptions - 用户配置项
638
+ * @param viteRoot - Vite 项目根目录,默认为当前工作目录
639
+ * @param platform - 当前平台标识,默认取 uni-env 的平台
640
+ */
641
+ constructor(userOptions: UserOptions, viteRoot?: string, platform?: string);
642
+ /**
643
+ * 设置 Vite logger
644
+ * @param logger - Vite logger 实例
645
+ */
646
+ setLogger(logger: Logger): void;
647
+ /**
648
+ * 加载用户页面配置文件(如 pages.config.ts)
649
+ * 使用 unconfig 加载配置,支持多种配置文件格式
650
+ */
651
+ loadUserPagesConfig(): Promise<void>;
652
+ /**
653
+ * 按顺序跑完扫描与合并:先扫描主包和分包的页面,再合并它们的
654
+ * 信息。步骤顺序只维护在这里,调用方和测试都不用关心。
655
+ */
656
+ scanAndMerge(): Promise<void>;
657
+ /** 刷新本轮扫描计划,并同步兼容投影供既有调用方读取 */
658
+ private refreshScanPlan;
659
+ /** 扫描与监听阶段读取本轮计划;计划在 refreshScanPlan 之后必定存在 */
660
+ private requireScanPlan;
661
+ /**
662
+ * 设置 Vite 开发服务器,用于 HMR 与文件监听
663
+ * @param server - Vite 开发服务器实例
664
+ */
665
+ setupViteServer(server: ViteDevServer): void;
666
+ /**
667
+ * 生成物(pages.json 与 d.ts)的绝对路径
668
+ *
669
+ * 只依赖构造后不再变化的 `options` 与 `resolvedPagesJSONPath`,
670
+ * 算一次缓存即可,不必每个事件重新解析
671
+ */
672
+ private generatedFilePaths;
673
+ /** 按当前词法规则识别页面事件,真实路径只用于关联已收录来源 */
674
+ private pageFileForEvent;
675
+ private pageDirectoryForEvent;
676
+ /**
677
+ * 注册配置文件与页面目录结构监听,并启动页面内容监听
678
+ *
679
+ * @param watcher - 配置文件及目录结构事件使用的 chokidar 监听器
680
+ */
681
+ setupWatcher(watcher: FSWatcher): Promise<void>;
682
+ /**
683
+ * 启动页面监听
684
+ *
685
+ * @description 初始化失败只记录并保留启动参数,后续生成会重新尝试;监听属于辅助
686
+ * 能力,不能阻断页面生成,也不能留下未处理的拒绝
687
+ */
688
+ private startPageWatcher;
689
+ /**
690
+ * 释放本上下文的监听与待处理更新
691
+ *
692
+ * @description 关闭后不再接受监听注册或更新;已开始的生成会完成,重复调用等待同一次释放
693
+ * 共享 watcher 的关闭仍由 Vite 负责
694
+ */
695
+ disposeWatchers(): Promise<void>;
696
+ /** 补充未覆盖的监听路径,注册成功后记账,失败时保留重试机会 */
697
+ private addWatchPaths;
698
+ /**
699
+ * 让监听路径与当前配置依赖保持一致
700
+ *
701
+ * 只新增路径,从不 unwatch:chokidar 对文件调用 unwatch 会连带
702
+ * 拆掉父目录监听,新建文件就再也发现不了。因此监听集合是并集,
703
+ * 会随着会话累积;每次刷新都按当前依赖重建配置监听计划,
704
+ * 真正决定是否触发的始终是计划里的依赖集合(恢复目录除外,那是
705
+ * 故意留的兜底)。
706
+ */
707
+ private refreshConfigWatchers;
708
+ /** 配置变化的完整更新:失败只记录,不让 Promise 拒绝 */
709
+ private updatePagesAndNotify;
710
+ /** 记录 watcher 更新失败,避免未处理的拒绝终止进程 */
711
+ private logUpdateFailure;
712
+ /**
713
+ * 登记页面事件触发的更新:生成期间到达的事件合并到下一轮
714
+ *
715
+ * @description 连续删除、重建会一次性派发大量事件,逐个生成会反复
716
+ * 重读全部页面;内容变更合并待刷新文件,结构变更执行完整刷新
717
+ * @param filepath - 只读取该页面;省略时执行完整扫描
718
+ */
719
+ private queuePageUpdate;
720
+ /**
721
+ * 排空页面事件队列;失败只记录,不让 Promise 拒绝
722
+ *
723
+ * 页面事件的回调走这里而不是直接调 {@link updatePagesJSON}:一旦
724
+ * 它拒绝(拿不到文件锁、声明文件写不进去),就成了未处理的拒绝,
725
+ * Node 默认直接终止进程。开发时正在编辑文件,一次偶发的锁冲突
726
+ * 不该把 dev server 打死。用户改一次文件就会再触发一次事件,
727
+ * 所以这里报错即可。
728
+ */
729
+ private flushPageUpdates;
730
+ /**
731
+ * 页面更新回调,页面文件或配置变化时触发
732
+ * 负责使虚拟模块失效并通知浏览器整页刷新
733
+ */
734
+ onUpdate(): void;
735
+ /**
736
+ * 刷新页面配置并更新 pages.json
737
+ *
738
+ * @description 同一实例的调用按顺序执行;指定页面时尝试增量读取,页面尚未收录或物理身份变化时执行完整刷新
739
+ *
740
+ * @param filepath 变更页面的绝对路径或相对 root 的路径;省略时执行完整刷新
741
+ * @returns pages.json 写入新内容时为 `true`,内容未变、上下文已关闭或跳过生成时为 `false`
742
+ * @throws 生成、写入或声明输出失败时拒绝;声明输出失败前 pages.json 可能已更新
743
+ */
744
+ updatePagesJSON(filepath?: string): Promise<boolean>;
745
+ private enqueuePagesUpdate;
746
+ private generatePagesJSON;
747
+ /** 最近一次生成的路由快照;未写入文件时由当前工作字段合成 */
748
+ get snapshot(): PagesSnapshot;
749
+ /**
750
+ * 生成虚拟模块内容
751
+ * 返回包含 pages 与 subPackages 导出的 JavaScript 代码
752
+ * @returns 虚拟模块代码字符串
753
+ */
754
+ virtualModule(): string;
755
+ /**
756
+ * 将主包路由数据解析为 JSON 字符串
757
+ * @returns 主包页面配置的 JSON 字符串
758
+ */
759
+ resolveRoutes(): string;
760
+ /**
761
+ * 将分包路由数据解析为 JSON 字符串
762
+ * @returns 分包页面配置的 JSON 字符串
763
+ */
764
+ resolveSubRoutes(): string;
765
+ /**
766
+ * 解析 tabBar 配置
767
+ * 将页面定义的 tabBar 项与配置文件定义的 tabBar 合并
768
+ * @returns 合并后的 tabBar 配置对象,无 tabBar 时为 undefined
769
+ */
770
+ resolveTabBar(): Promise<TabBar | undefined>;
771
+ /**
772
+ * 生成 TypeScript 声明文件
773
+ * 为页面路径生成类型定义,导航时提供类型提示
774
+ */
775
+ generateDeclaration(): Promise<void> | undefined;
776
+ /**
777
+ * 按词法目录扫描主包页面
778
+ *
779
+ * @description 各目录分别执行文件排除,物理别名保留到页面有效性与归属决议阶段
780
+ */
781
+ private scanPages;
782
+ /**
783
+ * 登记本轮来源并复用身份与输出基准均未变化的 Page
784
+ *
785
+ * @description 整轮更新使读取缓存失效,增量更新复用目标页的预读结果与其他页面缓存
786
+ * @returns 路径仍存在时返回页面实例,扫描期间已消失时为 undefined
787
+ */
788
+ private trackPage;
789
+ private pageEnvironment;
790
+ /** 页面来源的原始声明规则,用于冲突诊断;hook 页面可能没有 */
791
+ private configuredRule;
792
+ /**
793
+ * 按词法路径或物理身份查找全部缓存候选
794
+ * @param filepath - 页面文件的绝对路径
795
+ * @returns 主包和分包中属于同一文件的页面实例,每个实例只返回一次
796
+ */
797
+ private findPages;
798
+ /**
799
+ * 按词法来源扫描分包页面
800
+ *
801
+ * @description 同一物理目录的不同别名仍分别执行文件排除,避免某个别名被排除后漏页
802
+ */
803
+ private scanSubPages;
804
+ /**
805
+ * 为每个物理扫描目录选取声明来源
806
+ *
807
+ * @description 同一路径的不同写法只扫描一次,定位信息按显式优先选择;
808
+ * 符号链接别名是不同的 absolute,仍分别保留各自的词法路径
809
+ */
810
+ private subPackageSourcesByDir;
811
+ /** 获取目录的最终分包 root,未登记时相对 outDir 计算默认值 */
812
+ private subPackageRoot;
813
+ /**
814
+ * 决议有效页面的归属并校验生成路由
815
+ *
816
+ * @description 先读取宏并应用既有平台规则,再选择代表;冲突校验通过后才裁剪页面映射,
817
+ * 配置覆盖与输出去重在此之后执行
818
+ */
819
+ private resolveScanSources;
820
+ /**
821
+ * 解析 pages 规则并设置页面类型
822
+ * @param pages 页面路径映射
823
+ * @param packageType 页面包类型(主包或分包)
824
+ * @param overrides 自定义页面配置
825
+ * @returns pages 规则
826
+ */
827
+ private parsePages;
828
+ /**
829
+ * 设置首页
830
+ * @param result pages 规则数组
831
+ * @returns pages 规则
832
+ */
833
+ private setHomePage;
834
+ /**
835
+ * 决议扫描来源后合并主包页面配置
836
+ *
837
+ * @description 有效分包优先认领物理页面,生成来源冲突在用户配置覆盖前检查
838
+ */
839
+ private mergePageMetaData;
840
+ /**
841
+ * 合并分包页面配置
842
+ *
843
+ * @description 静态、glob 和回调来源先按最终 root 汇集,再对整组应用一次配置覆盖,
844
+ * 保留手工页面和分包 plugins 配置
845
+ */
846
+ private mergeSubPageMetaData;
847
+ }
848
+ /**
849
+ * 应用 vite-plugin-uni-platform 的页面文件名后缀规则(如 `index.h5.vue`
850
+ * 对应页面 `index`):丢弃其他平台的后缀页面,保留当前平台的并把文件名
851
+ * 里的后缀剥掉。
852
+ *
853
+ * 带点的判断只看路径最后一段(文件名),和 vite-plugin-uni-platform
854
+ * 自己的规则一致(它也只在文件名上判断后缀),目录名里的点(如
855
+ * `pages/v1.2/detail`)不算平台后缀。
856
+ *
857
+ * 注意后缀匹配仍是原始的 `path.includes(platform)`,没有做 definePage
858
+ * 那边 h5/web 的别名换算(见 condition.ts 的 platformMatches):
859
+ * UNI_PLATFORM=web 时,`.h5` 后缀的页面会被过滤掉。这是一直以来的
860
+ * 行为,为了和 vite-plugin-uni-platform 自己的命名规则保持一致而保留。
861
+ *
862
+ * @param pages - 合并后的主包页面配置
863
+ * @param platform - 当前平台标识
864
+ * @returns 过滤并剥掉后缀的新数组,入参不被修改
865
+ */
866
+ export declare function filterPlatformSuffixPages(pages: InternalPages, platform: string): InternalPages;
867
+ //#endregion
868
+ //#region src/directories.d.ts
869
+ /**
870
+ * 规范化页面目录选择器中的路径分隔符
871
+ *
872
+ * @description 在 Windows 上将反斜杠路径分隔符转换为 `/`,保留 `\[`、`\(` 等 glob 转义
873
+ *
874
+ * @param pattern 页面目录路径或 glob 表达式
875
+ * @returns Windows 返回规范化后的选择器,其他平台返回原字符串
876
+ *
877
+ * @example
878
+ * ```ts
879
+ * normalizePagePattern('src\\pages') // Windows: 'src/pages'
880
+ * ```
881
+ */
882
+ export declare function normalizePagePattern(pattern: string): string;
883
+ /**
884
+ * 将目录选择器中的 glob 转义还原为字面字符
885
+ *
886
+ * @description 用于已经确定的固定路径部分,还原后的字符串可传给 `path.resolve` 等路径 API
887
+ *
888
+ * @param pattern 以 `/` 分隔、可包含 glob 转义的固定目录路径
889
+ * @returns 去除 glob 特殊字符前转义反斜杠的路径字符串
890
+ *
891
+ * @example
892
+ * ```ts
893
+ * unescapePagePattern('src/\\[demo\\]') // 'src/[demo]'
894
+ * ```
895
+ */
896
+ export declare function unescapePagePattern(pattern: string): string;
897
+ /**
898
+ * 查找当前可扫描的页面目录
899
+ *
900
+ * @description 应用目录排除后,返回相对 root、按路径排序的匹配结果;空规则或否定规则返回空数组
901
+ *
902
+ * @param dir 页面目录 glob,可使用绝对路径
903
+ * @param root 相对目录和相对 exclude 的解析基准
904
+ * @param exclude 目录及页面排除规则
905
+ */
906
+ export declare function resolvePageDirs(dir: string, root: string, exclude: string[]): string[];
907
+ /** 单次分包目录发现保留的来源记录 */
908
+ export interface SubPackageDirectorySource extends ScanSourceCoordinate {
909
+ /**
910
+ * 扫描目录的词法路径,与 subPackages 的目录投影一致
911
+ *
912
+ * @description glob 或回调来源相对 Vite root,静态来源保留声明的绝对或相对写法
913
+ */
914
+ dir: string;
915
+ /** 相对 Vite root 解析的绝对路径,保留符号链接别名 */
916
+ absolute: string;
917
+ /** 目录的 realpath 身份;缺失、非目录或解析期间消失时为 undefined */
918
+ identity?: string;
919
+ /** 同一物理目录完成显式/默认来源决议后的最终分包 root */
920
+ root: string;
921
+ /** 最终 root 的选择来源,可能与当前声明不同 */
922
+ rootSource: ScanSourceOrigin;
923
+ }
924
+ type SubPackageDirectoryProjection = Pick<ResolvedOptions, 'subPackages' | 'subPackageRootMap'>;
925
+ /** 展开分包声明,返回逐条来源记录和扫描目录投影 */
926
+ export declare function discoverSubPackageDirectories(patterns: (string | SubPackageConfig)[], root: string, outDir: string, exclude: string[]): {
927
+ sources: SubPackageDirectorySource[];
928
+ projection: SubPackageDirectoryProjection;
929
+ };
930
+ /**
931
+ * 展开分包目录并确定各目录的最终 root
932
+ *
933
+ * @description 每次调用重新发现目录并求值回调;按声明顺序排列,glob 内按路径排序
934
+ * 同一物理目录的显式 root 优先于默认值,词法别名分别保留,重复目录投影只登记一次
935
+ *
936
+ * @param patterns 原始分包目录声明
937
+ * @param root 相对目录和相对 exclude 的解析基准
938
+ * @param outDir 默认分包 root 的换算基准,相对 root 解析
939
+ * @param exclude 目录及页面排除规则
940
+ * @returns 目录列表及最终 root 映射
941
+ * @throws 目录规则无效、root 回调失败、显式 root 冲突或非缺失类目录访问错误
942
+ */
943
+ export declare function resolveSubPackageDirs(patterns: (string | SubPackageConfig)[], root: string, outDir: string, exclude: string[]): SubPackageDirectoryProjection;
944
+ /**
945
+ * 读取当前分包目录来源
946
+ *
947
+ * @description 每次调用重新发现目录并求值回调;需要与扫描共用同一份结果时,
948
+ * 使用 ScanPlan 而不是在扫描中途再次调用
949
+ *
950
+ * @returns 按声明及匹配顺序排列的来源,调用方应只读使用记录
951
+ * @throws 目录规则、root 决议或目录访问错误
952
+ */
953
+ export declare function getSubPackageDirectorySources(options: ResolvedOptions): readonly SubPackageDirectorySource[];
954
+ /**
955
+ * 刷新扫描目录与分包 root 投影
956
+ *
957
+ * @description 仅用于兼容仍读取 `ResolvedOptions` 的调用方;内部扫描走
958
+ * `createScanPlan()`,每次重新发现目录来源与物理身份,不保留上一轮快照
959
+ *
960
+ * @throws 目录规则、root 决议或目录访问失败时抛出,应中止本轮扫描
961
+ */
962
+ export declare function refreshPageDirectories(options: ResolvedOptions): void;
963
+ /**
964
+ * 判断目录事件是否可能改变扫描目录集合
965
+ *
966
+ * @description directory 相对 options.root 解析,允许目录已删除;关闭 mergePages 时返回 false
967
+ */
968
+ export declare function isPageDirectoryEvent(directory: string, options: ResolvedOptions): boolean;
969
+ /**
970
+ * 判断文件路径是否位于当前页面规则内
971
+ *
972
+ * @description file 相对 options.root 解析,按原始规则与 exclude 判断,不要求文件存在或目录已展开
973
+ * 关闭 mergePages 时返回 false,文件扩展名由调用方校验
974
+ */
975
+ export declare function isPageFileInDirectories(file: string, options: ResolvedOptions): boolean;
651
976
  //#endregion
652
977
  //#region src/files.d.ts
653
978
  /**
654
- * 解析给定上下文下可作为有效页面的文件列表。
979
+ * 判断是否为路径缺失或中间路径不是目录的文件系统错误
980
+ *
981
+ * @returns 错误码为 ENOENT 或 ENOTDIR 时返回 true,其他错误及空输入返回 false
982
+ */
983
+ export declare function isMissingFsError(error: unknown): boolean;
984
+ /**
985
+ * 获取扫描目录中未被排除的页面文件
986
+ *
987
+ * @param directory - 绝对扫描目录,或相对项目根的目录
988
+ * @param options - 已解析的页面选项,排除规则以其中的项目根为基准
989
+ * @returns 相对扫描目录、使用 `/` 分隔的文件路径
655
990
  */
656
- declare function getPageFiles(path: string, options: ResolvedOptions): string[];
991
+ export declare function getPageFiles(directory: string, options: ResolvedOptions): string[];
657
992
  /**
658
993
  * 检查文件是否为目标页面文件
659
994
  * 判断文件扩展名是否在支持的页面文件类型列表中
@@ -661,7 +996,7 @@ declare function getPageFiles(path: string, options: ResolvedOptions): string[];
661
996
  * @param path - 文件路径
662
997
  * @returns 是否为目标文件
663
998
  */
664
- declare function isTargetFile(path: string): boolean;
999
+ export declare function isTargetFile(path: string): boolean;
665
1000
  /**
666
1001
  * 根据项目根目录与输出目录解析 pages.json 文件路径
667
1002
  *
@@ -669,7 +1004,7 @@ declare function isTargetFile(path: string): boolean;
669
1004
  * @param outDir - 相对 root 的 pages.json 输出目录
670
1005
  * @returns pages.json 绝对路径
671
1006
  */
672
- declare function resolvePagesJsonPath(root: string, outDir: string): string;
1007
+ export declare function resolvePagesJsonPath(root: string, outDir: string): string;
673
1008
  /**
674
1009
  * 确保这个路径上有一个能用的 pages.json 文件。
675
1010
  *
@@ -683,7 +1018,7 @@ declare function resolvePagesJsonPath(root: string, outDir: string): string;
683
1018
  * @throws 路径存在但不是普通文件、缺少读写权限,或占位文件创建失败时
684
1019
  * 抛出
685
1020
  */
686
- declare function checkPagesJsonFileSync(path: fs.PathLike): void;
1021
+ export declare function checkPagesJsonFileSync(path: fs.PathLike): void;
687
1022
  /**
688
1023
  * 拿到文件的独占锁后运行任务,运行完自动放锁。
689
1024
  *
@@ -699,8 +1034,9 @@ declare function checkPagesJsonFileSync(path: fs.PathLike): void;
699
1034
  * @param task - 在锁内运行的异步任务;返回值原样返回给调用方
700
1035
  * @param retry - 锁被别人拿着时的重试次数,默认 3
701
1036
  * @returns `task` 的结果;一直拿不到锁时为 `undefined`
1037
+ * @throws 权限不足、路径缺失等非竞争错误原样抛出,不重试
702
1038
  */
703
- declare function withFileLock<T>(path: string, task: () => Promise<T>, retry?: number): Promise<T | undefined>;
1039
+ export declare function withFileLock<T>(path: string, task: () => Promise<T>, retry?: number): Promise<T | undefined>;
704
1040
  //#endregion
705
1041
  //#region src/macro.d.ts
706
1042
  /**
@@ -722,7 +1058,7 @@ declare function withFileLock<T>(path: string, task: () => Promise<T>, retry?: n
722
1058
  * @param options - 解析选项
723
1059
  * @returns SFC descriptor 对象
724
1060
  */
725
- declare function parseSFC(code: string, options?: SFCParseOptions): SFCDescriptor;
1061
+ export declare function parseSFC(code: string, options?: SFCParseOptions): SFCDescriptor;
726
1062
  /**
727
1063
  * 求值 Vue SFC 里的 definePage 宏,返回页面信息
728
1064
  *
@@ -735,7 +1071,7 @@ declare function parseSFC(code: string, options?: SFCParseOptions): SFCDescripto
735
1071
  * @returns 页面信息对象;宏明确退出(definePage(null) 或函数返回
736
1072
  * null)时为 `null`;没找到 definePage 时为 undefined
737
1073
  */
738
- declare function evaluateDefinePage(code: string, filename: string, platform?: string): Promise<UserPageItem | null | undefined>;
1074
+ export declare function evaluateDefinePage(code: string, filename: string, platform?: string): Promise<UserPageItem | null | undefined>;
739
1075
  /**
740
1076
  * 在 Vue SFC 中定位 definePage 宏调用但不求值
741
1077
  *
@@ -748,7 +1084,7 @@ declare function evaluateDefinePage(code: string, filename: string, platform?: s
748
1084
  * @param options.onParseError - 以失败的 script 块名与错误对象调用
749
1085
  * @returns definePage 调用表达式,未找到时为 undefined
750
1086
  */
751
- declare function findDefinePageMacro(code: string, filename: string, options?: {
1087
+ export declare function findDefinePageMacro(code: string, filename: string, options?: {
752
1088
  onParseError?: (block: string, error: unknown) => void;
753
1089
  }): CallExpression | undefined;
754
1090
  //#endregion
@@ -761,15 +1097,7 @@ declare function findDefinePageMacro(code: string, filename: string, options?: {
761
1097
  * @param viteRoot - Vite 项目根目录
762
1098
  * @returns 解析后的配置项
763
1099
  */
764
- declare function resolveOptions(userOptions: UserOptions, viteRoot?: string): ResolvedOptions;
765
- /**
766
- * 根据给定的 glob 模式解析页面目录
767
- * @param dir - 页面目录 glob 模式
768
- * @param root - 项目根目录
769
- * @param exclude - 需要排除的 glob 模式
770
- * @returns 匹配到的目录路径
771
- */
772
- declare function resolvePageDirs(dir: string, root: string, exclude: string[]): string[];
1100
+ export declare function resolveOptions(userOptions: UserOptions, viteRoot?: string): ResolvedOptions;
773
1101
  //#endregion
774
1102
  //#region src/pages-json.d.ts
775
1103
  /**
@@ -779,6 +1107,8 @@ declare function resolvePageDirs(dir: string, root: string, exclude: string[]):
779
1107
  * - 多个平台共用一个文件时,用 #ifdef 注释区分各自的条目(合并规则
780
1108
  * 的核心在 platform-variants.ts,数组侧的适配在这里,对象侧
781
1109
  * tabBar 属性的适配在 tab-bar.ts)
1110
+ * - tabBar list 的条目顺序:配置覆盖全部既有条目时按配置顺序输出,
1111
+ * 否则新增条目落到声明位置、既有条目保持磁盘序(规则 6)
782
1112
  * - 合并时保持首页排最前
783
1113
  * - 写入"由插件生成"的标记,靠它识别哪些条目是插件写的
784
1114
  * - 序列化格式(缩进、换行)
@@ -789,13 +1119,13 @@ declare function resolvePageDirs(dir: string, root: string, exclude: string[]):
789
1119
  *
790
1120
  * 当前平台用不到的区块怎么处理,分两种情况:
791
1121
  * - tabBar 的外观属性:uni-app 条件编译能把整段剥掉,保留并包上 #ifdef
792
- * - 没有任何页面的子包:构建产物里会留下指向不存在目录的空壳,直接删掉
1122
+ * - 没有任何页面的分包:构建产物里会留下指向不存在目录的空壳,直接删掉
793
1123
  */
794
1124
  /** 由扫描/合并流水线组装出的路由数据 */
795
- interface PagesJsonData {
1125
+ export interface PagesJsonData {
796
1126
  /** 主包页面配置 */
797
1127
  pages: InternalPages;
798
- /** 子包页面配置 */
1128
+ /** 分包页面配置 */
799
1129
  subPackages: SubPackages;
800
1130
  /** 解析后的 tabBar 配置 */
801
1131
  tabBar?: TabBar;
@@ -807,7 +1137,7 @@ interface PagesJsonData {
807
1137
  homePath?: string;
808
1138
  }
809
1139
  /** 生成 pages.json 时怎么排版 */
810
- interface PagesJsonFormatOptions {
1140
+ export interface PagesJsonFormatOptions {
811
1141
  /**
812
1142
  * 压缩成一行输出,优先级高于 `indent`。单行 JSON 放不下注释,
813
1143
  * 生成标记、用户注释、所有 `#ifdef` 块都会丢失:只属于其他平台的
@@ -823,7 +1153,7 @@ interface PagesJsonFormatOptions {
823
1153
  /** 是否在末尾追加换行符 */
824
1154
  insertFinalNewline?: boolean;
825
1155
  }
826
- interface WritePagesJsonOptions {
1156
+ export interface WritePagesJsonOptions {
827
1157
  /** 当前平台标识,如 'mp-weixin' 或 'h5' */
828
1158
  platform: string;
829
1159
  /** 来自 pages.config.ts 的用户配置;pages/subPackages/tabBar 之外的字段原样写进输出 */
@@ -832,7 +1162,7 @@ interface WritePagesJsonOptions {
832
1162
  format?: PagesJsonFormatOptions;
833
1163
  }
834
1164
  /** 纯合并步骤的选项:{@link WritePagesJsonOptions} 中与文件无关的部分 */
835
- type MergePagesJsonOptions = Pick<WritePagesJsonOptions, 'platform' | 'globConfig' | 'format'>;
1165
+ export type MergePagesJsonOptions = Pick<WritePagesJsonOptions, 'platform' | 'globConfig' | 'format'>;
836
1166
  /**
837
1167
  * 把路由数据合并进 pages.json 并写回
838
1168
  *
@@ -846,13 +1176,22 @@ type MergePagesJsonOptions = Pick<WritePagesJsonOptions, 'platform' | 'globConfi
846
1176
  * @param options - 平台、用户配置与序列化格式
847
1177
  * @returns 写入结果;获取不到文件锁时为 undefined
848
1178
  */
849
- declare function writePagesJson(jsonPath: string, data: PagesJsonData, options: WritePagesJsonOptions): Promise<{
1179
+ export declare function writePagesJson(jsonPath: string, data: PagesJsonData, options: WritePagesJsonOptions): Promise<{
850
1180
  updated: boolean;
851
1181
  content: string;
852
1182
  } | undefined>;
1183
+ /**
1184
+ * Retries an async operation up to 3 times on EPERM, waiting 50ms between
1185
+ * attempts. Other errors propagate immediately.
1186
+ *
1187
+ * Windows file rename (used by write-file-atomic) can fail with EPERM when
1188
+ * another process holds the destination open with a sharing mode that excludes
1189
+ * rename (e.g. chokidar's watcher). The lock clears in under a frame.
1190
+ */
1191
+ export declare function retryOnEperm(operation: () => Promise<unknown>): Promise<void>;
853
1192
  /**
854
1193
  * 不碰文件系统,只做计算:把路由数据合并进现有 pages.json 文本
855
- * (多平台 `#ifdef` 块、首页重排、生成标记、过期子包清理)并序列化
1194
+ * (多平台 `#ifdef` 块、首页重排、生成标记、过期分包清理)并序列化
856
1195
  * 成字符串。文件锁、变更检测和原子写入都在 {@link writePagesJson}
857
1196
  * 里;测试直接用字符串检查这个函数。
858
1197
  *
@@ -861,7 +1200,7 @@ declare function writePagesJson(jsonPath: string, data: PagesJsonData, options:
861
1200
  * @param options - 平台、用户配置与序列化格式
862
1201
  * @returns 序列化后的 pages.json 内容
863
1202
  */
864
- declare function mergePagesJson(existingContent: string, data: PagesJsonData, options: MergePagesJsonOptions): string;
1203
+ export declare function mergePagesJson(existingContent: string, data: PagesJsonData, options: MergePagesJsonOptions): string;
865
1204
  //#endregion
866
1205
  //#region src/pipeline.d.ts
867
1206
  /**
@@ -873,7 +1212,7 @@ declare function mergePagesJson(existingContent: string, data: PagesJsonData, op
873
1212
  * 也是这里的调用方;测试通过这个入口跑完整流程,不去碰内部步骤。
874
1213
  */
875
1214
  /** 可以从外面传进来的流水线输入 */
876
- interface PipelineOverrides {
1215
+ export interface PipelineOverrides {
877
1216
  /** 项目根目录,默认为当前工作目录 */
878
1217
  root?: string;
879
1218
  /** 当前平台标识,如 'mp-weixin';默认取 uni-env 的平台 */
@@ -889,7 +1228,7 @@ interface PipelineOverrides {
889
1228
  * @param overrides - 从外面传入的 root 与 platform
890
1229
  * @returns 完成扫描与合并的 PageContext
891
1230
  */
892
- declare function createPages(userOptions?: UserOptions, overrides?: PipelineOverrides): Promise<PageContext>;
1231
+ export declare function createPages(userOptions?: UserOptions, overrides?: PipelineOverrides): Promise<PageContext>;
893
1232
  /**
894
1233
  * 运行完整流水线:加载用户配置、扫描、合并并写入 pages.json
895
1234
  * (以及 TypeScript 声明文件)
@@ -898,7 +1237,7 @@ declare function createPages(userOptions?: UserOptions, overrides?: PipelineOver
898
1237
  * @param overrides - 从外面传入的 root 与 platform
899
1238
  * @returns pages.json 是否有更新,以及产出它的上下文
900
1239
  */
901
- declare function generateAll(userOptions?: UserOptions, overrides?: PipelineOverrides): Promise<{
1240
+ export declare function generateAll(userOptions?: UserOptions, overrides?: PipelineOverrides): Promise<{
902
1241
  updated: boolean;
903
1242
  ctx: PageContext;
904
1243
  }>;
@@ -916,6 +1255,6 @@ declare function generateAll(userOptions?: UserOptions, overrides?: PipelineOver
916
1255
  * @param userOptions - 用户配置项
917
1256
  * @returns Vite 插件实例
918
1257
  */
919
- declare function VitePluginUniPages(userOptions?: UserOptions): Plugin;
1258
+ export declare function VitePluginUniPages(userOptions?: UserOptions): UniPagesPlugin;
920
1259
  //#endregion
921
- export { type ConfigSource, type DebugType, DefineConditional, type DefinePage, type DefinePageContext, type ExcludeIndexSignature, FILE_EXTENSIONS, type InternalPageItem, type InternalPages, MODULE_ID_VIRTUAL, type MaybeCallable, type MaybePromise, type MaybePromiseCallable, MergePagesJsonOptions, OUTPUT_NAME, type Options, Page, PageContext, type PagePath, PagesJsonData, PagesJsonFormatOptions, PipelineOverrides, RESOLVED_MODULE_ID_VIRTUAL, type ResolvedOptions, type SubPackageConfig, type UserOptions, type UserPageItem, type UserTabBarItem, VitePluginUniPages, VitePluginUniPages as default, WritePagesJsonOptions, checkPagesJsonFileSync, createPages, debug, type debugType, type definePage, defineUniPages, evaluateDefinePage, filterPlatformSuffixPages, findDefinePageMacro, generateAll, getPageFiles, isConditional, isTargetFile, mergePagesJson, parseSFC, resolveConditional, resolveOptions, resolvePageDirs, resolvePagesJsonPath, withFileLock, writePagesJson };
1260
+ export { type ConfigSource, type DebugType, type DefinePage, type DefinePageContext, type ExcludeIndexSignature, type InternalPageItem, type InternalPages, type MaybeCallable, type MaybePromise, type MaybePromiseCallable, type Options, type PagePath, type PrepareOptions, type ResolvedOptions, type ScanSourceCoordinate, type ScanSourceOrigin, type SubPackageConfig, type UniPagesPlugin, type UserOptions, type UserPageItem, type UserTabBarItem, VitePluginUniPages as default, type debugType, type definePage };