@uni-helper/vite-plugin-uni-pages 0.3.15 → 0.3.17

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
@@ -2,7 +2,6 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const node_child_process = require('node:child_process');
6
5
  const path = require('node:path');
7
6
  const process = require('node:process');
8
7
  const astKit = require('ast-kit');
@@ -10,13 +9,14 @@ const chokidar = require('chokidar');
10
9
  const kolorist = require('kolorist');
11
10
  const MagicString = require('magic-string');
12
11
  const vite = require('vite');
12
+ const fs = require('node:fs');
13
13
  const uniEnv = require('@uni-helper/uni-env');
14
14
  const commentJson = require('comment-json');
15
15
  const Debug = require('debug');
16
16
  const detectIndent = require('detect-indent');
17
17
  const detectNewline = require('detect-newline');
18
+ const lockfile = require('proper-lockfile');
18
19
  const unconfig = require('unconfig');
19
- const fs = require('node:fs');
20
20
  const promises = require('node:fs/promises');
21
21
  const fg = require('fast-glob');
22
22
  const node_module = require('node:module');
@@ -47,10 +47,11 @@ const path__default = /*#__PURE__*/_interopDefaultCompat(path);
47
47
  const process__default = /*#__PURE__*/_interopDefaultCompat(process);
48
48
  const chokidar__default = /*#__PURE__*/_interopDefaultCompat(chokidar);
49
49
  const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
50
+ const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
50
51
  const Debug__default = /*#__PURE__*/_interopDefaultCompat(Debug);
51
52
  const detectIndent__default = /*#__PURE__*/_interopDefaultCompat(detectIndent);
52
53
  const detectNewline__default = /*#__PURE__*/_interopDefaultCompat(detectNewline);
53
- const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
54
+ const lockfile__default = /*#__PURE__*/_interopDefaultCompat(lockfile);
54
55
  const fg__default = /*#__PURE__*/_interopDefaultCompat(fg);
55
56
  const vm__default = /*#__PURE__*/_interopDefaultCompat(vm);
56
57
  const babelGenerator__default = /*#__PURE__*/_interopDefaultCompat(babelGenerator);
@@ -234,6 +235,9 @@ ${jsCode}
234
235
  `);
235
236
  }
236
237
  }
238
+ function sleep(ms) {
239
+ return new Promise((resolve) => setTimeout(resolve, ms));
240
+ }
237
241
  function getDefaultExport(expr) {
238
242
  return expr.default === void 0 ? expr : expr.default;
239
243
  }
@@ -249,22 +253,72 @@ function getPageFiles(path, options) {
249
253
  });
250
254
  return files;
251
255
  }
252
- function checkPagesJsonFile(path) {
253
- if (!fs__default.existsSync(path)) {
254
- writeFileSync(path, commentJson.stringify({ pages: [{ path: "" }] }, null, 2));
255
- return false;
256
- }
257
- return true;
258
- }
259
- function readFileSync(path) {
256
+ function checkPagesJsonFileSync(path) {
257
+ const createEmptyFile = (path2) => {
258
+ try {
259
+ fs__default.writeFileSync(
260
+ path2,
261
+ JSON.stringify({ pages: [{ path: "" }] }, null, 2),
262
+ { encoding: "utf-8" }
263
+ );
264
+ return true;
265
+ } catch {
266
+ return false;
267
+ }
268
+ };
269
+ const unlinkFile = (path2) => {
270
+ try {
271
+ fs__default.unlinkSync(path2);
272
+ return true;
273
+ } catch {
274
+ return false;
275
+ }
276
+ };
260
277
  try {
261
- return fs__default.readFileSync(path, { encoding: "utf-8" });
278
+ try {
279
+ fs__default.accessSync(path, fs__default.constants.F_OK);
280
+ } catch {
281
+ return createEmptyFile(path);
282
+ }
283
+ const stat = fs__default.statSync(path);
284
+ if (!stat.isFile()) {
285
+ if (!unlinkFile(path)) {
286
+ return false;
287
+ }
288
+ return createEmptyFile(path);
289
+ }
290
+ try {
291
+ fs__default.accessSync(path, fs__default.constants.R_OK | fs__default.constants.W_OK);
292
+ return true;
293
+ } catch {
294
+ if (!unlinkFile(path)) {
295
+ return false;
296
+ }
297
+ return createEmptyFile(path);
298
+ }
262
299
  } catch {
263
- return "";
300
+ return createEmptyFile(path);
264
301
  }
265
302
  }
266
- function writeFileSync(path, content) {
267
- fs__default.writeFileSync(path, content, { encoding: "utf-8" });
303
+ async function writeFileWithLock(path, content, retry = 3) {
304
+ if (retry <= 0) {
305
+ debug.error(`${path} \u83B7\u53D6\u6587\u4EF6\u9501\u5931\u8D25\uFF0C\u5199\u5165\u5931\u8D25`);
306
+ return;
307
+ }
308
+ let relase;
309
+ try {
310
+ try {
311
+ relase = await lockfile__default.lock(path, { realpath: false });
312
+ } catch {
313
+ await sleep(500);
314
+ return writeFileWithLock(path, content, retry - 1);
315
+ }
316
+ await fs__default.promises.writeFile(path, content, { encoding: "utf-8" });
317
+ } finally {
318
+ if (relase) {
319
+ await relase();
320
+ }
321
+ }
268
322
  }
269
323
 
270
324
  function resolveOptions(userOptions, viteRoot = process__default.cwd()) {
@@ -461,7 +515,7 @@ class Page {
461
515
  }
462
516
  async readPageMetaFromFile() {
463
517
  try {
464
- const content = fs.readFileSync(this.path.absolutePath, "utf-8");
518
+ const content = await fs__default.promises.readFile(this.path.absolutePath, { encoding: "utf-8" });
465
519
  const sfc = parseSFC(content, { filename: this.path.absolutePath });
466
520
  const meta = await tryPageMetaFromMacro(sfc);
467
521
  if (meta) {
@@ -558,7 +612,6 @@ var __publicField = (obj, key, value) => {
558
612
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
559
613
  return value;
560
614
  };
561
- let lsatPagesJson = "";
562
615
  class PageContext {
563
616
  constructor(userOptions, viteRoot = process__default.cwd()) {
564
617
  __publicField(this, "_server");
@@ -571,14 +624,18 @@ class PageContext {
571
624
  __publicField(this, "pageMetaData", []);
572
625
  __publicField(this, "subPageMetaData", []);
573
626
  __publicField(this, "resolvedPagesJSONPath", "");
574
- __publicField(this, "resolvedPagesJSONIndent", " ");
575
- __publicField(this, "resolvedPagesJSONNewline", "\n");
576
- __publicField(this, "resolvedPagesJSONEofNewline", true);
627
+ __publicField(this, "resolvedPagesJSONIndent");
628
+ // ' '
629
+ __publicField(this, "resolvedPagesJSONNewline");
630
+ // '\n'
631
+ __publicField(this, "resolvedPagesJSONEofNewline");
632
+ // true
577
633
  __publicField(this, "rawOptions");
578
634
  __publicField(this, "root");
579
635
  __publicField(this, "options");
580
636
  __publicField(this, "logger");
581
637
  __publicField(this, "withUniPlatform", false);
638
+ __publicField(this, "lastPagesJson", "");
582
639
  this.rawOptions = userOptions;
583
640
  this.root = slash(viteRoot);
584
641
  debug.options("root", this.root);
@@ -590,10 +647,6 @@ class PageContext {
590
647
  Debug__default.enable(`${prefix}${suffix}`);
591
648
  }
592
649
  this.resolvedPagesJSONPath = path__default.join(this.root, this.options.outDir, OUTPUT_NAME);
593
- const resolvedPagesJSONContent = readFileSync(this.resolvedPagesJSONPath);
594
- this.resolvedPagesJSONIndent = detectIndent__default(resolvedPagesJSONContent).indent || " ";
595
- this.resolvedPagesJSONNewline = detectNewline__default(resolvedPagesJSONContent) || "\n";
596
- this.resolvedPagesJSONEofNewline = (resolvedPagesJSONContent.at(-1) ?? "\n") === this.resolvedPagesJSONNewline;
597
650
  debug.options(this.options);
598
651
  }
599
652
  setLogger(logger) {
@@ -809,7 +862,7 @@ class PageContext {
809
862
  }
810
863
  }
811
864
  }
812
- checkPagesJsonFile(this.resolvedPagesJSONPath);
865
+ checkPagesJsonFileSync(this.resolvedPagesJSONPath);
813
866
  this.options.onBeforeLoadUserConfig(this);
814
867
  await this.loadUserPagesConfig();
815
868
  this.options.onAfterLoadUserConfig(this);
@@ -831,24 +884,19 @@ class PageContext {
831
884
  pages.forEach((v) => pagesMap.set(v.path, v));
832
885
  this.pageMetaData = [...pagesMap.values()];
833
886
  this.options.onBeforeWriteFile(this);
834
- const data = {
835
- ...this.pagesGlobConfig,
836
- pages: this.pageMetaData,
837
- subPackages: this.subPageMetaData,
838
- tabBar: await this.getTabBarMerged()
839
- };
887
+ const data = await this.genratePagesJSON();
840
888
  const pagesJson = commentJson.stringify(
841
889
  data,
842
890
  null,
843
- this.options.minify ? void 0 : this.resolvedPagesJSONIndent
844
- ) + (this.resolvedPagesJSONEofNewline ? this.resolvedPagesJSONNewline : "");
891
+ this.options.minify ? void 0 : await this.getIndent()
892
+ ) + (await this.getEndOfLine() ? await this.getNewline() : "");
845
893
  this.generateDeclaration();
846
- if (lsatPagesJson === pagesJson) {
894
+ if (this.lastPagesJson === pagesJson) {
847
895
  debug.pages("PagesJson Not have change");
848
896
  return false;
849
897
  }
850
- writeFileSync(this.resolvedPagesJSONPath, pagesJson);
851
- lsatPagesJson = pagesJson;
898
+ await writeFileWithLock(this.resolvedPagesJSONPath, pagesJson);
899
+ this.lastPagesJson = pagesJson;
852
900
  this.options.onAfterWriteFile(this);
853
901
  return true;
854
902
  }
@@ -869,6 +917,88 @@ class PageContext {
869
917
  debug.declaration("generating");
870
918
  return writeDeclaration(this, this.options.dts);
871
919
  }
920
+ async writePagesJSONFile(pagesJson, retry = 3) {
921
+ if (retry <= 0) {
922
+ debug.error(`${this.resolvedPagesJSONPath} \u83B7\u53D6\u6587\u4EF6\u9501\u5931\u8D25\uFF0C\u5199\u5165\u5931\u8D25`);
923
+ return;
924
+ }
925
+ let relase;
926
+ try {
927
+ try {
928
+ relase = await lockfile__default.lock(this.resolvedPagesJSONPath, { realpath: false });
929
+ } catch {
930
+ return this.writePagesJSONFile(pagesJson, retry - 1);
931
+ }
932
+ await fs__default.promises.writeFile(this.resolvedPagesJSONPath, pagesJson, { encoding: "utf-8" });
933
+ } finally {
934
+ if (relase) {
935
+ await relase();
936
+ }
937
+ }
938
+ }
939
+ async genratePagesJSON() {
940
+ const content = await fs__default.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
941
+ let pageJson = commentJson.parse(content || "{}");
942
+ const { pages: _, subPackages: __, tabBar: ___, ...others } = this.pagesGlobConfig || {};
943
+ pageJson = Object.assign(pageJson, {
944
+ ...others
945
+ });
946
+ const currentPlatform = uniEnv.platform.toUpperCase();
947
+ pageJson.pages = mergePlatformItems(pageJson?.pages, currentPlatform, this.pageMetaData, "path");
948
+ pageJson.subPackages = pageJson?.subPackages || new commentJson.CommentArray();
949
+ const newSubPackages = /* @__PURE__ */ new Map();
950
+ for (const item of this.subPageMetaData) {
951
+ newSubPackages.set(item.root, item);
952
+ }
953
+ for (const existing of pageJson.subPackages) {
954
+ const sub = newSubPackages.get(existing.root);
955
+ if (sub) {
956
+ existing.pages = mergePlatformItems(existing.pages, currentPlatform, sub.pages, "path");
957
+ newSubPackages.delete(existing.root);
958
+ }
959
+ }
960
+ for (const [_2, newSub] of newSubPackages) {
961
+ pageJson.subPackages.push({
962
+ root: newSub.root,
963
+ pages: mergePlatformItems(void 0, currentPlatform, newSub.pages, "path")
964
+ });
965
+ }
966
+ const tabBar = await this.getTabBarMerged();
967
+ if (tabBar) {
968
+ const list = mergePlatformItems(pageJson?.tabBar?.list, currentPlatform, tabBar.list, "pagePath");
969
+ if (pageJson?.tabBar?.list) {
970
+ pageJson.tabBar.list = list;
971
+ } else {
972
+ pageJson.tabBar = pageJson.tabBar || {};
973
+ pageJson.tabBar.list = list;
974
+ }
975
+ }
976
+ return pageJson;
977
+ }
978
+ async readInfoFromPagesJSON() {
979
+ const resolvedPagesJSONContent = await fs__default.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
980
+ this.resolvedPagesJSONIndent = detectIndent__default(resolvedPagesJSONContent).indent || " ";
981
+ this.resolvedPagesJSONNewline = detectNewline__default(resolvedPagesJSONContent) || "\n";
982
+ this.resolvedPagesJSONEofNewline = (resolvedPagesJSONContent.at(-1) ?? "\n") === this.resolvedPagesJSONNewline;
983
+ }
984
+ async getIndent() {
985
+ if (!this.resolvedPagesJSONIndent) {
986
+ await this.readInfoFromPagesJSON();
987
+ }
988
+ return this.resolvedPagesJSONIndent;
989
+ }
990
+ async getNewline() {
991
+ if (!this.resolvedPagesJSONNewline) {
992
+ await this.readInfoFromPagesJSON();
993
+ }
994
+ return this.resolvedPagesJSONNewline;
995
+ }
996
+ async getEndOfLine() {
997
+ if (!this.resolvedPagesJSONEofNewline) {
998
+ await this.readInfoFromPagesJSON();
999
+ }
1000
+ return this.resolvedPagesJSONEofNewline;
1001
+ }
872
1002
  }
873
1003
  function getPagePaths(dir, options) {
874
1004
  const pagesDirPath = slash(path__default.resolve(options.root, dir));
@@ -881,25 +1011,117 @@ function getPagePaths(dir, options) {
881
1011
  }));
882
1012
  return pagePaths;
883
1013
  }
1014
+ function mergePlatformItems(source, currentPlatform, items, uniqueKeyName) {
1015
+ const src = source || new commentJson.CommentArray();
1016
+ currentPlatform = currentPlatform.toUpperCase();
1017
+ let lastPlatforms = [];
1018
+ for (const comment of src[Symbol.for("before:0")] || []) {
1019
+ const trimed = comment.value.trim();
1020
+ if (trimed.startsWith("GENERATED BY UNI-PAGES, PLATFORM:")) {
1021
+ lastPlatforms = trimed.split(":")[1].split("||").map((s) => s.trim()).filter((s) => s !== currentPlatform).sort();
1022
+ }
1023
+ }
1024
+ const tmpMap = /* @__PURE__ */ new Map();
1025
+ for (let i = 0; i < src.length; i++) {
1026
+ const item = src[i];
1027
+ const uniqueKey = item[uniqueKeyName];
1028
+ if (!uniqueKey) {
1029
+ continue;
1030
+ }
1031
+ const beforeComments = src[Symbol.for(`before:${i}`)];
1032
+ const ifdefComment = beforeComments?.find((c) => c.value.trim().startsWith("#ifdef"));
1033
+ let platforms = [...lastPlatforms];
1034
+ if (ifdefComment) {
1035
+ const match = ifdefComment.value.match(/#ifdef\s+(.+)/);
1036
+ if (match) {
1037
+ platforms = match[1].split("||").map((p) => p.trim()).filter((s) => s !== currentPlatform).sort();
1038
+ }
1039
+ }
1040
+ if (platforms.length === 0) {
1041
+ continue;
1042
+ }
1043
+ const existing = tmpMap.get(uniqueKey) || [];
1044
+ existing.push({ item, platforms, platformStr: platforms.join(" || ") });
1045
+ tmpMap.set(uniqueKey, existing);
1046
+ }
1047
+ for (const item of items) {
1048
+ const newItem = item;
1049
+ const uniqueKey = item[uniqueKeyName];
1050
+ if (!uniqueKey) {
1051
+ continue;
1052
+ }
1053
+ if (!tmpMap.has(uniqueKey)) {
1054
+ tmpMap.set(uniqueKey, [{
1055
+ item: newItem,
1056
+ platforms: [currentPlatform],
1057
+ platformStr: currentPlatform
1058
+ }]);
1059
+ continue;
1060
+ }
1061
+ const existing = tmpMap.get(uniqueKey);
1062
+ const newItemStr = JSON.stringify(newItem);
1063
+ const equalObj = existing.find((val) => JSON.stringify(val.item) === newItemStr);
1064
+ if (equalObj) {
1065
+ equalObj.platforms.push(currentPlatform);
1066
+ equalObj.platformStr = equalObj.platforms.join(" || ");
1067
+ } else {
1068
+ existing.push({
1069
+ item: newItem,
1070
+ platforms: [currentPlatform],
1071
+ platformStr: currentPlatform
1072
+ });
1073
+ }
1074
+ }
1075
+ const result = new commentJson.CommentArray();
1076
+ const platformUsage = {};
1077
+ tmpMap.forEach((val) => {
1078
+ Object.values(val).forEach((v) => {
1079
+ platformUsage[v.platformStr] = (platformUsage[v.platformStr] || 0) + 1;
1080
+ });
1081
+ });
1082
+ const usageKeys = Object.keys(platformUsage);
1083
+ const defaultPlatformStr = usageKeys.length ? usageKeys.reduce((a, b) => platformUsage[a] > platformUsage[b] ? a : b) : currentPlatform;
1084
+ result[Symbol.for("before:0")] = [{
1085
+ type: "LineComment",
1086
+ value: ` GENERATED BY UNI-PAGES, PLATFORM: ${defaultPlatformStr}`,
1087
+ inline: false,
1088
+ loc: {
1089
+ start: { line: 0, column: 0 },
1090
+ end: { line: 0, column: 0 }
1091
+ }
1092
+ }];
1093
+ for (const [_, list] of tmpMap) {
1094
+ for (const { item, platformStr } of list) {
1095
+ result.push(item);
1096
+ if (platformStr !== defaultPlatformStr) {
1097
+ result[Symbol.for(`before:${result.length - 1}`)] = [{
1098
+ type: "LineComment",
1099
+ value: ` #ifdef ${platformStr}`,
1100
+ inline: false,
1101
+ loc: {
1102
+ start: { line: 0, column: 0 },
1103
+ end: { line: 0, column: 0 }
1104
+ }
1105
+ }];
1106
+ result[Symbol.for(`after:${result.length - 1}`)] = [{
1107
+ type: "LineComment",
1108
+ value: " #endif",
1109
+ inline: false,
1110
+ loc: {
1111
+ start: { line: 0, column: 0 },
1112
+ end: { line: 0, column: 0 }
1113
+ }
1114
+ }];
1115
+ }
1116
+ }
1117
+ }
1118
+ return result;
1119
+ }
884
1120
 
885
1121
  function defineUniPages(config) {
886
1122
  return config;
887
1123
  }
888
1124
 
889
- async function restart() {
890
- return new Promise((resolve) => {
891
- const build = node_child_process.spawn(process__default.argv.shift(), process__default.argv, {
892
- cwd: process__default.env.VITE_ROOT_DIR || process__default.cwd(),
893
- detached: true,
894
- env: process__default.env
895
- });
896
- build.stdout?.pipe(process__default.stdout);
897
- build.stderr?.pipe(process__default.stderr);
898
- build.on("close", (code) => {
899
- resolve(process__default.exit(code));
900
- });
901
- });
902
- }
903
1125
  function VitePluginUniPages(userOptions = {}) {
904
1126
  let ctx;
905
1127
  const resolvedPagesJSONPath = path__default.join(
@@ -907,7 +1129,7 @@ function VitePluginUniPages(userOptions = {}) {
907
1129
  userOptions.outDir ?? "src",
908
1130
  OUTPUT_NAME
909
1131
  );
910
- const isValidated = checkPagesJsonFile(resolvedPagesJSONPath);
1132
+ checkPagesJsonFileSync(resolvedPagesJSONPath);
911
1133
  return {
912
1134
  name: "vite-plugin-uni-pages",
913
1135
  enforce: "pre",
@@ -921,12 +1143,6 @@ function VitePluginUniPages(userOptions = {}) {
921
1143
  ctx.setLogger(logger);
922
1144
  await ctx.updatePagesJSON();
923
1145
  if (config.command === "build") {
924
- if (!isValidated) {
925
- ctx.logger?.warn("In build mode, if `pages.json` does not exist, the plugin cannot create the complete `pages.json` before the uni-app, so it restarts the build.", {
926
- timestamp: true
927
- });
928
- await restart();
929
- }
930
1146
  if (config.build.watch)
931
1147
  ctx.setupWatcher(chokidar__default.watch([...ctx.options.dirs, ...ctx.options.subPackages]));
932
1148
  }
@@ -1000,7 +1216,7 @@ exports.PageContext = PageContext;
1000
1216
  exports.RESOLVED_MODULE_ID_VIRTUAL = RESOLVED_MODULE_ID_VIRTUAL;
1001
1217
  exports.VitePluginUniPages = VitePluginUniPages;
1002
1218
  exports.babelGenerate = babelGenerate;
1003
- exports.checkPagesJsonFile = checkPagesJsonFile;
1219
+ exports.checkPagesJsonFileSync = checkPagesJsonFileSync;
1004
1220
  exports.debug = debug;
1005
1221
  exports.default = VitePluginUniPages;
1006
1222
  exports.defineUniPages = defineUniPages;
@@ -1016,9 +1232,9 @@ exports.isTargetFile = isTargetFile;
1016
1232
  exports.mergePageMetaDataArray = mergePageMetaDataArray;
1017
1233
  exports.parseCustomBlock = parseCustomBlock;
1018
1234
  exports.parseSFC = parseSFC;
1019
- exports.readFileSync = readFileSync;
1020
1235
  exports.resolveOptions = resolveOptions;
1021
1236
  exports.resolvePageDirs = resolvePageDirs;
1237
+ exports.sleep = sleep;
1022
1238
  exports.tryPageMetaFromCustomBlock = tryPageMetaFromCustomBlock;
1023
1239
  exports.tryPageMetaFromMacro = tryPageMetaFromMacro;
1024
- exports.writeFileSync = writeFileSync;
1240
+ exports.writeFileWithLock = writeFileWithLock;
package/dist/index.d.cts CHANGED
@@ -6,6 +6,7 @@ import { SFCParseOptions, SFCDescriptor, SFCBlock } from '@vue/compiler-sfc';
6
6
  import * as t from '@babel/types';
7
7
  import babelGenerator from '@babel/generator';
8
8
  import Debug from 'debug';
9
+ import fs from 'node:fs';
9
10
 
10
11
  interface ConditionItem {
11
12
  /**
@@ -2955,14 +2956,15 @@ declare class PageContext {
2955
2956
  pageMetaData: PageMetaDatum[];
2956
2957
  subPageMetaData: SubPageMetaDatum[];
2957
2958
  resolvedPagesJSONPath: string;
2958
- resolvedPagesJSONIndent: string;
2959
- resolvedPagesJSONNewline: string;
2960
- resolvedPagesJSONEofNewline: boolean;
2959
+ private resolvedPagesJSONIndent?;
2960
+ private resolvedPagesJSONNewline?;
2961
+ private resolvedPagesJSONEofNewline?;
2961
2962
  rawOptions: UserOptions;
2962
2963
  root: string;
2963
2964
  options: ResolvedOptions;
2964
2965
  logger?: Logger;
2965
2966
  withUniPlatform: boolean;
2967
+ private lastPagesJson;
2966
2968
  constructor(userOptions: UserOptions, viteRoot?: string);
2967
2969
  setLogger(logger: Logger): void;
2968
2970
  loadUserPagesConfig(): Promise<void>;
@@ -2993,6 +2995,12 @@ declare class PageContext {
2993
2995
  resolveRoutes(): string;
2994
2996
  resolveSubRoutes(): string;
2995
2997
  generateDeclaration(): Promise<void> | undefined;
2998
+ private writePagesJSONFile;
2999
+ private genratePagesJSON;
3000
+ private readInfoFromPagesJSON;
3001
+ private getIndent;
3002
+ private getNewline;
3003
+ private getEndOfLine;
2996
3004
  }
2997
3005
 
2998
3006
  declare function invalidatePagesModule(server: ViteDevServer): void;
@@ -3029,6 +3037,7 @@ declare function execScript(options: {
3029
3037
  code: string;
3030
3038
  filename: string;
3031
3039
  }): Promise<any>;
3040
+ declare function sleep(ms: number): Promise<unknown>;
3032
3041
  declare const babelGenerate: typeof babelGenerator;
3033
3042
 
3034
3043
  interface CustomBlock {
@@ -3189,9 +3198,13 @@ declare function getRouteBlock(path: string, blockStr: SFCBlock | undefined, rou
3189
3198
  * Resolves the files that are valid pages for the given context.
3190
3199
  */
3191
3200
  declare function getPageFiles(path: string, options: ResolvedOptions): string[];
3192
- declare function checkPagesJsonFile(path: string): boolean;
3193
- declare function readFileSync(path: string): string;
3194
- declare function writeFileSync(path: string, content: string): void;
3201
+ /**
3202
+ * 检查指定路径的 pages.json 文件,如果文件不存在或不是有效文件则创建一个空的 pages.json 文件
3203
+ * @param path - 要检查的文件路径
3204
+ * @returns boolean - 返回操作是否成功
3205
+ */
3206
+ declare function checkPagesJsonFileSync(path: fs.PathLike): boolean;
3207
+ declare function writeFileWithLock(path: string, content: string, retry?: number): Promise<void>;
3195
3208
 
3196
3209
  declare function resolveOptions(userOptions: UserOptions, viteRoot?: string): ResolvedOptions;
3197
3210
  /**
@@ -3201,5 +3214,5 @@ declare function resolvePageDirs(dir: string, root: string, exclude: string[]):
3201
3214
 
3202
3215
  declare function VitePluginUniPages(userOptions?: UserOptions): Plugin;
3203
3216
 
3204
- export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFile, debug, VitePluginUniPages as default, definePage, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, readFileSync, resolveOptions, resolvePageDirs, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileSync };
3217
+ export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFileSync, debug, VitePluginUniPages as default, definePage, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, sleep, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileWithLock };
3205
3218
  export type { Condition, ConditionItem, ConfigSource, CustomBlock, DefinePage, EasyCom, GlobalStyle, MaybeCallable, MaybePromise, MaybePromiseCallable, Options, PageMetaDatum, PagePath, PagesConfig, ResolvedOptions, RouteBlockLang, SubPackage, SubPackages, SubPageMetaDatum, TabBar, TabBarIconFont, TabBarItem, TabBarMidButton, TheWindow, UniIdRouter, UserOptions, UserPageMeta, UserPagesConfig, UserTabBarItem, debugType };
package/dist/index.d.mts CHANGED
@@ -6,6 +6,7 @@ import { SFCParseOptions, SFCDescriptor, SFCBlock } from '@vue/compiler-sfc';
6
6
  import * as t from '@babel/types';
7
7
  import babelGenerator from '@babel/generator';
8
8
  import Debug from 'debug';
9
+ import fs from 'node:fs';
9
10
 
10
11
  interface ConditionItem {
11
12
  /**
@@ -2955,14 +2956,15 @@ declare class PageContext {
2955
2956
  pageMetaData: PageMetaDatum[];
2956
2957
  subPageMetaData: SubPageMetaDatum[];
2957
2958
  resolvedPagesJSONPath: string;
2958
- resolvedPagesJSONIndent: string;
2959
- resolvedPagesJSONNewline: string;
2960
- resolvedPagesJSONEofNewline: boolean;
2959
+ private resolvedPagesJSONIndent?;
2960
+ private resolvedPagesJSONNewline?;
2961
+ private resolvedPagesJSONEofNewline?;
2961
2962
  rawOptions: UserOptions;
2962
2963
  root: string;
2963
2964
  options: ResolvedOptions;
2964
2965
  logger?: Logger;
2965
2966
  withUniPlatform: boolean;
2967
+ private lastPagesJson;
2966
2968
  constructor(userOptions: UserOptions, viteRoot?: string);
2967
2969
  setLogger(logger: Logger): void;
2968
2970
  loadUserPagesConfig(): Promise<void>;
@@ -2993,6 +2995,12 @@ declare class PageContext {
2993
2995
  resolveRoutes(): string;
2994
2996
  resolveSubRoutes(): string;
2995
2997
  generateDeclaration(): Promise<void> | undefined;
2998
+ private writePagesJSONFile;
2999
+ private genratePagesJSON;
3000
+ private readInfoFromPagesJSON;
3001
+ private getIndent;
3002
+ private getNewline;
3003
+ private getEndOfLine;
2996
3004
  }
2997
3005
 
2998
3006
  declare function invalidatePagesModule(server: ViteDevServer): void;
@@ -3029,6 +3037,7 @@ declare function execScript(options: {
3029
3037
  code: string;
3030
3038
  filename: string;
3031
3039
  }): Promise<any>;
3040
+ declare function sleep(ms: number): Promise<unknown>;
3032
3041
  declare const babelGenerate: typeof babelGenerator;
3033
3042
 
3034
3043
  interface CustomBlock {
@@ -3189,9 +3198,13 @@ declare function getRouteBlock(path: string, blockStr: SFCBlock | undefined, rou
3189
3198
  * Resolves the files that are valid pages for the given context.
3190
3199
  */
3191
3200
  declare function getPageFiles(path: string, options: ResolvedOptions): string[];
3192
- declare function checkPagesJsonFile(path: string): boolean;
3193
- declare function readFileSync(path: string): string;
3194
- declare function writeFileSync(path: string, content: string): void;
3201
+ /**
3202
+ * 检查指定路径的 pages.json 文件,如果文件不存在或不是有效文件则创建一个空的 pages.json 文件
3203
+ * @param path - 要检查的文件路径
3204
+ * @returns boolean - 返回操作是否成功
3205
+ */
3206
+ declare function checkPagesJsonFileSync(path: fs.PathLike): boolean;
3207
+ declare function writeFileWithLock(path: string, content: string, retry?: number): Promise<void>;
3195
3208
 
3196
3209
  declare function resolveOptions(userOptions: UserOptions, viteRoot?: string): ResolvedOptions;
3197
3210
  /**
@@ -3201,5 +3214,5 @@ declare function resolvePageDirs(dir: string, root: string, exclude: string[]):
3201
3214
 
3202
3215
  declare function VitePluginUniPages(userOptions?: UserOptions): Plugin;
3203
3216
 
3204
- export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFile, debug, VitePluginUniPages as default, definePage, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, readFileSync, resolveOptions, resolvePageDirs, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileSync };
3217
+ export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFileSync, debug, VitePluginUniPages as default, definePage, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, sleep, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileWithLock };
3205
3218
  export type { Condition, ConditionItem, ConfigSource, CustomBlock, DefinePage, EasyCom, GlobalStyle, MaybeCallable, MaybePromise, MaybePromiseCallable, Options, PageMetaDatum, PagePath, PagesConfig, ResolvedOptions, RouteBlockLang, SubPackage, SubPackages, SubPageMetaDatum, TabBar, TabBarIconFont, TabBarItem, TabBarMidButton, TheWindow, UniIdRouter, UserOptions, UserPageMeta, UserPagesConfig, UserTabBarItem, debugType };
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ import { SFCParseOptions, SFCDescriptor, SFCBlock } from '@vue/compiler-sfc';
6
6
  import * as t from '@babel/types';
7
7
  import babelGenerator from '@babel/generator';
8
8
  import Debug from 'debug';
9
+ import fs from 'node:fs';
9
10
 
10
11
  interface ConditionItem {
11
12
  /**
@@ -2955,14 +2956,15 @@ declare class PageContext {
2955
2956
  pageMetaData: PageMetaDatum[];
2956
2957
  subPageMetaData: SubPageMetaDatum[];
2957
2958
  resolvedPagesJSONPath: string;
2958
- resolvedPagesJSONIndent: string;
2959
- resolvedPagesJSONNewline: string;
2960
- resolvedPagesJSONEofNewline: boolean;
2959
+ private resolvedPagesJSONIndent?;
2960
+ private resolvedPagesJSONNewline?;
2961
+ private resolvedPagesJSONEofNewline?;
2961
2962
  rawOptions: UserOptions;
2962
2963
  root: string;
2963
2964
  options: ResolvedOptions;
2964
2965
  logger?: Logger;
2965
2966
  withUniPlatform: boolean;
2967
+ private lastPagesJson;
2966
2968
  constructor(userOptions: UserOptions, viteRoot?: string);
2967
2969
  setLogger(logger: Logger): void;
2968
2970
  loadUserPagesConfig(): Promise<void>;
@@ -2993,6 +2995,12 @@ declare class PageContext {
2993
2995
  resolveRoutes(): string;
2994
2996
  resolveSubRoutes(): string;
2995
2997
  generateDeclaration(): Promise<void> | undefined;
2998
+ private writePagesJSONFile;
2999
+ private genratePagesJSON;
3000
+ private readInfoFromPagesJSON;
3001
+ private getIndent;
3002
+ private getNewline;
3003
+ private getEndOfLine;
2996
3004
  }
2997
3005
 
2998
3006
  declare function invalidatePagesModule(server: ViteDevServer): void;
@@ -3029,6 +3037,7 @@ declare function execScript(options: {
3029
3037
  code: string;
3030
3038
  filename: string;
3031
3039
  }): Promise<any>;
3040
+ declare function sleep(ms: number): Promise<unknown>;
3032
3041
  declare const babelGenerate: typeof babelGenerator;
3033
3042
 
3034
3043
  interface CustomBlock {
@@ -3189,9 +3198,13 @@ declare function getRouteBlock(path: string, blockStr: SFCBlock | undefined, rou
3189
3198
  * Resolves the files that are valid pages for the given context.
3190
3199
  */
3191
3200
  declare function getPageFiles(path: string, options: ResolvedOptions): string[];
3192
- declare function checkPagesJsonFile(path: string): boolean;
3193
- declare function readFileSync(path: string): string;
3194
- declare function writeFileSync(path: string, content: string): void;
3201
+ /**
3202
+ * 检查指定路径的 pages.json 文件,如果文件不存在或不是有效文件则创建一个空的 pages.json 文件
3203
+ * @param path - 要检查的文件路径
3204
+ * @returns boolean - 返回操作是否成功
3205
+ */
3206
+ declare function checkPagesJsonFileSync(path: fs.PathLike): boolean;
3207
+ declare function writeFileWithLock(path: string, content: string, retry?: number): Promise<void>;
3195
3208
 
3196
3209
  declare function resolveOptions(userOptions: UserOptions, viteRoot?: string): ResolvedOptions;
3197
3210
  /**
@@ -3201,5 +3214,5 @@ declare function resolvePageDirs(dir: string, root: string, exclude: string[]):
3201
3214
 
3202
3215
  declare function VitePluginUniPages(userOptions?: UserOptions): Plugin;
3203
3216
 
3204
- export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFile, debug, VitePluginUniPages as default, definePage, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, readFileSync, resolveOptions, resolvePageDirs, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileSync };
3217
+ export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFileSync, debug, VitePluginUniPages as default, definePage, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, sleep, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileWithLock };
3205
3218
  export type { Condition, ConditionItem, ConfigSource, CustomBlock, DefinePage, EasyCom, GlobalStyle, MaybeCallable, MaybePromise, MaybePromiseCallable, Options, PageMetaDatum, PagePath, PagesConfig, ResolvedOptions, RouteBlockLang, SubPackage, SubPackages, SubPageMetaDatum, TabBar, TabBarIconFont, TabBarItem, TabBarMidButton, TheWindow, UniIdRouter, UserOptions, UserPageMeta, UserPagesConfig, UserTabBarItem, debugType };
package/dist/index.mjs CHANGED
@@ -1,4 +1,3 @@
1
- import { spawn } from 'node:child_process';
2
1
  import path, { join, dirname, resolve, extname } from 'node:path';
3
2
  import process from 'node:process';
4
3
  import { babelParse, isCallOf } from 'ast-kit';
@@ -6,13 +5,14 @@ import chokidar from 'chokidar';
6
5
  import { lightYellow, bold, link, dim } from 'kolorist';
7
6
  import MagicString from 'magic-string';
8
7
  import { normalizePath, createLogger } from 'vite';
8
+ import fs, { existsSync } from 'node:fs';
9
9
  import { platform } from '@uni-helper/uni-env';
10
- import { stringify, parse, assign } from 'comment-json';
10
+ import { parse, assign, stringify, CommentArray } from 'comment-json';
11
11
  import Debug from 'debug';
12
12
  import detectIndent from 'detect-indent';
13
13
  import detectNewline from 'detect-newline';
14
+ import lockfile from 'proper-lockfile';
14
15
  import { loadConfig } from 'unconfig';
15
- import fs, { existsSync, readFileSync as readFileSync$1 } from 'node:fs';
16
16
  import { readFile, mkdir, writeFile as writeFile$1 } from 'node:fs/promises';
17
17
  import fg from 'fast-glob';
18
18
  import { createRequire } from 'node:module';
@@ -200,6 +200,9 @@ ${jsCode}
200
200
  `);
201
201
  }
202
202
  }
203
+ function sleep(ms) {
204
+ return new Promise((resolve) => setTimeout(resolve, ms));
205
+ }
203
206
  function getDefaultExport(expr) {
204
207
  return expr.default === void 0 ? expr : expr.default;
205
208
  }
@@ -215,22 +218,72 @@ function getPageFiles(path, options) {
215
218
  });
216
219
  return files;
217
220
  }
218
- function checkPagesJsonFile(path) {
219
- if (!fs.existsSync(path)) {
220
- writeFileSync(path, stringify({ pages: [{ path: "" }] }, null, 2));
221
- return false;
222
- }
223
- return true;
224
- }
225
- function readFileSync(path) {
221
+ function checkPagesJsonFileSync(path) {
222
+ const createEmptyFile = (path2) => {
223
+ try {
224
+ fs.writeFileSync(
225
+ path2,
226
+ JSON.stringify({ pages: [{ path: "" }] }, null, 2),
227
+ { encoding: "utf-8" }
228
+ );
229
+ return true;
230
+ } catch {
231
+ return false;
232
+ }
233
+ };
234
+ const unlinkFile = (path2) => {
235
+ try {
236
+ fs.unlinkSync(path2);
237
+ return true;
238
+ } catch {
239
+ return false;
240
+ }
241
+ };
226
242
  try {
227
- return fs.readFileSync(path, { encoding: "utf-8" });
243
+ try {
244
+ fs.accessSync(path, fs.constants.F_OK);
245
+ } catch {
246
+ return createEmptyFile(path);
247
+ }
248
+ const stat = fs.statSync(path);
249
+ if (!stat.isFile()) {
250
+ if (!unlinkFile(path)) {
251
+ return false;
252
+ }
253
+ return createEmptyFile(path);
254
+ }
255
+ try {
256
+ fs.accessSync(path, fs.constants.R_OK | fs.constants.W_OK);
257
+ return true;
258
+ } catch {
259
+ if (!unlinkFile(path)) {
260
+ return false;
261
+ }
262
+ return createEmptyFile(path);
263
+ }
228
264
  } catch {
229
- return "";
265
+ return createEmptyFile(path);
230
266
  }
231
267
  }
232
- function writeFileSync(path, content) {
233
- fs.writeFileSync(path, content, { encoding: "utf-8" });
268
+ async function writeFileWithLock(path, content, retry = 3) {
269
+ if (retry <= 0) {
270
+ debug.error(`${path} \u83B7\u53D6\u6587\u4EF6\u9501\u5931\u8D25\uFF0C\u5199\u5165\u5931\u8D25`);
271
+ return;
272
+ }
273
+ let relase;
274
+ try {
275
+ try {
276
+ relase = await lockfile.lock(path, { realpath: false });
277
+ } catch {
278
+ await sleep(500);
279
+ return writeFileWithLock(path, content, retry - 1);
280
+ }
281
+ await fs.promises.writeFile(path, content, { encoding: "utf-8" });
282
+ } finally {
283
+ if (relase) {
284
+ await relase();
285
+ }
286
+ }
234
287
  }
235
288
 
236
289
  function resolveOptions(userOptions, viteRoot = process.cwd()) {
@@ -427,7 +480,7 @@ class Page {
427
480
  }
428
481
  async readPageMetaFromFile() {
429
482
  try {
430
- const content = readFileSync$1(this.path.absolutePath, "utf-8");
483
+ const content = await fs.promises.readFile(this.path.absolutePath, { encoding: "utf-8" });
431
484
  const sfc = parseSFC(content, { filename: this.path.absolutePath });
432
485
  const meta = await tryPageMetaFromMacro(sfc);
433
486
  if (meta) {
@@ -524,7 +577,6 @@ var __publicField = (obj, key, value) => {
524
577
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
525
578
  return value;
526
579
  };
527
- let lsatPagesJson = "";
528
580
  class PageContext {
529
581
  constructor(userOptions, viteRoot = process.cwd()) {
530
582
  __publicField(this, "_server");
@@ -537,14 +589,18 @@ class PageContext {
537
589
  __publicField(this, "pageMetaData", []);
538
590
  __publicField(this, "subPageMetaData", []);
539
591
  __publicField(this, "resolvedPagesJSONPath", "");
540
- __publicField(this, "resolvedPagesJSONIndent", " ");
541
- __publicField(this, "resolvedPagesJSONNewline", "\n");
542
- __publicField(this, "resolvedPagesJSONEofNewline", true);
592
+ __publicField(this, "resolvedPagesJSONIndent");
593
+ // ' '
594
+ __publicField(this, "resolvedPagesJSONNewline");
595
+ // '\n'
596
+ __publicField(this, "resolvedPagesJSONEofNewline");
597
+ // true
543
598
  __publicField(this, "rawOptions");
544
599
  __publicField(this, "root");
545
600
  __publicField(this, "options");
546
601
  __publicField(this, "logger");
547
602
  __publicField(this, "withUniPlatform", false);
603
+ __publicField(this, "lastPagesJson", "");
548
604
  this.rawOptions = userOptions;
549
605
  this.root = slash(viteRoot);
550
606
  debug.options("root", this.root);
@@ -556,10 +612,6 @@ class PageContext {
556
612
  Debug.enable(`${prefix}${suffix}`);
557
613
  }
558
614
  this.resolvedPagesJSONPath = path.join(this.root, this.options.outDir, OUTPUT_NAME);
559
- const resolvedPagesJSONContent = readFileSync(this.resolvedPagesJSONPath);
560
- this.resolvedPagesJSONIndent = detectIndent(resolvedPagesJSONContent).indent || " ";
561
- this.resolvedPagesJSONNewline = detectNewline(resolvedPagesJSONContent) || "\n";
562
- this.resolvedPagesJSONEofNewline = (resolvedPagesJSONContent.at(-1) ?? "\n") === this.resolvedPagesJSONNewline;
563
615
  debug.options(this.options);
564
616
  }
565
617
  setLogger(logger) {
@@ -775,7 +827,7 @@ class PageContext {
775
827
  }
776
828
  }
777
829
  }
778
- checkPagesJsonFile(this.resolvedPagesJSONPath);
830
+ checkPagesJsonFileSync(this.resolvedPagesJSONPath);
779
831
  this.options.onBeforeLoadUserConfig(this);
780
832
  await this.loadUserPagesConfig();
781
833
  this.options.onAfterLoadUserConfig(this);
@@ -797,24 +849,19 @@ class PageContext {
797
849
  pages.forEach((v) => pagesMap.set(v.path, v));
798
850
  this.pageMetaData = [...pagesMap.values()];
799
851
  this.options.onBeforeWriteFile(this);
800
- const data = {
801
- ...this.pagesGlobConfig,
802
- pages: this.pageMetaData,
803
- subPackages: this.subPageMetaData,
804
- tabBar: await this.getTabBarMerged()
805
- };
852
+ const data = await this.genratePagesJSON();
806
853
  const pagesJson = stringify(
807
854
  data,
808
855
  null,
809
- this.options.minify ? void 0 : this.resolvedPagesJSONIndent
810
- ) + (this.resolvedPagesJSONEofNewline ? this.resolvedPagesJSONNewline : "");
856
+ this.options.minify ? void 0 : await this.getIndent()
857
+ ) + (await this.getEndOfLine() ? await this.getNewline() : "");
811
858
  this.generateDeclaration();
812
- if (lsatPagesJson === pagesJson) {
859
+ if (this.lastPagesJson === pagesJson) {
813
860
  debug.pages("PagesJson Not have change");
814
861
  return false;
815
862
  }
816
- writeFileSync(this.resolvedPagesJSONPath, pagesJson);
817
- lsatPagesJson = pagesJson;
863
+ await writeFileWithLock(this.resolvedPagesJSONPath, pagesJson);
864
+ this.lastPagesJson = pagesJson;
818
865
  this.options.onAfterWriteFile(this);
819
866
  return true;
820
867
  }
@@ -835,6 +882,88 @@ class PageContext {
835
882
  debug.declaration("generating");
836
883
  return writeDeclaration(this, this.options.dts);
837
884
  }
885
+ async writePagesJSONFile(pagesJson, retry = 3) {
886
+ if (retry <= 0) {
887
+ debug.error(`${this.resolvedPagesJSONPath} \u83B7\u53D6\u6587\u4EF6\u9501\u5931\u8D25\uFF0C\u5199\u5165\u5931\u8D25`);
888
+ return;
889
+ }
890
+ let relase;
891
+ try {
892
+ try {
893
+ relase = await lockfile.lock(this.resolvedPagesJSONPath, { realpath: false });
894
+ } catch {
895
+ return this.writePagesJSONFile(pagesJson, retry - 1);
896
+ }
897
+ await fs.promises.writeFile(this.resolvedPagesJSONPath, pagesJson, { encoding: "utf-8" });
898
+ } finally {
899
+ if (relase) {
900
+ await relase();
901
+ }
902
+ }
903
+ }
904
+ async genratePagesJSON() {
905
+ const content = await fs.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
906
+ let pageJson = parse(content || "{}");
907
+ const { pages: _, subPackages: __, tabBar: ___, ...others } = this.pagesGlobConfig || {};
908
+ pageJson = Object.assign(pageJson, {
909
+ ...others
910
+ });
911
+ const currentPlatform = platform.toUpperCase();
912
+ pageJson.pages = mergePlatformItems(pageJson?.pages, currentPlatform, this.pageMetaData, "path");
913
+ pageJson.subPackages = pageJson?.subPackages || new CommentArray();
914
+ const newSubPackages = /* @__PURE__ */ new Map();
915
+ for (const item of this.subPageMetaData) {
916
+ newSubPackages.set(item.root, item);
917
+ }
918
+ for (const existing of pageJson.subPackages) {
919
+ const sub = newSubPackages.get(existing.root);
920
+ if (sub) {
921
+ existing.pages = mergePlatformItems(existing.pages, currentPlatform, sub.pages, "path");
922
+ newSubPackages.delete(existing.root);
923
+ }
924
+ }
925
+ for (const [_2, newSub] of newSubPackages) {
926
+ pageJson.subPackages.push({
927
+ root: newSub.root,
928
+ pages: mergePlatformItems(void 0, currentPlatform, newSub.pages, "path")
929
+ });
930
+ }
931
+ const tabBar = await this.getTabBarMerged();
932
+ if (tabBar) {
933
+ const list = mergePlatformItems(pageJson?.tabBar?.list, currentPlatform, tabBar.list, "pagePath");
934
+ if (pageJson?.tabBar?.list) {
935
+ pageJson.tabBar.list = list;
936
+ } else {
937
+ pageJson.tabBar = pageJson.tabBar || {};
938
+ pageJson.tabBar.list = list;
939
+ }
940
+ }
941
+ return pageJson;
942
+ }
943
+ async readInfoFromPagesJSON() {
944
+ const resolvedPagesJSONContent = await fs.promises.readFile(this.resolvedPagesJSONPath, { encoding: "utf-8" }).catch(() => "");
945
+ this.resolvedPagesJSONIndent = detectIndent(resolvedPagesJSONContent).indent || " ";
946
+ this.resolvedPagesJSONNewline = detectNewline(resolvedPagesJSONContent) || "\n";
947
+ this.resolvedPagesJSONEofNewline = (resolvedPagesJSONContent.at(-1) ?? "\n") === this.resolvedPagesJSONNewline;
948
+ }
949
+ async getIndent() {
950
+ if (!this.resolvedPagesJSONIndent) {
951
+ await this.readInfoFromPagesJSON();
952
+ }
953
+ return this.resolvedPagesJSONIndent;
954
+ }
955
+ async getNewline() {
956
+ if (!this.resolvedPagesJSONNewline) {
957
+ await this.readInfoFromPagesJSON();
958
+ }
959
+ return this.resolvedPagesJSONNewline;
960
+ }
961
+ async getEndOfLine() {
962
+ if (!this.resolvedPagesJSONEofNewline) {
963
+ await this.readInfoFromPagesJSON();
964
+ }
965
+ return this.resolvedPagesJSONEofNewline;
966
+ }
838
967
  }
839
968
  function getPagePaths(dir, options) {
840
969
  const pagesDirPath = slash(path.resolve(options.root, dir));
@@ -847,25 +976,117 @@ function getPagePaths(dir, options) {
847
976
  }));
848
977
  return pagePaths;
849
978
  }
979
+ function mergePlatformItems(source, currentPlatform, items, uniqueKeyName) {
980
+ const src = source || new CommentArray();
981
+ currentPlatform = currentPlatform.toUpperCase();
982
+ let lastPlatforms = [];
983
+ for (const comment of src[Symbol.for("before:0")] || []) {
984
+ const trimed = comment.value.trim();
985
+ if (trimed.startsWith("GENERATED BY UNI-PAGES, PLATFORM:")) {
986
+ lastPlatforms = trimed.split(":")[1].split("||").map((s) => s.trim()).filter((s) => s !== currentPlatform).sort();
987
+ }
988
+ }
989
+ const tmpMap = /* @__PURE__ */ new Map();
990
+ for (let i = 0; i < src.length; i++) {
991
+ const item = src[i];
992
+ const uniqueKey = item[uniqueKeyName];
993
+ if (!uniqueKey) {
994
+ continue;
995
+ }
996
+ const beforeComments = src[Symbol.for(`before:${i}`)];
997
+ const ifdefComment = beforeComments?.find((c) => c.value.trim().startsWith("#ifdef"));
998
+ let platforms = [...lastPlatforms];
999
+ if (ifdefComment) {
1000
+ const match = ifdefComment.value.match(/#ifdef\s+(.+)/);
1001
+ if (match) {
1002
+ platforms = match[1].split("||").map((p) => p.trim()).filter((s) => s !== currentPlatform).sort();
1003
+ }
1004
+ }
1005
+ if (platforms.length === 0) {
1006
+ continue;
1007
+ }
1008
+ const existing = tmpMap.get(uniqueKey) || [];
1009
+ existing.push({ item, platforms, platformStr: platforms.join(" || ") });
1010
+ tmpMap.set(uniqueKey, existing);
1011
+ }
1012
+ for (const item of items) {
1013
+ const newItem = item;
1014
+ const uniqueKey = item[uniqueKeyName];
1015
+ if (!uniqueKey) {
1016
+ continue;
1017
+ }
1018
+ if (!tmpMap.has(uniqueKey)) {
1019
+ tmpMap.set(uniqueKey, [{
1020
+ item: newItem,
1021
+ platforms: [currentPlatform],
1022
+ platformStr: currentPlatform
1023
+ }]);
1024
+ continue;
1025
+ }
1026
+ const existing = tmpMap.get(uniqueKey);
1027
+ const newItemStr = JSON.stringify(newItem);
1028
+ const equalObj = existing.find((val) => JSON.stringify(val.item) === newItemStr);
1029
+ if (equalObj) {
1030
+ equalObj.platforms.push(currentPlatform);
1031
+ equalObj.platformStr = equalObj.platforms.join(" || ");
1032
+ } else {
1033
+ existing.push({
1034
+ item: newItem,
1035
+ platforms: [currentPlatform],
1036
+ platformStr: currentPlatform
1037
+ });
1038
+ }
1039
+ }
1040
+ const result = new CommentArray();
1041
+ const platformUsage = {};
1042
+ tmpMap.forEach((val) => {
1043
+ Object.values(val).forEach((v) => {
1044
+ platformUsage[v.platformStr] = (platformUsage[v.platformStr] || 0) + 1;
1045
+ });
1046
+ });
1047
+ const usageKeys = Object.keys(platformUsage);
1048
+ const defaultPlatformStr = usageKeys.length ? usageKeys.reduce((a, b) => platformUsage[a] > platformUsage[b] ? a : b) : currentPlatform;
1049
+ result[Symbol.for("before:0")] = [{
1050
+ type: "LineComment",
1051
+ value: ` GENERATED BY UNI-PAGES, PLATFORM: ${defaultPlatformStr}`,
1052
+ inline: false,
1053
+ loc: {
1054
+ start: { line: 0, column: 0 },
1055
+ end: { line: 0, column: 0 }
1056
+ }
1057
+ }];
1058
+ for (const [_, list] of tmpMap) {
1059
+ for (const { item, platformStr } of list) {
1060
+ result.push(item);
1061
+ if (platformStr !== defaultPlatformStr) {
1062
+ result[Symbol.for(`before:${result.length - 1}`)] = [{
1063
+ type: "LineComment",
1064
+ value: ` #ifdef ${platformStr}`,
1065
+ inline: false,
1066
+ loc: {
1067
+ start: { line: 0, column: 0 },
1068
+ end: { line: 0, column: 0 }
1069
+ }
1070
+ }];
1071
+ result[Symbol.for(`after:${result.length - 1}`)] = [{
1072
+ type: "LineComment",
1073
+ value: " #endif",
1074
+ inline: false,
1075
+ loc: {
1076
+ start: { line: 0, column: 0 },
1077
+ end: { line: 0, column: 0 }
1078
+ }
1079
+ }];
1080
+ }
1081
+ }
1082
+ }
1083
+ return result;
1084
+ }
850
1085
 
851
1086
  function defineUniPages(config) {
852
1087
  return config;
853
1088
  }
854
1089
 
855
- async function restart() {
856
- return new Promise((resolve) => {
857
- const build = spawn(process.argv.shift(), process.argv, {
858
- cwd: process.env.VITE_ROOT_DIR || process.cwd(),
859
- detached: true,
860
- env: process.env
861
- });
862
- build.stdout?.pipe(process.stdout);
863
- build.stderr?.pipe(process.stderr);
864
- build.on("close", (code) => {
865
- resolve(process.exit(code));
866
- });
867
- });
868
- }
869
1090
  function VitePluginUniPages(userOptions = {}) {
870
1091
  let ctx;
871
1092
  const resolvedPagesJSONPath = path.join(
@@ -873,7 +1094,7 @@ function VitePluginUniPages(userOptions = {}) {
873
1094
  userOptions.outDir ?? "src",
874
1095
  OUTPUT_NAME
875
1096
  );
876
- const isValidated = checkPagesJsonFile(resolvedPagesJSONPath);
1097
+ checkPagesJsonFileSync(resolvedPagesJSONPath);
877
1098
  return {
878
1099
  name: "vite-plugin-uni-pages",
879
1100
  enforce: "pre",
@@ -887,12 +1108,6 @@ function VitePluginUniPages(userOptions = {}) {
887
1108
  ctx.setLogger(logger);
888
1109
  await ctx.updatePagesJSON();
889
1110
  if (config.command === "build") {
890
- if (!isValidated) {
891
- ctx.logger?.warn("In build mode, if `pages.json` does not exist, the plugin cannot create the complete `pages.json` before the uni-app, so it restarts the build.", {
892
- timestamp: true
893
- });
894
- await restart();
895
- }
896
1111
  if (config.build.watch)
897
1112
  ctx.setupWatcher(chokidar.watch([...ctx.options.dirs, ...ctx.options.subPackages]));
898
1113
  }
@@ -958,4 +1173,4 @@ function VitePluginUniPages(userOptions = {}) {
958
1173
  };
959
1174
  }
960
1175
 
961
- export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFile, debug, VitePluginUniPages as default, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, readFileSync, resolveOptions, resolvePageDirs, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileSync };
1176
+ export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, Page, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, babelGenerate, checkPagesJsonFileSync, debug, VitePluginUniPages as default, defineUniPages, execScript, extsToGlob, findImports, findMacro, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, sleep, tryPageMetaFromCustomBlock, tryPageMetaFromMacro, writeFileWithLock };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@uni-helper/vite-plugin-uni-pages",
3
3
  "type": "module",
4
- "version": "0.3.15",
4
+ "version": "0.3.17",
5
5
  "description": "File system based routing for uni-app applications using Vite",
6
6
  "author": "KeJun",
7
7
  "maintainers": [
@@ -53,6 +53,7 @@
53
53
  "dependencies": {
54
54
  "@babel/generator": "^7.28.3",
55
55
  "@babel/types": "^7.28.2",
56
+ "@types/proper-lockfile": "^4.1.4",
56
57
  "@uni-helper/uni-env": "^0.1.4",
57
58
  "@vue/compiler-sfc": "3.4.21",
58
59
  "ast-kit": "1.4.3",
@@ -66,6 +67,7 @@
66
67
  "kolorist": "^1.8.0",
67
68
  "lodash.groupby": "^4.6.0",
68
69
  "magic-string": "^0.30.11",
70
+ "proper-lockfile": "^4.1.2",
69
71
  "typescript": "5.9.2",
70
72
  "unconfig": "^7.3.2",
71
73
  "yaml": "^2.5.0"