@uni-helper/vite-plugin-uni-pages 0.3.23 → 0.4.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.
package/dist/index.cjs CHANGED
@@ -1,91 +1,111 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- const path = require('node:path');
6
- const process = require('node:process');
7
- const astKit = require('ast-kit');
8
- const chokidar = require('chokidar');
9
- const kolorist = require('kolorist');
10
- const MagicString = require('magic-string');
11
- const vite = require('vite');
12
- const fs = require('node:fs');
13
- const uniEnv = require('@uni-helper/uni-env');
14
- const commentJson = require('comment-json');
15
- const Debug = require('debug');
16
- const detectIndent = require('detect-indent');
17
- const detectNewline = require('detect-newline');
18
- const unconfig = require('unconfig');
19
- const promises = require('node:fs/promises');
20
- const fg = require('fast-glob');
21
- const lockfile = require('proper-lockfile');
22
- const writeFileAtomic = require('write-file-atomic');
23
- const node_module = require('node:module');
24
- const vm = require('node:vm');
25
- const babelGenerator = require('@babel/generator');
26
- const groupBy = require('lodash.groupby');
27
- const ts = require('typescript');
28
- const t = require('@babel/types');
29
- const compilerSfc = require('@vue/compiler-sfc');
30
- const JSON5 = require('json5');
31
- const yaml = require('yaml');
32
-
33
- function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
34
-
35
- function _interopNamespaceCompat(e) {
36
- if (e && typeof e === 'object' && 'default' in e) return e;
37
- const n = Object.create(null);
38
- if (e) {
39
- for (const k in e) {
40
- n[k] = e[k];
41
- }
42
- }
43
- n.default = e;
44
- return n;
45
- }
46
-
47
- const path__default = /*#__PURE__*/_interopDefaultCompat(path);
48
- const process__default = /*#__PURE__*/_interopDefaultCompat(process);
49
- const chokidar__default = /*#__PURE__*/_interopDefaultCompat(chokidar);
50
- const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
51
- const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
52
- const Debug__default = /*#__PURE__*/_interopDefaultCompat(Debug);
53
- const detectIndent__default = /*#__PURE__*/_interopDefaultCompat(detectIndent);
54
- const detectNewline__default = /*#__PURE__*/_interopDefaultCompat(detectNewline);
55
- const fg__default = /*#__PURE__*/_interopDefaultCompat(fg);
56
- const lockfile__default = /*#__PURE__*/_interopDefaultCompat(lockfile);
57
- const writeFileAtomic__default = /*#__PURE__*/_interopDefaultCompat(writeFileAtomic);
58
- const vm__default = /*#__PURE__*/_interopDefaultCompat(vm);
59
- const babelGenerator__default = /*#__PURE__*/_interopDefaultCompat(babelGenerator);
60
- const groupBy__default = /*#__PURE__*/_interopDefaultCompat(groupBy);
61
- const ts__namespace = /*#__PURE__*/_interopNamespaceCompat(ts);
62
- const t__namespace = /*#__PURE__*/_interopNamespaceCompat(t);
63
- const JSON5__default = /*#__PURE__*/_interopDefaultCompat(JSON5);
64
-
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
+ key = keys[i];
15
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: ((k) => from[k]).bind(null, key),
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+ //#endregion
27
+ let node_path = require("node:path");
28
+ node_path = __toESM(node_path, 1);
29
+ let node_process = require("node:process");
30
+ node_process = __toESM(node_process, 1);
31
+ let ast_kit = require("ast-kit");
32
+ let chokidar = require("chokidar");
33
+ chokidar = __toESM(chokidar, 1);
34
+ let magic_string = require("magic-string");
35
+ magic_string = __toESM(magic_string, 1);
36
+ let vite = require("vite");
37
+ let node_fs = require("node:fs");
38
+ node_fs = __toESM(node_fs, 1);
39
+ let _uni_helper_uni_env = require("@uni-helper/uni-env");
40
+ let comment_json = require("comment-json");
41
+ let debug = require("debug");
42
+ debug = __toESM(debug, 1);
43
+ let detect_indent = require("detect-indent");
44
+ detect_indent = __toESM(detect_indent, 1);
45
+ let detect_newline = require("detect-newline");
46
+ detect_newline = __toESM(detect_newline, 1);
47
+ let unconfig = require("unconfig");
48
+ let node_fs_promises = require("node:fs/promises");
49
+ let proper_lockfile = require("proper-lockfile");
50
+ proper_lockfile = __toESM(proper_lockfile, 1);
51
+ let tinyglobby = require("tinyglobby");
52
+ let write_file_atomic = require("write-file-atomic");
53
+ write_file_atomic = __toESM(write_file_atomic, 1);
54
+ let node_module = require("node:module");
55
+ let node_vm = require("node:vm");
56
+ node_vm = __toESM(node_vm, 1);
57
+ let _babel_generator = require("@babel/generator");
58
+ _babel_generator = __toESM(_babel_generator, 1);
59
+ let lodash_groupby = require("lodash.groupby");
60
+ lodash_groupby = __toESM(lodash_groupby, 1);
61
+ let typescript = require("typescript");
62
+ typescript = __toESM(typescript, 1);
63
+ let _babel_types = require("@babel/types");
64
+ _babel_types = __toESM(_babel_types, 1);
65
+ let _vue_compiler_sfc = require("@vue/compiler-sfc");
66
+ let _uni_helper_uni_pages_types = require("@uni-helper/uni-pages-types");
67
+ //#region src/constant.ts
68
+ /** Virtual module identifier for Vite module resolution */
65
69
  const MODULE_ID_VIRTUAL = "virtual:uni-pages";
70
+ /** Resolved virtual module identifier with \0 prefix to avoid conflicts with other modules */
66
71
  const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}`;
72
+ /** Output filename, the uni-app page configuration file */
67
73
  const OUTPUT_NAME = "pages.json";
68
- const FILE_EXTENSIONS = ["vue", "nvue", "uvue"];
69
-
74
+ /** Supported page file extensions */
75
+ const FILE_EXTENSIONS = [
76
+ "vue",
77
+ "nvue",
78
+ "uvue"
79
+ ];
80
+ //#endregion
81
+ //#region ../../node_modules/.pnpm/@antfu+utils@9.3.0/node_modules/@antfu/utils/dist/index.mjs
70
82
  function slash(str) {
71
- return str.replace(/\\/g, "/");
83
+ return str.replace(/\\/g, "/");
72
84
  }
73
-
85
+ //#endregion
86
+ //#region src/declaration.ts
87
+ /**
88
+ * Generate TypeScript declaration file content
89
+ * Provide type hints for uni-app navigation APIs (navigateTo, redirectTo, switchTab, reLaunch)
90
+ * Ensure page paths get type checking at compile time
91
+ *
92
+ * @param ctx - Page context instance
93
+ * @returns Declaration file code string
94
+ */
74
95
  function getDeclaration(ctx) {
75
- const subPagesPath = ctx.subPageMetaData.map((sub) => {
76
- return sub.pages.map((v) => `"/${vite.normalizePath(path.join(sub.root, v.path))}"`);
77
- }).flat();
78
- const tabsPagesPath = ctx.pagesGlobConfig?.tabBar?.list?.map((v) => {
79
- return `"/${v.pagePath}"`;
80
- }) ?? [];
81
- const allPagesPath = [...ctx.pageMetaData.filter((page) => !tabsPagesPath.includes(page.path)).map((v) => `"/${v.path}"`), ...subPagesPath];
82
- const code = `/* eslint-disable */
96
+ const subPagesPath = ctx.subPageMetaData.map((sub) => {
97
+ return sub.pages.map((v) => `"/${(0, vite.normalizePath)((0, node_path.join)(sub.root, v.path))}"`);
98
+ }).flat();
99
+ const tabsPagesPath = ctx.pagesGlobConfig?.tabBar?.list?.map((v) => {
100
+ return `"/${v.pagePath}"`;
101
+ }) ?? [];
102
+ return `/* eslint-disable */
83
103
  /* prettier-ignore */
84
104
  // @ts-nocheck
85
105
  // Generated by vite-plugin-uni-pages
86
106
 
87
107
  type _LocationUrl =
88
- ${allPagesPath.join(" |\n ")};
108
+ ${[...ctx.pageMetaData.filter((page) => !tabsPagesPath.includes(page.path)).map((v) => `"/${v.path}"`), ...subPagesPath].join(" |\n ")};
89
109
 
90
110
  interface NavigateToOptions {
91
111
  url: _LocationUrl;
@@ -109,1111 +129,1212 @@ declare module "virtual:uni-pages" {
109
129
  export type LocationUrl = _LocationUrl;
110
130
  }
111
131
  `;
112
- return code;
113
132
  }
133
+ /**
134
+ * Write file, automatically create directories
135
+ * @param filePath - File path
136
+ * @param content - File content
137
+ */
114
138
  async function writeFile(filePath, content) {
115
- await promises.mkdir(path.dirname(filePath), { recursive: true });
116
- return await promises.writeFile(filePath, content, "utf-8");
139
+ await (0, node_fs_promises.mkdir)((0, node_path.dirname)(filePath), { recursive: true });
140
+ return await (0, node_fs_promises.writeFile)(filePath, content, "utf-8");
117
141
  }
142
+ /**
143
+ * Write declaration file to disk
144
+ * Only writes when content changes to avoid unnecessary file operations
145
+ *
146
+ * @param ctx - Page context instance
147
+ * @param filepath - Declaration file output path
148
+ */
118
149
  async function writeDeclaration(ctx, filepath) {
119
- const originalContent = fs.existsSync(filepath) ? await promises.readFile(filepath, "utf-8") : "";
120
- const code = getDeclaration(ctx);
121
- if (!code)
122
- return;
123
- if (code !== originalContent)
124
- await writeFile(filepath, code);
150
+ const originalContent = (0, node_fs.existsSync)(filepath) ? await (0, node_fs_promises.readFile)(filepath, "utf-8") : "";
151
+ const code = getDeclaration(ctx);
152
+ if (!code) return;
153
+ if (code !== originalContent) await writeFile(filepath, code);
125
154
  }
126
-
155
+ //#endregion
156
+ //#region src/utils.ts
157
+ /**
158
+ * Invalidate virtual module to trigger HMR update
159
+ * When page configuration changes, the virtual module needs to be invalidated to regenerate content
160
+ *
161
+ * @param server - Vite dev server instance
162
+ */
127
163
  function invalidatePagesModule(server) {
128
- const { moduleGraph } = server;
129
- const mods = moduleGraph.getModulesByFile(RESOLVED_MODULE_ID_VIRTUAL);
130
- if (mods) {
131
- const seen = /* @__PURE__ */ new Set();
132
- mods.forEach((mod) => {
133
- moduleGraph.invalidateModule(mod, seen);
134
- });
135
- }
164
+ const { moduleGraph } = server;
165
+ const mods = moduleGraph.getModulesByFile(RESOLVED_MODULE_ID_VIRTUAL);
166
+ if (mods) {
167
+ const seen = /* @__PURE__ */ new Set();
168
+ mods.forEach((mod) => {
169
+ moduleGraph.invalidateModule(mod, seen);
170
+ });
171
+ }
136
172
  }
137
- const debug = {
138
- hmr: Debug__default("vite-plugin-uni-pages:hmr"),
139
- routeBlock: Debug__default("vite-plugin-uni-pages:routeBlock"),
140
- options: Debug__default("vite-plugin-uni-pages:options"),
141
- pages: Debug__default("vite-plugin-uni-pages:pages"),
142
- subPages: Debug__default("vite-plugin-uni-pages:subPages"),
143
- error: Debug__default("vite-plugin-uni-pages:error"),
144
- cache: Debug__default("vite-plugin-uni-pages:cache"),
145
- declaration: Debug__default("vite-plugin-uni-pages:declaration"),
146
- definePage: Debug__default("vite-plugin-uni-pages:definePage")
173
+ /**
174
+ * Debug logging utility
175
+ * Uses debug package for leveled log output
176
+ * Enable via environment variable DEBUG=vite-plugin-uni-pages:*
177
+ */
178
+ const debug$1 = {
179
+ /** HMR related logs */
180
+ hmr: (0, debug.default)("vite-plugin-uni-pages:hmr"),
181
+ /** Configuration options related logs */
182
+ options: (0, debug.default)("vite-plugin-uni-pages:options"),
183
+ /** Main package page scanning logs */
184
+ pages: (0, debug.default)("vite-plugin-uni-pages:pages"),
185
+ /** Sub-package page scanning logs */
186
+ subPages: (0, debug.default)("vite-plugin-uni-pages:subPages"),
187
+ /** Error logs */
188
+ error: (0, debug.default)("vite-plugin-uni-pages:error"),
189
+ /** Cache related logs */
190
+ cache: (0, debug.default)("vite-plugin-uni-pages:cache"),
191
+ /** Declaration file generation logs */
192
+ declaration: (0, debug.default)("vite-plugin-uni-pages:declaration"),
193
+ /** definePage macro parsing logs */
194
+ definePage: (0, debug.default)("vite-plugin-uni-pages:definePage")
147
195
  };
196
+ /**
197
+ * Convert file extensions array to glob pattern
198
+ * @param extensions - File extensions array
199
+ * @returns Glob pattern string
200
+ */
148
201
  function extsToGlob(extensions) {
149
- return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
202
+ return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
150
203
  }
151
- function isTargetFile(path2) {
152
- const ext = path2.split(".").pop();
153
- return FILE_EXTENSIONS.includes(ext);
204
+ /**
205
+ * Check if file is a target page file
206
+ * Determine if the file extension is in the supported page file types list
207
+ *
208
+ * @param path - File path
209
+ * @returns Whether it's a target file
210
+ */
211
+ function isTargetFile(path) {
212
+ const ext = path.split(".").pop();
213
+ return FILE_EXTENSIONS.includes(ext);
154
214
  }
215
+ /**
216
+ * merge page meta data array by path and assign style
217
+ * @param pageMetaData page meta data array
218
+ * TODO: support merge middleware
219
+ */
155
220
  function mergePageMetaDataArray(pageMetaData) {
156
- const pageMetaDataObj = groupBy__default(pageMetaData, "path");
157
- const result = [];
158
- for (const path2 in pageMetaDataObj) {
159
- const _pageMetaData = pageMetaDataObj[path2];
160
- const options = _pageMetaData[0];
161
- for (const page of _pageMetaData) {
162
- options.style = Object.assign(options.style ?? {}, page.style ?? {});
163
- Object.assign(options, page);
164
- }
165
- result.push(options);
166
- }
167
- return result;
221
+ const pageMetaDataObj = (0, lodash_groupby.default)(pageMetaData, "path");
222
+ const result = [];
223
+ for (const path in pageMetaDataObj) {
224
+ const _pageMetaData = pageMetaDataObj[path];
225
+ const options = _pageMetaData[0];
226
+ for (const page of _pageMetaData) {
227
+ options.style = Object.assign(options.style ?? {}, page.style ?? {});
228
+ Object.assign(options, page);
229
+ }
230
+ result.push(options);
231
+ }
232
+ return result;
168
233
  }
234
+ /**
235
+ * Convert TypeScript / JavaScript script code to object/function
236
+ *
237
+ * @param options - Configuration required for script execution
238
+ * @param options.imports - List of module import statements to include
239
+ * @param options.code - TypeScript code content to execute
240
+ * @param options.filename - Script filename for error location and context
241
+ * @returns Script execution result, if export is a function then execute and return its return value
242
+ */
169
243
  async function parseCode(options) {
170
- const { imports = [], code, filename } = options;
171
- let jsCode = "";
172
- try {
173
- const tmpCode = `${imports.join("\n")}
174
- export default ${code}`;
175
- jsCode = ts__namespace.transpileModule(tmpCode, {
176
- compilerOptions: {
177
- module: ts__namespace.ModuleKind.CommonJS,
178
- // 生成的模块格式为 CommonJS(Node.js 默认格式)
179
- target: ts__namespace.ScriptTarget.ES2022,
180
- // 编译后的 JavaScript 目标版本
181
- noEmit: true,
182
- // 不生成输出文件
183
- strict: false,
184
- // 关闭所有严格类型检查选项
185
- noImplicitAny: false,
186
- // 允许表达式和 any 类型
187
- strictNullChecks: false,
188
- // 关闭严格的 null 和 undefined 检查
189
- strictFunctionTypes: false,
190
- // 关闭函数参数的严格逆变比较
191
- strictBindCallApply: false,
192
- // 关闭对 bind、call 和 apply 方法的严格类型检查
193
- strictPropertyInitialization: false,
194
- // 关闭类属性初始化的严格检查
195
- noImplicitThis: false,
196
- // 允许 this 表达式具有隐式的 any 类型
197
- alwaysStrict: false,
198
- // 不以严格模式解析并为每个源文件生成 "use strict" 指令
199
- allowJs: true,
200
- // 允许编译 JavaScript 文件
201
- checkJs: false,
202
- // 不检查 JavaScript 文件中的类型
203
- skipLibCheck: true,
204
- // 跳过对 TypeScript 声明文件 (*.d.ts) 的类型检查
205
- esModuleInterop: true,
206
- // 启用 ES 模块互操作性,允许使用 import 导入 CommonJS 模块
207
- removeComments: true
208
- // 删除注释
209
- },
210
- jsDocParsingMode: ts__namespace.JSDocParsingMode.ParseNone
211
- // 不解析 JSDoc
212
- }).outputText;
213
- const dir = path__default.dirname(filename);
214
- const vmContext = {
215
- module: {},
216
- exports: {},
217
- __filename: filename,
218
- __dirname: dir,
219
- require: node_module.createRequire(dir),
220
- import: (id) => import(id),
221
- // 定时器相关
222
- setTimeout,
223
- clearTimeout,
224
- setInterval,
225
- clearInterval,
226
- setImmediate,
227
- clearImmediate,
228
- // 控制台相关
229
- console,
230
- // URL 处理
231
- URL,
232
- URLSearchParams,
233
- // 进程和性能相关
234
- performance,
235
- // 全局对象引用
236
- global: globalThis,
237
- globalThis
238
- };
239
- const script = new vm__default.Script(jsCode, { filename });
240
- await script.runInNewContext(vmContext, {
241
- timeout: 1e3
242
- // 设置超时避免长时间运行
243
- });
244
- const result = vmContext.exports.default || vmContext.exports;
245
- return result;
246
- } catch (error) {
247
- throw new Error(`EXEC SCRIPT FAIL IN ${filename}: ${error.message}
248
-
249
- ${jsCode}
250
-
251
- `);
252
- }
244
+ const { imports = [], code, filename } = options;
245
+ let jsCode = "";
246
+ try {
247
+ const tmpCode = `${imports.join("\n")}\n export default ${code}`;
248
+ jsCode = typescript.transpileModule(tmpCode, {
249
+ compilerOptions: {
250
+ module: typescript.ModuleKind.CommonJS,
251
+ target: typescript.ScriptTarget.ES2022,
252
+ noEmit: true,
253
+ strict: false,
254
+ noImplicitAny: false,
255
+ strictNullChecks: false,
256
+ strictFunctionTypes: false,
257
+ strictBindCallApply: false,
258
+ strictPropertyInitialization: false,
259
+ noImplicitThis: false,
260
+ alwaysStrict: false,
261
+ allowJs: true,
262
+ checkJs: false,
263
+ skipLibCheck: true,
264
+ esModuleInterop: true,
265
+ removeComments: true
266
+ },
267
+ jsDocParsingMode: typescript.JSDocParsingMode.ParseNone
268
+ }).outputText;
269
+ const dir = node_path.default.dirname(filename);
270
+ const vmContext = {
271
+ module: {},
272
+ exports: {},
273
+ __filename: filename,
274
+ __dirname: dir,
275
+ require: (0, node_module.createRequire)(dir),
276
+ import: (id) => import(id),
277
+ setTimeout,
278
+ clearTimeout,
279
+ setInterval,
280
+ clearInterval,
281
+ setImmediate,
282
+ clearImmediate,
283
+ console,
284
+ URL,
285
+ URLSearchParams,
286
+ performance,
287
+ global: globalThis,
288
+ globalThis
289
+ };
290
+ await new node_vm.default.Script(jsCode, { filename }).runInNewContext(vmContext, { timeout: 1e3 });
291
+ return vmContext.exports.default || vmContext.exports;
292
+ } catch (error) {
293
+ throw new Error(`EXEC SCRIPT FAIL IN ${filename}: ${error.message} \n\n${jsCode}\n\n`);
294
+ }
253
295
  }
296
+ /**
297
+ * Async sleep function
298
+ * @param ms - Sleep duration in milliseconds
299
+ * @returns Promise object
300
+ */
254
301
  function sleep(ms) {
255
- return new Promise((resolve) => setTimeout(resolve, ms));
302
+ return new Promise((resolve) => setTimeout(resolve, ms));
256
303
  }
304
+ /**
305
+ * Get default export of a module
306
+ * Compatible with CommonJS and ES Module export styles
307
+ *
308
+ * @param expr - Module object
309
+ * @returns Default export value
310
+ */
257
311
  function getDefaultExport(expr) {
258
- return expr.default === void 0 ? expr : expr.default;
312
+ return expr.default === void 0 ? expr : expr.default;
259
313
  }
260
- const babelGenerate = getDefaultExport(babelGenerator__default);
261
-
314
+ /** Babel code generator for converting AST back to code */
315
+ const babelGenerate = getDefaultExport(_babel_generator.default);
316
+ function stripType(item) {
317
+ const { type, ...rest } = item;
318
+ return rest;
319
+ }
320
+ //#endregion
321
+ //#region src/files.ts
322
+ /**
323
+ * Resolves the files that are valid pages for the given context.
324
+ */
262
325
  function getPageFiles(path, options) {
263
- const { exclude } = options;
264
- const ext = extsToGlob(FILE_EXTENSIONS);
265
- const files = fg__default.sync(`**/*.${ext}`, {
266
- ignore: exclude,
267
- onlyFiles: true,
268
- cwd: path
269
- });
270
- return files;
326
+ const { exclude } = options;
327
+ return (0, tinyglobby.globSync)(`**/*.${extsToGlob(FILE_EXTENSIONS)}`, {
328
+ ignore: exclude,
329
+ onlyFiles: true,
330
+ cwd: path
331
+ });
271
332
  }
333
+ /**
334
+ * Check the pages.json file at the specified path, create an empty pages.json file if it doesn't exist or is not a valid file
335
+ * @param path - File path to check
336
+ * @returns boolean - Whether the operation was successful
337
+ */
272
338
  function checkPagesJsonFileSync(path) {
273
- const createEmptyFile = (path2) => {
274
- try {
275
- fs__default.writeFileSync(
276
- path2,
277
- JSON.stringify({ pages: [{ path: "" }] }, null, 2),
278
- { encoding: "utf-8" }
279
- );
280
- return true;
281
- } catch {
282
- return false;
283
- }
284
- };
285
- const unlinkFile = (path2) => {
286
- try {
287
- fs__default.unlinkSync(path2);
288
- return true;
289
- } catch {
290
- return false;
291
- }
292
- };
293
- try {
294
- try {
295
- fs__default.accessSync(path, fs__default.constants.F_OK);
296
- } catch {
297
- return createEmptyFile(path);
298
- }
299
- const stat = fs__default.statSync(path);
300
- if (!stat.isFile()) {
301
- if (!unlinkFile(path)) {
302
- return false;
303
- }
304
- return createEmptyFile(path);
305
- }
306
- try {
307
- fs__default.accessSync(path, fs__default.constants.R_OK | fs__default.constants.W_OK);
308
- return true;
309
- } catch {
310
- if (!unlinkFile(path)) {
311
- return false;
312
- }
313
- return createEmptyFile(path);
314
- }
315
- } catch {
316
- return createEmptyFile(path);
317
- }
339
+ /**
340
+ * Create an empty pages.json file
341
+ * @param path - File path
342
+ * @returns boolean - Whether the creation was successful
343
+ */
344
+ const createEmptyFile = (path) => {
345
+ try {
346
+ node_fs.default.writeFileSync(path, JSON.stringify({ pages: [{ path: "" }] }, null, 2), { encoding: "utf-8" });
347
+ return true;
348
+ } catch {
349
+ return false;
350
+ }
351
+ };
352
+ /**
353
+ * Delete the file at the specified path
354
+ * @param path - File path
355
+ * @returns boolean - Whether the deletion was successful
356
+ */
357
+ const unlinkFile = (path) => {
358
+ try {
359
+ node_fs.default.unlinkSync(path);
360
+ return true;
361
+ } catch {
362
+ return false;
363
+ }
364
+ };
365
+ try {
366
+ try {
367
+ node_fs.default.accessSync(path, node_fs.default.constants.F_OK);
368
+ } catch {
369
+ return createEmptyFile(path);
370
+ }
371
+ if (!node_fs.default.statSync(path).isFile()) {
372
+ if (!unlinkFile(path)) return false;
373
+ return createEmptyFile(path);
374
+ }
375
+ try {
376
+ node_fs.default.accessSync(path, node_fs.default.constants.R_OK | node_fs.default.constants.W_OK);
377
+ return true;
378
+ } catch {
379
+ if (!unlinkFile(path)) return false;
380
+ return createEmptyFile(path);
381
+ }
382
+ } catch {
383
+ return createEmptyFile(path);
384
+ }
318
385
  }
386
+ /**
387
+ * Safely write file using file lock
388
+ * Avoid data corruption caused by concurrent writes through file lock
389
+ * Use atomic write to ensure file write integrity
390
+ *
391
+ * @param path - File path
392
+ * @param content - File content
393
+ * @param retry - Number of retries when lock acquisition fails, defaults to 3
394
+ */
319
395
  async function writeFileWithLock(path, content, retry = 3) {
320
- if (retry <= 0) {
321
- debug.error(`${path} \u83B7\u53D6\u6587\u4EF6\u9501\u5931\u8D25\uFF0C\u5199\u5165\u5931\u8D25`);
322
- return;
323
- }
324
- let release;
325
- try {
326
- try {
327
- release = await lockfile__default.lock(path, { realpath: false });
328
- } catch {
329
- await sleep(500);
330
- return writeFileWithLock(path, content, retry - 1);
331
- }
332
- await writeFileAtomic__default(path, content);
333
- } finally {
334
- if (release) {
335
- await release();
336
- }
337
- }
396
+ if (retry <= 0) {
397
+ debug$1.error(`${path} Failed to acquire file lock, write failed`);
398
+ return;
399
+ }
400
+ let release;
401
+ try {
402
+ try {
403
+ release = await proper_lockfile.default.lock(path, { realpath: false });
404
+ } catch {
405
+ await sleep(500);
406
+ return writeFileWithLock(path, content, retry - 1);
407
+ }
408
+ await (0, write_file_atomic.default)(path, content);
409
+ } finally {
410
+ if (release) await release();
411
+ }
338
412
  }
339
-
340
- function resolveOptions(userOptions, viteRoot = process__default.cwd()) {
341
- const {
342
- dts = true,
343
- configSource = "pages.config",
344
- homePage = ["pages/index", "pages/index/index"],
345
- mergePages = true,
346
- dir = "src/pages",
347
- subPackages = [],
348
- outDir = "src",
349
- exclude = ["node_modules", ".git", "**/__*__/**"],
350
- routeBlockLang = "json5",
351
- minify = false,
352
- debug = false,
353
- onBeforeLoadUserConfig = () => {
354
- },
355
- onAfterLoadUserConfig = () => {
356
- },
357
- onBeforeScanPages = () => {
358
- },
359
- onAfterScanPages = () => {
360
- },
361
- onBeforeMergePageMetaData = () => {
362
- },
363
- onAfterMergePageMetaData = () => {
364
- },
365
- onBeforeWriteFile = () => {
366
- },
367
- onAfterWriteFile = () => {
368
- }
369
- } = userOptions;
370
- const root = viteRoot || slash(process__default.env.VITE_ROOT_DIR || process__default.cwd());
371
- const resolvedDirs = resolvePageDirs(dir, root, exclude);
372
- const resolvedSubDirs = subPackages.map((dir2) => slash(dir2));
373
- const resolvedHomePage = typeof homePage === "string" ? [homePage] : homePage;
374
- const resolvedConfigSource = typeof configSource === "string" ? [{ files: configSource }] : configSource;
375
- const resolvedDts = !dts ? false : typeof dts === "string" ? dts : path.resolve(viteRoot, "uni-pages.d.ts");
376
- const resolvedOptions = {
377
- dts: resolvedDts,
378
- configSource: Array.isArray(resolvedConfigSource) ? resolvedConfigSource : [resolvedConfigSource],
379
- homePage: resolvedHomePage,
380
- mergePages,
381
- dirs: resolvedDirs,
382
- subPackages: resolvedSubDirs,
383
- outDir,
384
- exclude,
385
- routeBlockLang,
386
- root,
387
- minify,
388
- debug,
389
- onBeforeLoadUserConfig,
390
- onAfterLoadUserConfig,
391
- onBeforeScanPages,
392
- onAfterScanPages,
393
- onBeforeMergePageMetaData,
394
- onAfterMergePageMetaData,
395
- onBeforeWriteFile,
396
- onAfterWriteFile
397
- };
398
- return resolvedOptions;
413
+ //#endregion
414
+ //#region src/options.ts
415
+ /**
416
+ * Resolve user configuration options
417
+ * Merge user-provided configuration with default values and handle path resolution
418
+ *
419
+ * @param userOptions - User configuration options
420
+ * @param viteRoot - Vite project root directory
421
+ * @returns Resolved configuration options
422
+ */
423
+ function resolveOptions(userOptions, viteRoot = node_process.default.cwd()) {
424
+ const { dts = true, configSource = "pages.config", homePage = ["pages/index", "pages/index/index"], mergePages = true, dir = "src/pages", subPackages = [], outDir = "src", exclude = [
425
+ "node_modules",
426
+ ".git",
427
+ "**/__*__/**"
428
+ ], minify = false, debug = false, onBeforeLoadUserConfig = () => {}, onAfterLoadUserConfig = () => {}, onBeforeScanPages = () => {}, onAfterScanPages = () => {}, onBeforeMergePageMetaData = () => {}, onAfterMergePageMetaData = () => {}, onBeforeWriteFile = () => {}, onAfterWriteFile = () => {} } = userOptions;
429
+ const root = viteRoot || slash(node_process.default.env.VITE_ROOT_DIR || node_process.default.cwd());
430
+ const resolvedDirs = resolvePageDirs(dir, root, exclude);
431
+ const resolvedSubDirs = subPackages.map((dir) => slash(dir));
432
+ const resolvedHomePage = typeof homePage === "string" ? [homePage] : homePage;
433
+ const resolvedConfigSource = typeof configSource === "string" ? [{ files: configSource }] : configSource;
434
+ return {
435
+ dts: !dts ? false : typeof dts === "string" ? dts : (0, node_path.resolve)(viteRoot, "uni-pages.d.ts"),
436
+ configSource: Array.isArray(resolvedConfigSource) ? resolvedConfigSource : [resolvedConfigSource],
437
+ homePage: resolvedHomePage,
438
+ mergePages,
439
+ dirs: resolvedDirs,
440
+ subPackages: resolvedSubDirs,
441
+ outDir,
442
+ exclude,
443
+ root,
444
+ minify,
445
+ debug,
446
+ onBeforeLoadUserConfig,
447
+ onAfterLoadUserConfig,
448
+ onBeforeScanPages,
449
+ onAfterScanPages,
450
+ onBeforeMergePageMetaData,
451
+ onAfterMergePageMetaData,
452
+ onBeforeWriteFile,
453
+ onAfterWriteFile
454
+ };
399
455
  }
456
+ /**
457
+ * Resolves the page dirs for its for its given globs
458
+ */
400
459
  function resolvePageDirs(dir, root, exclude) {
401
- const dirs = fg__default.sync(slash(dir), {
402
- ignore: exclude,
403
- onlyDirectories: true,
404
- dot: true,
405
- unique: true,
406
- cwd: root
407
- });
408
- return dirs;
409
- }
410
-
411
- function parseCustomBlock(block, filePath, routeBlockLang) {
412
- const lang = block.lang ?? routeBlockLang;
413
- const attr = {
414
- type: "page",
415
- ...block.attrs
416
- };
417
- let content;
418
- debug.routeBlock(`use ${lang} parser`);
419
- if (lang === "json5") {
420
- try {
421
- content = JSON5__default.parse(block.content);
422
- } catch (err) {
423
- throw new Error(
424
- `Invalid JSON5 format of <${block.type}> content in ${filePath}
425
- ${err.message}`
426
- );
427
- }
428
- } else if (lang === "jsonc") {
429
- try {
430
- content = commentJson.parse(block.content);
431
- } catch (err) {
432
- throw new Error(
433
- `Invalid JSONC format of <${block.type}> content in ${filePath}
434
- ${err.message}`
435
- );
436
- }
437
- } else if (lang === "json") {
438
- try {
439
- content = JSON.parse(block.content);
440
- } catch (err) {
441
- throw new Error(
442
- `Invalid JSON format of <${block.type}> content in ${filePath}
443
- ${err.message}`
444
- );
445
- }
446
- } else if (lang === "yaml" || lang === "yml") {
447
- try {
448
- content = yaml.parse(block.content);
449
- } catch (err) {
450
- throw new Error(
451
- `Invalid YAML format of <${block.type}> content in ${filePath}
452
- ${err.message}`
453
- );
454
- }
455
- }
456
- return {
457
- attr,
458
- content: content ?? {}
459
- };
460
- }
461
- function getRouteSfcBlock(sfc) {
462
- return sfc?.customBlocks.find((b) => b.type === "route");
460
+ return (0, tinyglobby.globSync)(slash(dir), {
461
+ ignore: exclude,
462
+ onlyDirectories: true,
463
+ expandDirectories: false,
464
+ dot: true,
465
+ cwd: root
466
+ });
463
467
  }
464
- function getRouteBlock(path, blockStr, routeBlockLang) {
465
- if (!blockStr)
466
- return;
467
- return parseCustomBlock(blockStr, path, routeBlockLang);
468
- }
469
-
470
- var __defProp$1 = Object.defineProperty;
471
- var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
472
- var __publicField$1 = (obj, key, value) => {
473
- __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
474
- return value;
468
+ //#endregion
469
+ //#region src/page.ts
470
+ /**
471
+ * Page class representing a Vue page file
472
+ *
473
+ * Responsibilities:
474
+ * 1. Read page file content
475
+ * 2. Parse page metadata defined by definePage macro
476
+ * 3. Provide tabBar configuration information
477
+ * 4. Track page file change status
478
+ */
479
+ var Page = class {
480
+ /** Page context instance */
481
+ ctx;
482
+ /** Page path information containing relative and absolute paths */
483
+ path;
484
+ /** Page URI used for pages.json path field */
485
+ uri;
486
+ /** Whether the page has changed, used for incremental update judgment */
487
+ changed = true;
488
+ /** Raw JSON string of page metadata for change detection */
489
+ raw = "";
490
+ /** Parsed page metadata */
491
+ meta;
492
+ /**
493
+ * Create a page instance
494
+ * @param ctx - Page context instance
495
+ * @param path - Page path information
496
+ */
497
+ constructor(ctx, path) {
498
+ this.ctx = ctx;
499
+ this.path = path;
500
+ this.uri = (0, vite.normalizePath)(path.relativePath.replace((0, node_path.extname)(path.relativePath), ""));
501
+ }
502
+ /**
503
+ * Get page metadata
504
+ * Parse configuration defined by definePage macro and return metadata for pages.json
505
+ *
506
+ * @param forceUpdate - Whether to force update, ignoring cache
507
+ * @returns Page metadata object
508
+ */
509
+ async getPageMeta(forceUpdate = false) {
510
+ if (forceUpdate || !this.meta) await this.read();
511
+ const { path, tabBar: _, ...others } = this.meta || {};
512
+ return {
513
+ path: path ?? this.uri,
514
+ ...others
515
+ };
516
+ }
517
+ /**
518
+ * Get page tabBar configuration
519
+ * Extract tabBar related configuration from definePage macro
520
+ *
521
+ * @param forceUpdate - Whether to force update, ignoring cache
522
+ * @returns tabBar configuration object, or undefined if page doesn't define tabBar
523
+ */
524
+ async getTabBar(forceUpdate = false) {
525
+ if (forceUpdate || !this.meta) await this.read();
526
+ const { tabBar } = this.meta || {};
527
+ if (tabBar === void 0) return;
528
+ return {
529
+ ...tabBar,
530
+ pagePath: tabBar.pagePath || this.uri,
531
+ index: tabBar.index ?? 0
532
+ };
533
+ }
534
+ /**
535
+ * Check if the page has changed
536
+ * @returns Whether the page has changed
537
+ */
538
+ hasChanged() {
539
+ return this.changed;
540
+ }
541
+ /**
542
+ * Read page file and parse metadata
543
+ * Extract configuration defined by definePage macro from Vue SFC
544
+ */
545
+ async read() {
546
+ let meta;
547
+ try {
548
+ meta = await this.readPageMetaFromFile();
549
+ } catch (err) {
550
+ debug$1.error(err);
551
+ return;
552
+ }
553
+ let raw = "";
554
+ try {
555
+ raw = JSON.stringify(meta);
556
+ } catch {}
557
+ this.changed = this.raw !== raw;
558
+ this.meta = meta;
559
+ this.raw = raw;
560
+ }
561
+ async readPageMetaFromFile() {
562
+ try {
563
+ const meta = await tryPageMetaFromMacro(parseSFC(await node_fs.default.promises.readFile(this.path.absolutePath, { encoding: "utf-8" }), { filename: this.path.absolutePath }));
564
+ if (meta) return meta;
565
+ return { type: "page" };
566
+ } catch (err) {
567
+ throw new Error(`Read page meta fail in ${this.path.relativePath}\n${err.message}`);
568
+ }
569
+ }
475
570
  };
476
- class Page {
477
- constructor(ctx, path$1) {
478
- __publicField$1(this, "ctx");
479
- __publicField$1(this, "path");
480
- __publicField$1(this, "uri");
481
- __publicField$1(this, "changed", true);
482
- __publicField$1(this, "raw", "");
483
- __publicField$1(this, "meta");
484
- this.ctx = ctx;
485
- this.path = path$1;
486
- this.uri = vite.normalizePath(path$1.relativePath.replace(path.extname(path$1.relativePath), ""));
487
- }
488
- async getPageMeta(forceUpdate = false) {
489
- if (forceUpdate || !this.meta) {
490
- await this.read();
491
- }
492
- const { path, tabBar: _, ...others } = this.meta || {};
493
- return {
494
- path: path ?? this.uri,
495
- ...others
496
- };
497
- }
498
- async getTabBar(forceUpdate = false) {
499
- if (forceUpdate || !this.meta) {
500
- await this.read();
501
- }
502
- const { tabBar } = this.meta;
503
- if (tabBar === void 0) {
504
- return void 0;
505
- }
506
- return {
507
- ...tabBar,
508
- pagePath: tabBar.pagePath || this.uri,
509
- index: tabBar.index || 0
510
- };
511
- }
512
- hasChanged() {
513
- return this.changed;
514
- }
515
- async read() {
516
- let meta;
517
- try {
518
- meta = await this.readPageMetaFromFile();
519
- } catch (err) {
520
- debug.error(err);
521
- return;
522
- }
523
- let raw = "";
524
- try {
525
- raw = JSON.stringify(meta);
526
- } catch {
527
- }
528
- this.changed = this.raw !== raw;
529
- this.meta = meta;
530
- this.raw = raw;
531
- }
532
- async readPageMetaFromFile() {
533
- try {
534
- const content = await fs__default.promises.readFile(this.path.absolutePath, { encoding: "utf-8" });
535
- const sfc = parseSFC(content, { filename: this.path.absolutePath });
536
- const meta = await tryPageMetaFromMacro(sfc);
537
- if (meta) {
538
- return meta;
539
- }
540
- return tryPageMetaFromCustomBlock(sfc, this.ctx.options.routeBlockLang);
541
- } catch (err) {
542
- throw new Error(`Read page meta fail in ${this.path.relativePath}
543
- ${err.message}`);
544
- }
545
- }
546
- }
571
+ /**
572
+ * Parse Vue Single File Component (SFC)
573
+ * Compatible with different versions of @vue/compiler-sfc
574
+ *
575
+ * @param code - Vue SFC source code
576
+ * @param options - Parse options
577
+ * @returns SFC descriptor object
578
+ */
547
579
  function parseSFC(code, options) {
548
- return compilerSfc.parse(code, {
549
- pad: "space",
550
- ...options
551
- }).descriptor || compilerSfc.parse({
552
- source: code,
553
- ...options
554
- });
580
+ return (0, _vue_compiler_sfc.parse)(code, {
581
+ pad: "space",
582
+ ...options
583
+ }).descriptor || (0, _vue_compiler_sfc.parse)({
584
+ source: code,
585
+ ...options
586
+ });
555
587
  }
588
+ /**
589
+ * Try to extract page metadata defined by definePage macro from SFC
590
+ * Support using definePage in script setup or regular script
591
+ *
592
+ * @param sfc - Vue SFC descriptor
593
+ * @returns Page metadata object, or undefined if definePage is not found
594
+ */
556
595
  async function tryPageMetaFromMacro(sfc) {
557
- const sfcScript = sfc.scriptSetup || sfc.script;
558
- if (!sfcScript) {
559
- return void 0;
560
- }
561
- const ast = astKit.babelParse(sfcScript.content, sfcScript.lang || "js", {
562
- plugins: [["importAttributes", { deprecatedAssertSyntax: true }]]
563
- });
564
- const macro = findMacro(ast.body, sfc.filename);
565
- if (macro) {
566
- const imports = findImports(ast.body).filter((imp) => !!imp.specifiers.length).map((imp) => babelGenerate(imp).code);
567
- const [macroOption] = macro.arguments;
568
- const code = babelGenerate(macroOption).code;
569
- const parsed = await parseCode({
570
- imports,
571
- code,
572
- filename: sfc.filename
573
- });
574
- const res = typeof parsed === "function" ? await Promise.resolve(parsed()) : await Promise.resolve(parsed);
575
- return {
576
- type: "page",
577
- ...res
578
- };
579
- }
580
- return void 0;
581
- }
582
- async function tryPageMetaFromCustomBlock(sfc, routeBlockLang) {
583
- const block = getRouteSfcBlock(sfc);
584
- const routeBlock = getRouteBlock(sfc.filename, block, routeBlockLang);
585
- const pageMeta = {
586
- type: routeBlock?.attr.type ?? "page"
587
- };
588
- if (routeBlock) {
589
- try {
590
- commentJson.assign(pageMeta, routeBlock.content);
591
- } catch {
592
- }
593
- }
594
- return pageMeta;
596
+ const sfcScript = sfc.scriptSetup || sfc.script;
597
+ if (!sfcScript) return;
598
+ const ast = (0, ast_kit.babelParse)(sfcScript.content, sfcScript.lang || "js", { plugins: [["importAttributes", { deprecatedAssertSyntax: true }]] });
599
+ const macro = findMacro(ast.body, sfc.filename);
600
+ if (macro) {
601
+ const imports = findImports(ast.body).filter((imp) => !!imp.specifiers.length).map((imp) => babelGenerate(imp).code);
602
+ const [macroOption] = macro.arguments;
603
+ const code = babelGenerate(macroOption).code;
604
+ const parsed = await parseCode({
605
+ imports,
606
+ code,
607
+ filename: sfc.filename
608
+ });
609
+ return {
610
+ type: "page",
611
+ ...typeof parsed === "function" ? await Promise.resolve(parsed()) : await Promise.resolve(parsed)
612
+ };
613
+ }
595
614
  }
615
+ /**
616
+ * Find definePage macro call in AST
617
+ * Support function expressions, arrow functions and object expressions as arguments
618
+ *
619
+ * @param stmts - AST statement array
620
+ * @param filename - Filename for error reporting
621
+ * @returns definePage call expression, or undefined if not found
622
+ */
596
623
  function findMacro(stmts, filename) {
597
- let macro;
598
- for (const stmt of stmts) {
599
- let node = stmt;
600
- if (stmt.type === "ExpressionStatement")
601
- node = stmt.expression;
602
- if (astKit.isCallOf(node, "definePage")) {
603
- macro = node;
604
- break;
605
- }
606
- }
607
- if (!macro)
608
- return;
609
- const [opt] = macro.arguments;
610
- if (opt && !t__namespace.isFunctionExpression(opt) && !t__namespace.isArrowFunctionExpression(opt) && !t__namespace.isObjectExpression(opt)) {
611
- debug.definePage(`definePage() \u53C2\u6570\u4EC5\u652F\u6301\u51FD\u6570\u6216\u5BF9\u8C61\uFF1A${filename}`);
612
- return;
613
- }
614
- return macro;
624
+ let macro;
625
+ for (const stmt of stmts) {
626
+ let node = stmt;
627
+ if (stmt.type === "ExpressionStatement") node = stmt.expression;
628
+ if ((0, ast_kit.isCallOf)(node, "definePage")) {
629
+ macro = node;
630
+ break;
631
+ }
632
+ }
633
+ if (!macro) return;
634
+ const [opt] = macro.arguments;
635
+ if (opt && !_babel_types.isFunctionExpression(opt) && !_babel_types.isArrowFunctionExpression(opt) && !_babel_types.isObjectExpression(opt)) {
636
+ debug$1.definePage(`definePage() 参数仅支持函数或对象:${filename}`);
637
+ return;
638
+ }
639
+ return macro;
615
640
  }
641
+ /**
642
+ * Extract all import declarations from AST
643
+ * Used to provide necessary imports when executing definePage arguments
644
+ *
645
+ * @param stmts - AST statement array
646
+ * @returns Import declaration array
647
+ */
616
648
  function findImports(stmts) {
617
- const imports = [];
618
- for (const stmt of stmts) {
619
- if (t__namespace.isImportDeclaration(stmt)) {
620
- imports.push(stmt);
621
- }
622
- }
623
- return imports;
649
+ const imports = [];
650
+ for (const stmt of stmts) if (_babel_types.isImportDeclaration(stmt)) imports.push(stmt);
651
+ return imports;
624
652
  }
625
-
626
- var __defProp = Object.defineProperty;
627
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
628
- var __publicField = (obj, key, value) => {
629
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
630
- return value;
653
+ //#endregion
654
+ //#region src/context.ts
655
+ /**
656
+ * Page context class responsible for page scanning, config loading, page metadata merging and pages.json generation
657
+ *
658
+ * Core responsibilities:
659
+ * 1. Scan page directories and collect page files
660
+ * 2. Load user configuration files (pages.config.ts, etc.)
661
+ * 3. Parse page metadata (definePage macro)
662
+ * 4. Merge page configurations and generate pages.json
663
+ * 5. Provide virtual module and HMR support
664
+ */
665
+ var PageContext = class {
666
+ _server;
667
+ /** Parsed configuration object from user config file (pages.config.ts) */
668
+ pagesGlobConfig;
669
+ /** Source path list of user configuration files */
670
+ pagesConfigSourcePaths = [];
671
+ /** Main package page map, key is the absolute path of the page file */
672
+ pages = /* @__PURE__ */ new Map();
673
+ /** Sub-package page map, key is the sub-package root directory, value is the page map under that sub-package */
674
+ subPages = /* @__PURE__ */ new Map();
675
+ /** Main package page metadata array for generating pages.json pages field */
676
+ pageMetaData = [];
677
+ /** Sub-package page metadata array for generating pages.json subPackages field */
678
+ subPageMetaData = [];
679
+ /** Generated pages.json file path */
680
+ resolvedPagesJSONPath = "";
681
+ resolvedPagesJSONIndent;
682
+ resolvedPagesJSONNewline;
683
+ resolvedPagesJSONEofNewline;
684
+ /** Original options passed by the user */
685
+ rawOptions;
686
+ /** Project root directory */
687
+ root;
688
+ /** Resolved configuration options */
689
+ options;
690
+ logger;
691
+ /** Whether to work with vite-plugin-uni-platform plugin */
692
+ withUniPlatform = false;
693
+ /** Cached previous pages.json content to avoid redundant writes */
694
+ lastPagesJson = "";
695
+ /**
696
+ * Create a PageContext instance
697
+ * @param userOptions - User configuration options
698
+ * @param viteRoot - Vite project root directory, defaults to current working directory
699
+ */
700
+ constructor(userOptions, viteRoot = node_process.default.cwd()) {
701
+ this.rawOptions = userOptions;
702
+ this.root = slash(viteRoot);
703
+ debug$1.options("root", this.root);
704
+ this.options = resolveOptions(userOptions, this.root);
705
+ const debugOption = this.options.debug;
706
+ if (debugOption) {
707
+ const prefix = "vite-plugin-uni-pages:";
708
+ const suffix = typeof debugOption === "boolean" ? "*" : debugOption;
709
+ debug.default.enable(`${prefix}${suffix}`);
710
+ }
711
+ this.resolvedPagesJSONPath = node_path.default.join(this.root, this.options.outDir, OUTPUT_NAME);
712
+ debug$1.options(this.options);
713
+ }
714
+ /**
715
+ * Set the Vite logger
716
+ * @param logger - Vite logger instance
717
+ */
718
+ setLogger(logger) {
719
+ this.logger = logger;
720
+ }
721
+ /**
722
+ * Load user page configuration file (e.g. pages.config.ts)
723
+ * Uses unconfig to load configuration, supporting multiple config file formats
724
+ */
725
+ async loadUserPagesConfig() {
726
+ const configSource = this.options.configSource;
727
+ const { config, sources } = await (0, unconfig.loadConfig)({
728
+ cwd: this.root,
729
+ sources: configSource,
730
+ defaults: {}
731
+ });
732
+ this.pagesGlobConfig = config.default || config;
733
+ this.pagesConfigSourcePaths = sources;
734
+ debug$1.options(this.pagesGlobConfig);
735
+ }
736
+ /**
737
+ * Scan main package page directories and collect all page file paths
738
+ * Scan corresponding directories based on the configured dirs option
739
+ */
740
+ async scanPages() {
741
+ const paths = this.options.dirs.map((dir) => {
742
+ return {
743
+ dir,
744
+ files: getPagePaths(dir, this.options)
745
+ };
746
+ }).map((page) => page.files).flat();
747
+ debug$1.pages(paths);
748
+ const pages = /* @__PURE__ */ new Map();
749
+ for (const path of paths) {
750
+ const page = this.pages.get(path.absolutePath) || new Page(this, path);
751
+ pages.set(path.absolutePath, page);
752
+ }
753
+ this.pages = pages;
754
+ }
755
+ /**
756
+ * Scan sub-package page directories and collect all sub-package page file paths
757
+ * Scan corresponding directories based on the configured subPackages option
758
+ */
759
+ async scanSubPages() {
760
+ const paths = {};
761
+ const subPages = /* @__PURE__ */ new Map();
762
+ for (const dir of this.options.subPackages) {
763
+ const pagePaths = getPagePaths(dir, this.options);
764
+ paths[dir] = pagePaths;
765
+ const pages = /* @__PURE__ */ new Map();
766
+ for (const path of pagePaths) {
767
+ const page = this.subPages.get(dir)?.get(path.absolutePath) || new Page(this, path);
768
+ pages.set(path.absolutePath, page);
769
+ }
770
+ subPages.set(dir, pages);
771
+ }
772
+ debug$1.subPages(JSON.stringify(paths, null, 2));
773
+ this.subPages = subPages;
774
+ }
775
+ /**
776
+ * Set up Vite dev server for HMR and file watching
777
+ * @param server - Vite dev server instance
778
+ */
779
+ setupViteServer(server) {
780
+ if (this._server === server) return;
781
+ this._server = server;
782
+ this.setupWatcher(server.watcher);
783
+ }
784
+ /**
785
+ * Set up file watcher to monitor page file and config file changes
786
+ * Automatically update pages.json when page files or config files change
787
+ * @param watcher - chokidar file watcher instance
788
+ */
789
+ async setupWatcher(watcher) {
790
+ watcher.add(this.pagesConfigSourcePaths);
791
+ const targetDirs = [...this.options.dirs, ...this.options.subPackages].map((v) => slash(node_path.default.resolve(this.root, v)));
792
+ const isInTargetDirs = (filePath) => targetDirs.some((v) => slash(node_path.default.resolve(this.root, filePath)).startsWith(v));
793
+ watcher.on("add", async (path) => {
794
+ path = slash(path);
795
+ if (!isTargetFile(path)) return;
796
+ if (!isInTargetDirs(path)) return;
797
+ debug$1.pages(`File added: ${path}`);
798
+ if (await this.updatePagesJSON()) this.onUpdate();
799
+ });
800
+ watcher.on("change", async (path) => {
801
+ path = slash(path);
802
+ if (!isTargetFile(path)) return;
803
+ if (!isInTargetDirs(path)) return;
804
+ debug$1.pages(`File changed: ${path}`);
805
+ debug$1.pages(targetDirs);
806
+ debug$1.pages(isInTargetDirs(path));
807
+ if (await this.updatePagesJSON(path)) this.onUpdate();
808
+ });
809
+ watcher.on("change", async (path) => {
810
+ if (this.pagesConfigSourcePaths.includes(path)) {
811
+ debug$1.pages(`Config source changed: ${path}`);
812
+ if (await this.updatePagesJSON()) this.onUpdate();
813
+ }
814
+ });
815
+ watcher.on("unlink", async (path) => {
816
+ path = slash(path);
817
+ if (!isTargetFile(path)) return;
818
+ if (!isInTargetDirs(path)) return;
819
+ debug$1.pages(`File removed: ${path}`);
820
+ if (await this.updatePagesJSON()) this.onUpdate();
821
+ });
822
+ }
823
+ /**
824
+ * Page update callback, triggered when page files or configuration changes
825
+ * Responsible for invalidating virtual modules and notifying the browser to do a full reload
826
+ */
827
+ onUpdate() {
828
+ if (!this._server) return;
829
+ invalidatePagesModule(this._server);
830
+ debug$1.hmr("Reload generated pages.");
831
+ this._server.ws.send({ type: "full-reload" });
832
+ }
833
+ /**
834
+ * parse pages rules && set page type
835
+ * @param pages page path array
836
+ * @param type page type
837
+ * @param overrides custom page config
838
+ * @returns pages rules
839
+ */
840
+ async parsePages(pages, type, overrides) {
841
+ const jobs = [];
842
+ for (const [_, page] of pages) jobs.push(page.getPageMeta());
843
+ const generatedPageMetaData = await Promise.all(jobs);
844
+ const customPageMetaData = overrides || [];
845
+ const result = customPageMetaData.length ? mergePageMetaDataArray(generatedPageMetaData.concat(customPageMetaData)) : generatedPageMetaData;
846
+ const parseMeta = Array.from(result.reduce((map, page) => {
847
+ map.set(page.path, page);
848
+ return map;
849
+ }, /* @__PURE__ */ new Map()).values());
850
+ return type === "main" ? this.setHomePage(parseMeta) : parseMeta;
851
+ }
852
+ /**
853
+ * set home page
854
+ * @param result pages rules array
855
+ * @returns pages rules
856
+ */
857
+ setHomePage(result) {
858
+ if (!result.some(({ type }) => type === "home")) {
859
+ const basePath = slash(node_path.default.join(this.options.root, this.options.outDir));
860
+ const resolvedHomePages = this.options.homePage.map((v) => {
861
+ return slash(node_path.default.relative(basePath, slash(node_path.default.resolve(basePath, v))));
862
+ });
863
+ const matchHomePage = (itemPath, configPath) => {
864
+ if (itemPath === configPath) return true;
865
+ const normalizedItem = itemPath.replace(/\\/g, "/");
866
+ const normalizedConfig = configPath.replace(/\\/g, "/");
867
+ return normalizedItem.endsWith(`/${normalizedConfig}`);
868
+ };
869
+ if (!result.some((item) => {
870
+ const isFound = resolvedHomePages.some((expectedPath) => matchHomePage(item.path, expectedPath));
871
+ if (isFound) item.type = "home";
872
+ return isFound;
873
+ })) this.logger?.warn("No home page found, check the configuration of pages.config.ts, or add the `homePage` option to UniPages in vite.config.js, or add `definePage({ type: \"home\" })` in your vue page.", { timestamp: true });
874
+ }
875
+ result.sort((page) => page.type === "home" ? -1 : 0);
876
+ return result;
877
+ }
878
+ /**
879
+ * Merge main package page metadata
880
+ * Filter out pages belonging to sub-packages, then parse page metadata and merge user configuration
881
+ */
882
+ async mergePageMetaData() {
883
+ const subPageAbsolutePaths = Array.from(this.subPages.values()).flatMap((v) => Array.from(v.keys()));
884
+ for (const subPageAbsolutePath of subPageAbsolutePaths) this.pages.delete(subPageAbsolutePath);
885
+ const pageMetaData = await this.parsePages(this.pages, "main", this.pagesGlobConfig?.pages);
886
+ this.pageMetaData = pageMetaData;
887
+ debug$1.pages(this.pageMetaData);
888
+ }
889
+ /**
890
+ * Merge sub-package page metadata
891
+ * Parse page metadata for each sub-package and handle sub-package configuration inheritance
892
+ * Preserves sub-package level properties like plugins from user config
893
+ */
894
+ async mergeSubPageMetaData() {
895
+ const subPageMaps = {};
896
+ const subPlugins = {};
897
+ const subPackages = this.pagesGlobConfig?.subPackages || [];
898
+ for (const [dir, pages] of this.subPages) {
899
+ const basePath = slash(node_path.default.join(this.options.root, this.options.outDir));
900
+ const root = slash(node_path.default.relative(basePath, node_path.default.join(this.options.root, dir)));
901
+ const globPackage = subPackages?.find((v) => v.root === root);
902
+ subPageMaps[root] = await this.parsePages(pages, "sub", globPackage?.pages);
903
+ subPageMaps[root] = subPageMaps[root].map((page) => ({
904
+ ...page,
905
+ path: slash(node_path.default.relative(root, page.path))
906
+ }));
907
+ if (globPackage?.plugins) subPlugins[root] = globPackage.plugins;
908
+ }
909
+ for (const { root, pages, plugins } of subPackages) if (root && !subPageMaps[root]) {
910
+ subPageMaps[root] = pages || [];
911
+ if (plugins) subPlugins[root] = plugins;
912
+ }
913
+ const subPageMetaData = Object.keys(subPageMaps).map((root) => ({
914
+ root,
915
+ pages: subPageMaps[root],
916
+ ...subPlugins[root] && { plugins: subPlugins[root] }
917
+ })).filter((meta) => meta.pages.length > 0);
918
+ this.subPageMetaData = subPageMetaData;
919
+ debug$1.subPages(this.subPageMetaData);
920
+ }
921
+ /**
922
+ * Update pages.json file
923
+ * This is the core method responsible for coordinating the entire page configuration generation flow:
924
+ * 1. Check file changes (if filepath is specified)
925
+ * 2. Load user configuration
926
+ * 3. Scan page files
927
+ * 4. Merge page metadata
928
+ * 5. Generate and write pages.json
929
+ * @param filepath - Changed file path for incremental update judgment
930
+ * @returns Whether pages.json was successfully updated
931
+ */
932
+ async updatePagesJSON(filepath) {
933
+ if (filepath) {
934
+ let page = this.pages.get(filepath);
935
+ if (!page) {
936
+ let subPage;
937
+ for (const [_, pages] of this.subPages) {
938
+ subPage = pages.get(filepath);
939
+ if (subPage) break;
940
+ }
941
+ page = subPage;
942
+ }
943
+ if (page) {
944
+ await page.read();
945
+ if (!page.hasChanged()) {
946
+ debug$1.cache(`The page meta on page ${filepath} did not send any changes, skipping`);
947
+ return false;
948
+ }
949
+ }
950
+ }
951
+ checkPagesJsonFileSync(this.resolvedPagesJSONPath);
952
+ this.options.onBeforeLoadUserConfig(this);
953
+ await this.loadUserPagesConfig();
954
+ this.options.onAfterLoadUserConfig(this);
955
+ if (this.options.mergePages) {
956
+ this.options.onBeforeScanPages(this);
957
+ await this.scanPages();
958
+ await this.scanSubPages();
959
+ this.options.onAfterScanPages(this);
960
+ }
961
+ this.options.onBeforeMergePageMetaData(this);
962
+ await this.mergePageMetaData();
963
+ await this.mergeSubPageMetaData();
964
+ this.options.onAfterMergePageMetaData(this);
965
+ const pagesMap = /* @__PURE__ */ new Map();
966
+ (this.withUniPlatform ? this.pageMetaData.filter((v) => !/\..*$/.test(v.path) || v.path.includes(_uni_helper_uni_env.platform)).map((v) => {
967
+ v.path = v.path.replace(/\..*$/, "");
968
+ return v;
969
+ }) : this.pageMetaData).forEach((v) => pagesMap.set(v.path, v));
970
+ this.pageMetaData = [...pagesMap.values()];
971
+ this.options.onBeforeWriteFile(this);
972
+ const pagesJson = (0, comment_json.stringify)(await this.genratePagesJSON(), null, this.options.minify ? void 0 : await this.getIndent()) + (await this.getEndOfLine() ? await this.getNewline() : "");
973
+ this.generateDeclaration();
974
+ if (this.lastPagesJson === pagesJson) {
975
+ debug$1.pages("PagesJson Not have change");
976
+ return false;
977
+ }
978
+ await writeFileWithLock(this.resolvedPagesJSONPath, pagesJson);
979
+ this.lastPagesJson = pagesJson;
980
+ this.options.onAfterWriteFile(this);
981
+ return true;
982
+ }
983
+ /**
984
+ * Generate virtual module content
985
+ * Returns JavaScript code containing pages and subPackages exports
986
+ * @returns Virtual module code string
987
+ */
988
+ virtualModule() {
989
+ return [`export const pages = ${this.resolveRoutes()};`, `export const subPackages = ${this.resolveSubRoutes()};`].join("\n");
990
+ }
991
+ /**
992
+ * Resolve main package route data to JSON string
993
+ * @returns JSON string of main package page metadata
994
+ */
995
+ resolveRoutes() {
996
+ return (0, comment_json.stringify)(this.pageMetaData.map(stripType), null, 2);
997
+ }
998
+ /**
999
+ * Resolve sub-package route data to JSON string
1000
+ * @returns JSON string of sub-package page metadata
1001
+ */
1002
+ resolveSubRoutes() {
1003
+ return (0, comment_json.stringify)(this.subPageMetaData.map(({ pages, ...rest }) => ({
1004
+ ...rest,
1005
+ pages: pages.map(stripType)
1006
+ })), null, 2);
1007
+ }
1008
+ /**
1009
+ * Resolve tabBar configuration
1010
+ * Merges page-defined tabBar items with config-defined tabBar
1011
+ * @returns Merged tabBar configuration object, or undefined if no tabBar exists
1012
+ */
1013
+ async resolveTabBar() {
1014
+ const tabBarItems = [];
1015
+ for (const [_, page] of this.pages) {
1016
+ const tabbar = await page.getTabBar();
1017
+ if (tabbar) tabBarItems.push(tabbar);
1018
+ }
1019
+ if (tabBarItems.length === 0) return this.pagesGlobConfig?.tabBar;
1020
+ const tabBar = {
1021
+ ...this.pagesGlobConfig?.tabBar,
1022
+ list: this.pagesGlobConfig?.tabBar?.list || []
1023
+ };
1024
+ const pagePaths = /* @__PURE__ */ new Map();
1025
+ for (const item of tabBar.list) pagePaths.set(item.pagePath, true);
1026
+ tabBarItems.sort((a, b) => a.index - b.index);
1027
+ for (const item of tabBarItems) if (!pagePaths.has(item.pagePath)) {
1028
+ const { index: _, ...tabbar } = item;
1029
+ tabBar.list.push(tabbar);
1030
+ }
1031
+ return tabBar;
1032
+ }
1033
+ /**
1034
+ * Generate TypeScript declaration file
1035
+ * Generate type definitions for page paths to provide type hints during navigation
1036
+ */
1037
+ generateDeclaration() {
1038
+ if (!this.options.dts) return;
1039
+ debug$1.declaration("generating");
1040
+ return writeDeclaration(this, this.options.dts);
1041
+ }
1042
+ async genratePagesJSON() {
1043
+ const { pages: oldPages, subPackages: oldSubPackages, tabBar: oldTabBar } = (0, comment_json.parse)(await node_fs.default.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "") || "{}");
1044
+ const { pages: _pages, subPackages: _subPackages, tabBar: _tabBar, ...pageJson } = this.pagesGlobConfig || {};
1045
+ const currentPlatform = _uni_helper_uni_env.platform.toUpperCase();
1046
+ pageJson.pages = mergePlatformItems(oldPages, currentPlatform, this.pageMetaData, "path").map(stripType);
1047
+ if (pageJson.pages && pageJson.pages.length > 0) {
1048
+ const pagesArray = pageJson.pages;
1049
+ const homeIndex = pagesArray.findIndex((page) => page.type === "home");
1050
+ if (homeIndex > 0) {
1051
+ const [homePage] = pagesArray.splice(homeIndex, 1);
1052
+ pagesArray.unshift(homePage);
1053
+ }
1054
+ }
1055
+ pageJson.subPackages = oldSubPackages || new comment_json.CommentArray();
1056
+ const newSubPackages = /* @__PURE__ */ new Map();
1057
+ for (const item of this.subPageMetaData) newSubPackages.set(item.root, item);
1058
+ for (const existing of pageJson.subPackages) {
1059
+ const sub = newSubPackages.get(existing.root);
1060
+ if (sub) {
1061
+ existing.pages = mergePlatformItems(existing.pages, currentPlatform, sub.pages, "path").map(stripType);
1062
+ if (sub.plugins) existing.plugins = sub.plugins;
1063
+ newSubPackages.delete(existing.root);
1064
+ }
1065
+ }
1066
+ for (const [_, newSub] of newSubPackages) {
1067
+ const subPackage = {
1068
+ root: newSub.root,
1069
+ pages: mergePlatformItems(void 0, currentPlatform, newSub.pages, "path").map(stripType)
1070
+ };
1071
+ if (newSub.plugins) subPackage.plugins = newSub.plugins;
1072
+ pageJson.subPackages.push(subPackage);
1073
+ }
1074
+ const { list, ...tabBarOthers } = await this.resolveTabBar() || {};
1075
+ if (list) {
1076
+ const { list: oldList } = oldTabBar || {};
1077
+ const newList = mergePlatformItems(oldList, currentPlatform, list, "pagePath");
1078
+ pageJson.tabBar = {
1079
+ ...tabBarOthers,
1080
+ list: newList
1081
+ };
1082
+ } else pageJson.tabBar = void 0;
1083
+ return pageJson;
1084
+ }
1085
+ async readInfoFromPagesJSON() {
1086
+ const resolvedPagesJSONContent = await node_fs.default.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
1087
+ this.resolvedPagesJSONIndent = (0, detect_indent.default)(resolvedPagesJSONContent).indent || " ";
1088
+ this.resolvedPagesJSONNewline = (0, detect_newline.default)(resolvedPagesJSONContent) || "\n";
1089
+ this.resolvedPagesJSONEofNewline = (resolvedPagesJSONContent.at(-1) ?? "\n") === this.resolvedPagesJSONNewline;
1090
+ }
1091
+ async getIndent() {
1092
+ if (!this.resolvedPagesJSONIndent) await this.readInfoFromPagesJSON();
1093
+ return this.resolvedPagesJSONIndent;
1094
+ }
1095
+ async getNewline() {
1096
+ if (!this.resolvedPagesJSONNewline) await this.readInfoFromPagesJSON();
1097
+ return this.resolvedPagesJSONNewline;
1098
+ }
1099
+ async getEndOfLine() {
1100
+ if (!this.resolvedPagesJSONEofNewline) await this.readInfoFromPagesJSON();
1101
+ return this.resolvedPagesJSONEofNewline;
1102
+ }
631
1103
  };
632
- class PageContext {
633
- constructor(userOptions, viteRoot = process__default.cwd()) {
634
- __publicField(this, "_server");
635
- __publicField(this, "pagesGlobConfig");
636
- __publicField(this, "pagesConfigSourcePaths", []);
637
- __publicField(this, "pages", /* @__PURE__ */ new Map());
638
- // abs path -> Page
639
- __publicField(this, "subPages", /* @__PURE__ */ new Map());
640
- // root -> abs path -> page
641
- __publicField(this, "pageMetaData", []);
642
- __publicField(this, "subPageMetaData", []);
643
- __publicField(this, "resolvedPagesJSONPath", "");
644
- __publicField(this, "resolvedPagesJSONIndent");
645
- // ' '
646
- __publicField(this, "resolvedPagesJSONNewline");
647
- // '\n'
648
- __publicField(this, "resolvedPagesJSONEofNewline");
649
- // true
650
- __publicField(this, "rawOptions");
651
- __publicField(this, "root");
652
- __publicField(this, "options");
653
- __publicField(this, "logger");
654
- __publicField(this, "withUniPlatform", false);
655
- __publicField(this, "lastPagesJson", "");
656
- this.rawOptions = userOptions;
657
- this.root = slash(viteRoot);
658
- debug.options("root", this.root);
659
- this.options = resolveOptions(userOptions, this.root);
660
- const debugOption = this.options.debug;
661
- if (debugOption) {
662
- const prefix = "vite-plugin-uni-pages:";
663
- const suffix = typeof debugOption === "boolean" ? "*" : debugOption;
664
- Debug__default.enable(`${prefix}${suffix}`);
665
- }
666
- this.resolvedPagesJSONPath = path__default.join(this.root, this.options.outDir, OUTPUT_NAME);
667
- debug.options(this.options);
668
- }
669
- setLogger(logger) {
670
- this.logger = logger;
671
- }
672
- async loadUserPagesConfig() {
673
- const configSource = this.options.configSource;
674
- const { config, sources } = await unconfig.loadConfig({ cwd: this.root, sources: configSource, defaults: {} });
675
- this.pagesGlobConfig = config.default || config;
676
- this.pagesConfigSourcePaths = sources;
677
- debug.options(this.pagesGlobConfig);
678
- }
679
- async scanPages() {
680
- const pageDirFiles = this.options.dirs.map((dir) => {
681
- return { dir, files: getPagePaths(dir, this.options) };
682
- });
683
- const paths = pageDirFiles.map((page) => page.files).flat();
684
- debug.pages(paths);
685
- const pages = /* @__PURE__ */ new Map();
686
- for (const path2 of paths) {
687
- const page = this.pages.get(path2.absolutePath) || new Page(this, path2);
688
- pages.set(path2.absolutePath, page);
689
- }
690
- this.pages = pages;
691
- }
692
- async scanSubPages() {
693
- const paths = {};
694
- const subPages = /* @__PURE__ */ new Map();
695
- for (const dir of this.options.subPackages) {
696
- const pagePaths = getPagePaths(dir, this.options);
697
- paths[dir] = pagePaths;
698
- const pages = /* @__PURE__ */ new Map();
699
- for (const path2 of pagePaths) {
700
- const page = this.subPages.get(dir)?.get(path2.absolutePath) || new Page(this, path2);
701
- pages.set(path2.absolutePath, page);
702
- }
703
- subPages.set(dir, pages);
704
- }
705
- debug.subPages(JSON.stringify(paths, null, 2));
706
- this.subPages = subPages;
707
- }
708
- setupViteServer(server) {
709
- if (this._server === server)
710
- return;
711
- this._server = server;
712
- this.setupWatcher(server.watcher);
713
- }
714
- async setupWatcher(watcher) {
715
- watcher.add(this.pagesConfigSourcePaths);
716
- const targetDirs = [...this.options.dirs, ...this.options.subPackages].map((v) => slash(path__default.resolve(this.root, v)));
717
- const isInTargetDirs = (filePath) => targetDirs.some((v) => slash(path__default.resolve(this.root, filePath)).startsWith(v));
718
- watcher.on("add", async (path2) => {
719
- path2 = slash(path2);
720
- if (!isTargetFile(path2))
721
- return;
722
- if (!isInTargetDirs(path2))
723
- return;
724
- debug.pages(`File added: ${path2}`);
725
- if (await this.updatePagesJSON())
726
- this.onUpdate();
727
- });
728
- watcher.on("change", async (path2) => {
729
- path2 = slash(path2);
730
- if (!isTargetFile(path2))
731
- return;
732
- if (!isInTargetDirs(path2))
733
- return;
734
- debug.pages(`File changed: ${path2}`);
735
- debug.pages(targetDirs);
736
- debug.pages(isInTargetDirs(path2));
737
- if (await this.updatePagesJSON(path2))
738
- this.onUpdate();
739
- });
740
- watcher.on("change", async (path2) => {
741
- if (this.pagesConfigSourcePaths.includes(path2)) {
742
- debug.pages(`Config source changed: ${path2}`);
743
- if (await this.updatePagesJSON())
744
- this.onUpdate();
745
- }
746
- });
747
- watcher.on("unlink", async (path2) => {
748
- path2 = slash(path2);
749
- if (!isTargetFile(path2))
750
- return;
751
- if (!isInTargetDirs(path2))
752
- return;
753
- debug.pages(`File removed: ${path2}`);
754
- if (await this.updatePagesJSON())
755
- this.onUpdate();
756
- });
757
- }
758
- onUpdate() {
759
- if (!this._server)
760
- return;
761
- invalidatePagesModule(this._server);
762
- debug.hmr("Reload generated pages.");
763
- this._server.ws.send({
764
- type: "full-reload"
765
- });
766
- }
767
- /**
768
- * parse pages rules && set page type
769
- * @param pages page path array
770
- * @param type page type
771
- * @param overrides custom page config
772
- * @returns pages rules
773
- */
774
- async parsePages(pages, type, overrides) {
775
- const jobs = [];
776
- for (const [_, page] of pages) {
777
- jobs.push(page.getPageMeta());
778
- }
779
- const generatedPageMetaData = await Promise.all(jobs);
780
- const customPageMetaData = overrides || [];
781
- const result = customPageMetaData.length ? mergePageMetaDataArray(generatedPageMetaData.concat(customPageMetaData)) : generatedPageMetaData;
782
- const parseMeta = Array.from(
783
- result.reduce((map, page) => {
784
- map.set(page.path, page);
785
- return map;
786
- }, /* @__PURE__ */ new Map()).values()
787
- );
788
- return type === "main" ? this.setHomePage(parseMeta) : parseMeta;
789
- }
790
- /**
791
- * set home page
792
- * @param result pages rules array
793
- * @returns pages rules
794
- */
795
- setHomePage(result) {
796
- const hasHome = result.some(({ type }) => type === "home");
797
- if (!hasHome) {
798
- const isFoundHome = result.some((item) => {
799
- const isFound = this.options.homePage.find((v) => v === item.path);
800
- if (isFound)
801
- item.type = "home";
802
- return isFound;
803
- });
804
- if (!isFoundHome) {
805
- this.logger?.warn('No home page found, check the configuration of pages.config.ts, or add the `homePage` option to UniPages in vite.config.js, or add `type="home"` to the routeBlock of your vue page.', {
806
- timestamp: true
807
- });
808
- }
809
- }
810
- result.sort((page) => page.type === "home" ? -1 : 0);
811
- return result;
812
- }
813
- async mergePageMetaData() {
814
- const subPageAbsolutePaths = Array.from(this.subPages.values()).flatMap((v) => Array.from(v.keys()));
815
- for (const subPageAbsolutePath of subPageAbsolutePaths)
816
- this.pages.delete(subPageAbsolutePath);
817
- const pageMetaData = await this.parsePages(this.pages, "main", this.pagesGlobConfig?.pages);
818
- this.pageMetaData = pageMetaData;
819
- debug.pages(this.pageMetaData);
820
- }
821
- async mergeSubPageMetaData() {
822
- const subPageMaps = {};
823
- const subPackages = this.pagesGlobConfig?.subPackages || [];
824
- for (const [dir, pages] of this.subPages) {
825
- const basePath = slash(path__default.join(this.options.root, this.options.outDir));
826
- const root = slash(path__default.relative(basePath, path__default.join(this.options.root, dir)));
827
- const globPackage = subPackages?.find((v) => v.root === root);
828
- subPageMaps[root] = await this.parsePages(pages, "sub", globPackage?.pages);
829
- subPageMaps[root] = subPageMaps[root].map((page) => ({ ...page, path: slash(path__default.relative(root, page.path)) }));
830
- }
831
- for (const { root, pages } of subPackages) {
832
- if (root && !subPageMaps[root])
833
- subPageMaps[root] = pages || [];
834
- }
835
- const subPageMetaData = Object.keys(subPageMaps).map((root) => ({ root, pages: subPageMaps[root] })).filter((meta) => meta.pages.length > 0);
836
- this.subPageMetaData = subPageMetaData;
837
- debug.subPages(this.subPageMetaData);
838
- }
839
- async getTabBarMerged() {
840
- const tabBarItems = [];
841
- for (const [_, page] of this.pages) {
842
- const tabbar = await page.getTabBar();
843
- if (tabbar) {
844
- tabBarItems.push(tabbar);
845
- }
846
- }
847
- if (tabBarItems.length === 0) {
848
- return this.pagesGlobConfig?.tabBar;
849
- }
850
- const tabBar = {
851
- ...this.pagesGlobConfig?.tabBar,
852
- list: this.pagesGlobConfig?.tabBar?.list || []
853
- };
854
- const pagePaths = /* @__PURE__ */ new Map();
855
- for (const item of tabBar.list) {
856
- pagePaths.set(item.pagePath, true);
857
- }
858
- tabBarItems.sort((a, b) => a.index - b.index);
859
- for (const item of tabBarItems) {
860
- if (!pagePaths.has(item.pagePath)) {
861
- const { index: _, ...tabbar } = item;
862
- tabBar.list.push(tabbar);
863
- }
864
- }
865
- return tabBar;
866
- }
867
- async updatePagesJSON(filepath) {
868
- if (filepath) {
869
- let page = this.pages.get(filepath);
870
- if (!page) {
871
- let subPage;
872
- for (const [_, pages2] of this.subPages) {
873
- subPage = pages2.get(filepath);
874
- if (subPage) {
875
- break;
876
- }
877
- }
878
- page = subPage;
879
- }
880
- if (page) {
881
- await page.read();
882
- if (!page.hasChanged()) {
883
- debug.cache(`The route block on page ${filepath} did not send any changes, skipping`);
884
- return false;
885
- }
886
- }
887
- }
888
- checkPagesJsonFileSync(this.resolvedPagesJSONPath);
889
- this.options.onBeforeLoadUserConfig(this);
890
- await this.loadUserPagesConfig();
891
- this.options.onAfterLoadUserConfig(this);
892
- if (this.options.mergePages) {
893
- this.options.onBeforeScanPages(this);
894
- await this.scanPages();
895
- await this.scanSubPages();
896
- this.options.onAfterScanPages(this);
897
- }
898
- this.options.onBeforeMergePageMetaData(this);
899
- await this.mergePageMetaData();
900
- await this.mergeSubPageMetaData();
901
- this.options.onAfterMergePageMetaData(this);
902
- const pagesMap = /* @__PURE__ */ new Map();
903
- const pages = this.withUniPlatform ? this.pageMetaData.filter((v) => !/\..*$/.test(v.path) || v.path.includes(uniEnv.platform)).map((v) => {
904
- v.path = v.path.replace(/\..*$/, "");
905
- return v;
906
- }) : this.pageMetaData;
907
- pages.forEach((v) => pagesMap.set(v.path, v));
908
- this.pageMetaData = [...pagesMap.values()];
909
- this.options.onBeforeWriteFile(this);
910
- const data = await this.genratePagesJSON();
911
- const pagesJson = commentJson.stringify(
912
- data,
913
- null,
914
- this.options.minify ? void 0 : await this.getIndent()
915
- ) + (await this.getEndOfLine() ? await this.getNewline() : "");
916
- this.generateDeclaration();
917
- if (this.lastPagesJson === pagesJson) {
918
- debug.pages("PagesJson Not have change");
919
- return false;
920
- }
921
- await writeFileWithLock(this.resolvedPagesJSONPath, pagesJson);
922
- this.lastPagesJson = pagesJson;
923
- this.options.onAfterWriteFile(this);
924
- return true;
925
- }
926
- virtualModule() {
927
- const pages = `export const pages = ${this.resolveRoutes()};`;
928
- const subPackages = `export const subPackages = ${this.resolveSubRoutes()};`;
929
- return [pages, subPackages].join("\n");
930
- }
931
- resolveRoutes() {
932
- return commentJson.stringify(this.pageMetaData, null, 2);
933
- }
934
- resolveSubRoutes() {
935
- return commentJson.stringify(this.subPageMetaData, null, 2);
936
- }
937
- generateDeclaration() {
938
- if (!this.options.dts)
939
- return;
940
- debug.declaration("generating");
941
- return writeDeclaration(this, this.options.dts);
942
- }
943
- async genratePagesJSON() {
944
- const content = await fs__default.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
945
- const { pages: oldPages, subPackages: oldSubPackages, tabBar: oldTabBar } = commentJson.parse(content || "{}");
946
- const { pages: _, subPackages: __, tabBar: ___, ...pageJson } = this.pagesGlobConfig || {};
947
- const currentPlatform = uniEnv.platform.toUpperCase();
948
- pageJson.pages = mergePlatformItems(oldPages, currentPlatform, this.pageMetaData, "path");
949
- pageJson.subPackages = oldSubPackages || new commentJson.CommentArray();
950
- const newSubPackages = /* @__PURE__ */ new Map();
951
- for (const item of this.subPageMetaData) {
952
- newSubPackages.set(item.root, item);
953
- }
954
- for (const existing of pageJson.subPackages) {
955
- const sub = newSubPackages.get(existing.root);
956
- if (sub) {
957
- existing.pages = mergePlatformItems(existing.pages, currentPlatform, sub.pages, "path");
958
- newSubPackages.delete(existing.root);
959
- }
960
- }
961
- for (const [_2, newSub] of newSubPackages) {
962
- pageJson.subPackages.push({
963
- root: newSub.root,
964
- pages: mergePlatformItems(void 0, currentPlatform, newSub.pages, "path")
965
- });
966
- }
967
- const { list, ...tabBarOthers } = await this.getTabBarMerged() || {};
968
- if (list) {
969
- const { list: oldList } = oldTabBar || {};
970
- const newList = mergePlatformItems(oldList, currentPlatform, list, "pagePath");
971
- pageJson.tabBar = {
972
- ...tabBarOthers,
973
- // 每次都直接更新除 list 外的其他属性
974
- list: newList
975
- };
976
- } else {
977
- pageJson.tabBar = void 0;
978
- }
979
- return pageJson;
980
- }
981
- async readInfoFromPagesJSON() {
982
- const resolvedPagesJSONContent = await fs__default.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
983
- this.resolvedPagesJSONIndent = detectIndent__default(resolvedPagesJSONContent).indent || " ";
984
- this.resolvedPagesJSONNewline = detectNewline__default(resolvedPagesJSONContent) || "\n";
985
- this.resolvedPagesJSONEofNewline = (resolvedPagesJSONContent.at(-1) ?? "\n") === this.resolvedPagesJSONNewline;
986
- }
987
- async getIndent() {
988
- if (!this.resolvedPagesJSONIndent) {
989
- await this.readInfoFromPagesJSON();
990
- }
991
- return this.resolvedPagesJSONIndent;
992
- }
993
- async getNewline() {
994
- if (!this.resolvedPagesJSONNewline) {
995
- await this.readInfoFromPagesJSON();
996
- }
997
- return this.resolvedPagesJSONNewline;
998
- }
999
- async getEndOfLine() {
1000
- if (!this.resolvedPagesJSONEofNewline) {
1001
- await this.readInfoFromPagesJSON();
1002
- }
1003
- return this.resolvedPagesJSONEofNewline;
1004
- }
1005
- }
1104
+ /**
1105
+ * Get all page paths in the specified directory
1106
+ * @param dir - Page directory path
1107
+ * @param options - Resolved configuration options
1108
+ * @returns Page path array containing relative and absolute paths
1109
+ */
1006
1110
  function getPagePaths(dir, options) {
1007
- const pagesDirPath = slash(path__default.resolve(options.root, dir));
1008
- const basePath = slash(path__default.join(options.root, options.outDir));
1009
- const files = getPageFiles(pagesDirPath, options);
1010
- debug.pages(dir, files);
1011
- const pagePaths = files.map((file) => slash(file)).map((file) => ({
1012
- relativePath: path__default.relative(basePath, slash(path__default.resolve(pagesDirPath, file))),
1013
- absolutePath: slash(path__default.resolve(pagesDirPath, file))
1014
- }));
1015
- return pagePaths;
1111
+ const pagesDirPath = slash(node_path.default.resolve(options.root, dir));
1112
+ const basePath = slash(node_path.default.join(options.root, options.outDir));
1113
+ const files = getPageFiles(pagesDirPath, options);
1114
+ debug$1.pages(dir, files);
1115
+ return files.map((file) => slash(file)).map((file) => ({
1116
+ relativePath: node_path.default.relative(basePath, slash(node_path.default.resolve(pagesDirPath, file))),
1117
+ absolutePath: slash(node_path.default.resolve(pagesDirPath, file))
1118
+ }));
1016
1119
  }
1120
+ /**
1121
+ * Merge multi-platform page configuration items
1122
+ * Handle conditional compilation comments (#ifdef / #endif), merge configuration items from different platforms into one array
1123
+ * Same configuration items will automatically merge platform identifiers, different configuration items will keep conditional compilation comments
1124
+ *
1125
+ * @param source - Existing configuration item array (from pages.json)
1126
+ * @param currentPlatform - Current platform identifier (e.g. H5, MP-WEIXIN)
1127
+ * @param items - New configuration item array
1128
+ * @param uniqueKeyName - Field name used to identify configuration item uniqueness (e.g. 'path' or 'pagePath')
1129
+ * @returns Merged configuration item array with conditional compilation comments
1130
+ */
1017
1131
  function mergePlatformItems(source, currentPlatform, items, uniqueKeyName) {
1018
- const src = source || new commentJson.CommentArray();
1019
- currentPlatform = currentPlatform.toUpperCase();
1020
- let lastPlatforms = [];
1021
- for (const comment of src[Symbol.for("before:0")] || []) {
1022
- const trimed = comment.value.trim();
1023
- if (trimed.startsWith("GENERATED BY UNI-PAGES, PLATFORM:")) {
1024
- lastPlatforms = trimed.split(":")[1].split("||").map((s) => s.trim()).filter((s) => s !== currentPlatform).sort();
1025
- }
1026
- }
1027
- const tmpMap = /* @__PURE__ */ new Map();
1028
- for (let i = 0; i < src.length; i++) {
1029
- const item = src[i];
1030
- const uniqueKey = item[uniqueKeyName];
1031
- if (!uniqueKey) {
1032
- continue;
1033
- }
1034
- const beforeComments = src[Symbol.for(`before:${i}`)];
1035
- const ifdefComment = beforeComments?.find((c) => c.value.trim().startsWith("#ifdef"));
1036
- let platforms = [...lastPlatforms];
1037
- if (ifdefComment) {
1038
- const match = ifdefComment.value.match(/#ifdef\s+(.+)/);
1039
- if (match) {
1040
- platforms = match[1].split("||").map((p) => p.trim()).filter((s) => s !== currentPlatform).sort();
1041
- }
1042
- }
1043
- if (platforms.length === 0) {
1044
- continue;
1045
- }
1046
- const existing = tmpMap.get(uniqueKey) || [];
1047
- existing.push({ item, itemStr: JSON.stringify(item), platforms, platformStr: platforms.join(" || ") });
1048
- tmpMap.set(uniqueKey, existing);
1049
- }
1050
- for (const item of items) {
1051
- const newItem = item;
1052
- const uniqueKey = item[uniqueKeyName];
1053
- if (!uniqueKey) {
1054
- continue;
1055
- }
1056
- if (!tmpMap.has(uniqueKey)) {
1057
- tmpMap.set(uniqueKey, [{
1058
- item: newItem,
1059
- itemStr: JSON.stringify(newItem),
1060
- platforms: [currentPlatform],
1061
- platformStr: currentPlatform
1062
- }]);
1063
- continue;
1064
- }
1065
- const existing = tmpMap.get(uniqueKey);
1066
- const newItemStr = JSON.stringify(newItem);
1067
- const equalObj = existing.find((val) => val.itemStr === newItemStr);
1068
- if (equalObj) {
1069
- equalObj.platforms.push(currentPlatform);
1070
- equalObj.platforms.sort();
1071
- equalObj.platformStr = equalObj.platforms.join(" || ");
1072
- } else {
1073
- existing.push({
1074
- item: newItem,
1075
- itemStr: newItemStr,
1076
- platforms: [currentPlatform],
1077
- platformStr: currentPlatform
1078
- });
1079
- }
1080
- }
1081
- const result = new commentJson.CommentArray();
1082
- const platformUsage = {};
1083
- tmpMap.forEach((val) => {
1084
- Object.values(val).forEach((v) => {
1085
- platformUsage[v.platformStr] = (platformUsage[v.platformStr] || 0) + 1;
1086
- });
1087
- });
1088
- const usageKeys = Object.keys(platformUsage);
1089
- const defaultPlatformStr = usageKeys.length ? usageKeys.reduce((a, b) => platformUsage[a] > platformUsage[b] ? a : b) : currentPlatform;
1090
- result[Symbol.for("before:0")] = [{
1091
- type: "LineComment",
1092
- value: ` GENERATED BY UNI-PAGES, PLATFORM: ${defaultPlatformStr}`,
1093
- inline: false,
1094
- loc: {
1095
- start: { line: 0, column: 0 },
1096
- end: { line: 0, column: 0 }
1097
- }
1098
- }];
1099
- for (const [_, list] of tmpMap) {
1100
- for (const { item, platformStr } of list) {
1101
- result.push(item);
1102
- if (platformStr !== defaultPlatformStr) {
1103
- result[Symbol.for(`before:${result.length - 1}`)] = [{
1104
- type: "LineComment",
1105
- value: ` #ifdef ${platformStr}`,
1106
- inline: false,
1107
- loc: {
1108
- start: { line: 0, column: 0 },
1109
- end: { line: 0, column: 0 }
1110
- }
1111
- }];
1112
- result[Symbol.for(`after:${result.length - 1}`)] = [{
1113
- type: "LineComment",
1114
- value: " #endif",
1115
- inline: false,
1116
- loc: {
1117
- start: { line: 0, column: 0 },
1118
- end: { line: 0, column: 0 }
1119
- }
1120
- }];
1121
- }
1122
- }
1123
- }
1124
- return result;
1132
+ const src = source || new comment_json.CommentArray();
1133
+ currentPlatform = currentPlatform.toUpperCase();
1134
+ let lastPlatforms = [];
1135
+ for (const comment of src[Symbol.for("before:0")] || []) {
1136
+ const trimed = comment.value.trim();
1137
+ if (trimed.startsWith("GENERATED BY UNI-PAGES, PLATFORM:")) lastPlatforms = trimed.split(":")[1].split("||").map((s) => s.trim()).filter((s) => s !== currentPlatform).sort();
1138
+ }
1139
+ const tmpMap = /* @__PURE__ */ new Map();
1140
+ for (let i = 0; i < src.length; i++) {
1141
+ const item = src[i];
1142
+ const uniqueKey = item[uniqueKeyName];
1143
+ if (!uniqueKey) continue;
1144
+ const ifdefComment = src[Symbol.for(`before:${i}`)]?.find((c) => c.value.trim().startsWith("#ifdef"));
1145
+ let platforms = [...lastPlatforms];
1146
+ if (ifdefComment) {
1147
+ const match = ifdefComment.value.match(/#ifdef\s+(.+)/);
1148
+ if (match) platforms = match[1].split("||").map((p) => p.trim()).filter((s) => s !== currentPlatform).sort();
1149
+ }
1150
+ if (platforms.length === 0) continue;
1151
+ const existing = tmpMap.get(uniqueKey) || [];
1152
+ existing.push({
1153
+ item,
1154
+ itemStr: JSON.stringify(item),
1155
+ platforms,
1156
+ platformStr: platforms.join(" || ")
1157
+ });
1158
+ tmpMap.set(uniqueKey, existing);
1159
+ }
1160
+ for (const item of items) {
1161
+ const newItem = item;
1162
+ const uniqueKey = item[uniqueKeyName];
1163
+ if (!uniqueKey) continue;
1164
+ if (!tmpMap.has(uniqueKey)) {
1165
+ tmpMap.set(uniqueKey, [{
1166
+ item: newItem,
1167
+ itemStr: JSON.stringify(newItem),
1168
+ platforms: [currentPlatform],
1169
+ platformStr: currentPlatform
1170
+ }]);
1171
+ continue;
1172
+ }
1173
+ const existing = tmpMap.get(uniqueKey);
1174
+ const newItemStr = JSON.stringify(newItem);
1175
+ const equalObj = existing.find((val) => val.itemStr === newItemStr);
1176
+ if (equalObj) {
1177
+ equalObj.platforms.push(currentPlatform);
1178
+ equalObj.platforms.sort();
1179
+ equalObj.platformStr = equalObj.platforms.join(" || ");
1180
+ } else existing.push({
1181
+ item: newItem,
1182
+ itemStr: newItemStr,
1183
+ platforms: [currentPlatform],
1184
+ platformStr: currentPlatform
1185
+ });
1186
+ }
1187
+ const result = new comment_json.CommentArray();
1188
+ const platformUsage = {};
1189
+ tmpMap.forEach((val) => {
1190
+ Object.values(val).forEach((v) => {
1191
+ platformUsage[v.platformStr] = (platformUsage[v.platformStr] || 0) + 1;
1192
+ });
1193
+ });
1194
+ const usageKeys = Object.keys(platformUsage);
1195
+ const defaultPlatformStr = usageKeys.length ? usageKeys.reduce((a, b) => platformUsage[a] > platformUsage[b] ? a : b) : currentPlatform;
1196
+ result[Symbol.for("before:0")] = [{
1197
+ type: "LineComment",
1198
+ value: ` GENERATED BY UNI-PAGES, PLATFORM: ${defaultPlatformStr}`,
1199
+ inline: false,
1200
+ loc: {
1201
+ start: {
1202
+ line: 0,
1203
+ column: 0
1204
+ },
1205
+ end: {
1206
+ line: 0,
1207
+ column: 0
1208
+ }
1209
+ }
1210
+ }];
1211
+ for (const [_, list] of tmpMap) for (const { item, platformStr } of list) {
1212
+ result.push(item);
1213
+ if (platformStr !== defaultPlatformStr) {
1214
+ result[Symbol.for(`before:${result.length - 1}`)] = [{
1215
+ type: "LineComment",
1216
+ value: ` #ifdef ${platformStr}`,
1217
+ inline: false,
1218
+ loc: {
1219
+ start: {
1220
+ line: 0,
1221
+ column: 0
1222
+ },
1223
+ end: {
1224
+ line: 0,
1225
+ column: 0
1226
+ }
1227
+ }
1228
+ }];
1229
+ result[Symbol.for(`after:${result.length - 1}`)] = [{
1230
+ type: "LineComment",
1231
+ value: " #endif",
1232
+ inline: false,
1233
+ loc: {
1234
+ start: {
1235
+ line: 0,
1236
+ column: 0
1237
+ },
1238
+ end: {
1239
+ line: 0,
1240
+ column: 0
1241
+ }
1242
+ }
1243
+ }];
1244
+ }
1245
+ }
1246
+ return result;
1125
1247
  }
1126
-
1248
+ //#endregion
1249
+ //#region src/config/index.ts
1250
+ /**
1251
+ * Define uni-pages configuration
1252
+ * Used in pages.config.ts configuration file to provide type hints and validation
1253
+ *
1254
+ * @param config - Page configuration object
1255
+ * @returns Configuration object
1256
+ */
1127
1257
  function defineUniPages(config) {
1128
- return config;
1258
+ return config;
1129
1259
  }
1130
-
1260
+ /**
1261
+ * vite-plugin-uni-pages plugin main entry
1262
+ *
1263
+ * Automatically scan page directories and generate pages.json configuration file
1264
+ * Support definePage macro for defining page metadata
1265
+ * Support multi-platform conditional compilation
1266
+ * Support sub-package configuration
1267
+ * Support TypeScript declaration file generation
1268
+ *
1269
+ * @param userOptions - User configuration options
1270
+ * @returns Vite plugin instance
1271
+ */
1131
1272
  function VitePluginUniPages(userOptions = {}) {
1132
- let ctx;
1133
- const resolvedPagesJSONPath = path__default.join(
1134
- process__default.env.VITE_ROOT_DIR || process__default.cwd(),
1135
- userOptions.outDir ?? "src",
1136
- OUTPUT_NAME
1137
- );
1138
- checkPagesJsonFileSync(resolvedPagesJSONPath);
1139
- return {
1140
- name: "vite-plugin-uni-pages",
1141
- enforce: "pre",
1142
- async configResolved(config) {
1143
- ctx = new PageContext(userOptions, config.root);
1144
- if (config.plugins.some((v) => v.name === "vite-plugin-uni-platform"))
1145
- ctx.withUniPlatform = true;
1146
- const logger = vite.createLogger(void 0, {
1147
- prefix: "[vite-plugin-uni-pages]"
1148
- });
1149
- ctx.setLogger(logger);
1150
- await ctx.updatePagesJSON();
1151
- if (config.command === "build") {
1152
- if (config.build.watch)
1153
- ctx.setupWatcher(chokidar__default.watch([...ctx.options.dirs, ...ctx.options.subPackages]));
1154
- }
1155
- },
1156
- // Applet do not support custom route block, so we need to remove the route block here
1157
- async transform(code, id) {
1158
- if (!FILE_EXTENSIONS.find((ext) => id.endsWith(ext))) {
1159
- return null;
1160
- }
1161
- const sfc = parseSFC(code, { filename: id });
1162
- let macro;
1163
- if (sfc.scriptSetup) {
1164
- const ast = astKit.babelParse(sfc.scriptSetup.content, sfc.scriptSetup.lang || "js");
1165
- macro = findMacro(ast.body, sfc.filename);
1166
- }
1167
- if (!macro && sfc.script) {
1168
- const ast = astKit.babelParse(sfc.script.content, sfc.script.lang || "js");
1169
- macro = findMacro(ast.body, sfc.filename);
1170
- }
1171
- const routeBlock = sfc.customBlocks.find((block) => block.type === "route");
1172
- if (!macro && !routeBlock)
1173
- return null;
1174
- if (macro && routeBlock)
1175
- throw new Error(`\u4E0D\u652F\u6301\u6DF7\u5408\u4F7F\u7528 definePage() \u548C <route/> ${id}`);
1176
- const s = new MagicString__default(code);
1177
- if (macro)
1178
- s.remove(macro.start, macro.end);
1179
- if (routeBlock) {
1180
- console.log(kolorist.lightYellow("\u8B66\u544A\uFF1A"), `${kolorist.bold("<route/>")} \u6807\u7B7E\u5DF2\u5E9F\u5F03\uFF0C\u5C06\u5728\u4E0B\u4E00\u4E2A\u7248\u672C\u4E2D\u79FB\u9664\uFF0C\u8BF7\u4F7F\u7528 definePage() \u4EE3\u66FF\uFF1B${kolorist.link("\u67E5\u770B\u8FC1\u79FB\u6307\u5357", "https://uni-helper.js.org/vite-plugin-uni-pages/definePage")}\u3002`);
1181
- console.log(kolorist.dim(id));
1182
- console.log();
1183
- const routeBlockMatches = s.original.matchAll(
1184
- /<route[^>]*>([\s\S]*?)<\/route>/g
1185
- );
1186
- for (const match of routeBlockMatches) {
1187
- const index = match.index;
1188
- const length = match[0].length;
1189
- s.remove(index, index + length);
1190
- }
1191
- }
1192
- if (s.hasChanged()) {
1193
- return {
1194
- code: s.toString(),
1195
- map: s.generateMap({
1196
- source: id,
1197
- includeContent: true,
1198
- file: `${id}.map`
1199
- })
1200
- };
1201
- }
1202
- },
1203
- configureServer(server) {
1204
- ctx.setupViteServer(server);
1205
- },
1206
- resolveId(id) {
1207
- if (id === MODULE_ID_VIRTUAL)
1208
- return RESOLVED_MODULE_ID_VIRTUAL;
1209
- },
1210
- load(id) {
1211
- if (id === RESOLVED_MODULE_ID_VIRTUAL)
1212
- return ctx.virtualModule();
1213
- }
1214
- };
1273
+ let ctx;
1274
+ checkPagesJsonFileSync(node_path.default.join(node_process.default.env.VITE_ROOT_DIR || node_process.default.cwd(), userOptions.outDir ?? "src", OUTPUT_NAME));
1275
+ return {
1276
+ name: "vite-plugin-uni-pages",
1277
+ enforce: "pre",
1278
+ /**
1279
+ * Vite configResolved hook
1280
+ * Initialize PageContext, set logger, generate initial pages.json
1281
+ */
1282
+ async configResolved(config) {
1283
+ ctx = new PageContext(userOptions, config.root);
1284
+ if (config.plugins.some((v) => v.name === "vite-plugin-uni-platform")) ctx.withUniPlatform = true;
1285
+ const logger = (0, vite.createLogger)(void 0, { prefix: "[vite-plugin-uni-pages]" });
1286
+ ctx.setLogger(logger);
1287
+ await ctx.updatePagesJSON();
1288
+ if (config.command === "build") {
1289
+ if (config.build.watch) ctx.setupWatcher(chokidar.default.watch([...ctx.options.dirs, ...ctx.options.subPackages]));
1290
+ }
1291
+ },
1292
+ /**
1293
+ * Code transform hook
1294
+ * Remove definePage macro calls from Vue SFC to avoid runtime errors
1295
+ */
1296
+ async transform(code, id) {
1297
+ if (!FILE_EXTENSIONS.some((ext) => id.endsWith(ext))) return null;
1298
+ const sfc = parseSFC(code, { filename: id });
1299
+ let macro;
1300
+ if (sfc.scriptSetup) macro = findMacro((0, ast_kit.babelParse)(sfc.scriptSetup.content, sfc.scriptSetup.lang || "js").body, sfc.filename);
1301
+ if (!macro && sfc.script) macro = findMacro((0, ast_kit.babelParse)(sfc.script.content, sfc.script.lang || "js").body, sfc.filename);
1302
+ if (!macro) return null;
1303
+ const s = new magic_string.default(code);
1304
+ s.remove(macro.start, macro.end);
1305
+ if (s.hasChanged()) return {
1306
+ code: s.toString(),
1307
+ map: s.generateMap({
1308
+ source: id,
1309
+ includeContent: true,
1310
+ file: `${id}.map`
1311
+ })
1312
+ };
1313
+ },
1314
+ /**
1315
+ * Configure server hook
1316
+ * Set up file watching and HMR support
1317
+ */
1318
+ configureServer(server) {
1319
+ ctx.setupViteServer(server);
1320
+ },
1321
+ /**
1322
+ * Module resolution hook
1323
+ * Resolve virtual module identifier to internal path
1324
+ */
1325
+ resolveId(id) {
1326
+ if (id === "virtual:uni-pages") return RESOLVED_MODULE_ID_VIRTUAL;
1327
+ },
1328
+ /**
1329
+ * Module load hook
1330
+ * Return the code content of the virtual module
1331
+ */
1332
+ load(id) {
1333
+ if (id === RESOLVED_MODULE_ID_VIRTUAL) return ctx.virtualModule();
1334
+ }
1335
+ };
1215
1336
  }
1216
-
1337
+ //#endregion
1217
1338
  exports.FILE_EXTENSIONS = FILE_EXTENSIONS;
1218
1339
  exports.MODULE_ID_VIRTUAL = MODULE_ID_VIRTUAL;
1219
1340
  exports.OUTPUT_NAME = OUTPUT_NAME;
@@ -1221,26 +1342,37 @@ exports.Page = Page;
1221
1342
  exports.PageContext = PageContext;
1222
1343
  exports.RESOLVED_MODULE_ID_VIRTUAL = RESOLVED_MODULE_ID_VIRTUAL;
1223
1344
  exports.VitePluginUniPages = VitePluginUniPages;
1345
+ exports.default = VitePluginUniPages;
1224
1346
  exports.babelGenerate = babelGenerate;
1225
1347
  exports.checkPagesJsonFileSync = checkPagesJsonFileSync;
1226
- exports.debug = debug;
1227
- exports.default = VitePluginUniPages;
1348
+ exports.debug = debug$1;
1349
+ Object.defineProperty(exports, "definePage", {
1350
+ enumerable: true,
1351
+ get: function() {
1352
+ return _uni_helper_uni_pages_types.definePage;
1353
+ }
1354
+ });
1228
1355
  exports.defineUniPages = defineUniPages;
1229
1356
  exports.extsToGlob = extsToGlob;
1230
1357
  exports.findImports = findImports;
1231
1358
  exports.findMacro = findMacro;
1232
1359
  exports.getPageFiles = getPageFiles;
1233
- exports.getRouteBlock = getRouteBlock;
1234
- exports.getRouteSfcBlock = getRouteSfcBlock;
1235
1360
  exports.invalidatePagesModule = invalidatePagesModule;
1236
1361
  exports.isTargetFile = isTargetFile;
1237
1362
  exports.mergePageMetaDataArray = mergePageMetaDataArray;
1238
1363
  exports.parseCode = parseCode;
1239
- exports.parseCustomBlock = parseCustomBlock;
1240
1364
  exports.parseSFC = parseSFC;
1241
1365
  exports.resolveOptions = resolveOptions;
1242
1366
  exports.resolvePageDirs = resolvePageDirs;
1243
1367
  exports.sleep = sleep;
1244
- exports.tryPageMetaFromCustomBlock = tryPageMetaFromCustomBlock;
1368
+ exports.stripType = stripType;
1245
1369
  exports.tryPageMetaFromMacro = tryPageMetaFromMacro;
1246
1370
  exports.writeFileWithLock = writeFileWithLock;
1371
+ Object.keys(_uni_helper_uni_pages_types).forEach(function(k) {
1372
+ if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1373
+ enumerable: true,
1374
+ get: function() {
1375
+ return _uni_helper_uni_pages_types[k];
1376
+ }
1377
+ });
1378
+ });