@uni-helper/vite-plugin-uni-pages 0.2.3 → 0.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -7,6 +7,7 @@ const node_child_process = require('node:child_process');
7
7
  const vite = require('vite');
8
8
  const MagicString = require('magic-string');
9
9
  const chokidar = require('chokidar');
10
+ const process$1 = require('node:process');
10
11
  const unconfig = require('unconfig');
11
12
  const uniEnv = require('@uni-helper/uni-env');
12
13
  const Debug = require('debug');
@@ -22,6 +23,7 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
22
23
  const path__default = /*#__PURE__*/_interopDefaultCompat(path);
23
24
  const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
24
25
  const chokidar__default = /*#__PURE__*/_interopDefaultCompat(chokidar);
26
+ const process__default = /*#__PURE__*/_interopDefaultCompat(process$1);
25
27
  const Debug__default = /*#__PURE__*/_interopDefaultCompat(Debug);
26
28
  const fg__default = /*#__PURE__*/_interopDefaultCompat(fg);
27
29
  const fs__default = /*#__PURE__*/_interopDefaultCompat(fs);
@@ -36,6 +38,72 @@ const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}`;
36
38
  const OUTPUT_NAME = "pages.json";
37
39
  const FILE_EXTENSIONS = ["vue", "nvue", "uvue"];
38
40
 
41
+ async function parseSFC(code) {
42
+ try {
43
+ return compilerSfc.parse(code, {
44
+ pad: "space"
45
+ }).descriptor || compilerSfc.parse({
46
+ source: code
47
+ });
48
+ } catch {
49
+ throw new Error(
50
+ `[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required.`
51
+ );
52
+ }
53
+ }
54
+ function parseCustomBlock(block, filePath, options) {
55
+ const lang = block.lang ?? options.routeBlockLang;
56
+ const attr = {
57
+ type: "page",
58
+ ...block.attrs
59
+ };
60
+ let content;
61
+ debug.routeBlock(`use ${lang} parser`);
62
+ if (lang === "json5" || lang === "jsonc") {
63
+ try {
64
+ content = JSON5__default.parse(block.content);
65
+ } catch (err) {
66
+ throw new Error(
67
+ `Invalid JSON5 format of <${block.type}> content in ${filePath}
68
+ ${err.message}`
69
+ );
70
+ }
71
+ } else if (lang === "json") {
72
+ try {
73
+ content = JSON.parse(block.content);
74
+ } catch (err) {
75
+ throw new Error(
76
+ `Invalid JSON format of <${block.type}> content in ${filePath}
77
+ ${err.message}`
78
+ );
79
+ }
80
+ } else if (lang === "yaml" || lang === "yml") {
81
+ try {
82
+ content = yaml.parse(block.content);
83
+ } catch (err) {
84
+ throw new Error(
85
+ `Invalid YAML format of <${block.type}> content in ${filePath}
86
+ ${err.message}`
87
+ );
88
+ }
89
+ }
90
+ return {
91
+ attr,
92
+ content: content ?? {}
93
+ };
94
+ }
95
+ async function getRouteSfcBlock(path) {
96
+ const content = fs__default.readFileSync(path, "utf8");
97
+ const parsedSFC = await parseSFC(content);
98
+ const blockStr = parsedSFC?.customBlocks.find((b) => b.type === "route");
99
+ return blockStr;
100
+ }
101
+ async function getRouteBlock(path, blockStr, options) {
102
+ if (!blockStr)
103
+ return;
104
+ return parseCustomBlock(blockStr, path, options);
105
+ }
106
+
39
107
  function invalidatePagesModule(server) {
40
108
  const { moduleGraph } = server;
41
109
  const mods = moduleGraph.getModulesByFile(RESOLVED_MODULE_ID_VIRTUAL);
@@ -52,7 +120,8 @@ const debug = {
52
120
  options: Debug__default("vite-plugin-uni-pages:options"),
53
121
  pages: Debug__default("vite-plugin-uni-pages:pages"),
54
122
  subPages: Debug__default("vite-plugin-uni-pages:subPages"),
55
- error: Debug__default("vite-plugin-uni-pages:error")
123
+ error: Debug__default("vite-plugin-uni-pages:error"),
124
+ cache: Debug__default("vite-plugin-uni-pages:cache")
56
125
  };
57
126
  function extsToGlob(extensions) {
58
127
  return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
@@ -85,6 +154,27 @@ async function getPagesConfigSourcePaths() {
85
154
  absolute: true
86
155
  });
87
156
  }
157
+ function useCachedPages() {
158
+ const pages = /* @__PURE__ */ new Map();
159
+ function parseData(block) {
160
+ return {
161
+ content: block?.loc.source.trim() ?? "",
162
+ attr: block?.attrs ?? ""
163
+ };
164
+ }
165
+ function setCache(filePath, routeBlock) {
166
+ pages.set(filePath, JSON.stringify(parseData(routeBlock)));
167
+ }
168
+ async function hasChanged(filePath, routeBlock) {
169
+ if (!routeBlock)
170
+ routeBlock = await getRouteSfcBlock(vite.normalizePath(filePath));
171
+ return !pages.has(filePath) || JSON.stringify(parseData(routeBlock)) !== pages.get(filePath);
172
+ }
173
+ return {
174
+ setCache,
175
+ hasChanged
176
+ };
177
+ }
88
178
 
89
179
  function resolveOptions(userOptions, viteRoot) {
90
180
  const {
@@ -114,7 +204,7 @@ function resolveOptions(userOptions, viteRoot) {
114
204
  onAfterWriteFile = () => {
115
205
  }
116
206
  } = userOptions;
117
- const root = viteRoot || slash(process.cwd());
207
+ const root = viteRoot || slash(process__default.cwd());
118
208
  const resolvedDirs = resolvePageDirs(dir, root, exclude);
119
209
  const resolvedSubDirs = subPackages.map((dir2) => slash(dir2));
120
210
  const ResolvedHomePage = typeof homePage === "string" ? [homePage] : homePage;
@@ -172,72 +262,10 @@ function writeFileSync(path, content) {
172
262
  fs__default.writeFileSync(path, content, { encoding: "utf-8" });
173
263
  }
174
264
 
175
- async function parseSFC(code) {
176
- try {
177
- return compilerSfc.parse(code, {
178
- pad: "space"
179
- }).descriptor || compilerSfc.parse({
180
- source: code
181
- });
182
- } catch {
183
- throw new Error(
184
- `[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required.`
185
- );
186
- }
187
- }
188
- function parseCustomBlock(block, filePath, options) {
189
- const lang = block.lang ?? options.routeBlockLang;
190
- const attr = {
191
- type: "page",
192
- ...block.attrs
193
- };
194
- let content;
195
- debug.routeBlock(`use ${lang} parser`);
196
- if (lang === "json5" || lang === "jsonc") {
197
- try {
198
- content = JSON5__default.parse(block.content);
199
- } catch (err) {
200
- throw new Error(
201
- `Invalid JSON5 format of <${block.type}> content in ${filePath}
202
- ${err.message}`
203
- );
204
- }
205
- } else if (lang === "json") {
206
- try {
207
- content = JSON.parse(block.content);
208
- } catch (err) {
209
- throw new Error(
210
- `Invalid JSON format of <${block.type}> content in ${filePath}
211
- ${err.message}`
212
- );
213
- }
214
- } else if (lang === "yaml" || lang === "yml") {
215
- try {
216
- content = yaml.parse(block.content);
217
- } catch (err) {
218
- throw new Error(
219
- `Invalid YAML format of <${block.type}> content in ${filePath}
220
- ${err.message}`
221
- );
222
- }
223
- }
224
- return {
225
- attr,
226
- content: content ?? {}
227
- };
228
- }
229
- async function getRouteBlock(path, options) {
230
- const content = fs__default.readFileSync(path, "utf8");
231
- const parsedSFC = await parseSFC(content);
232
- const blockStr = parsedSFC?.customBlocks.find((b) => b.type === "route");
233
- if (!blockStr)
234
- return;
235
- const result = parseCustomBlock(blockStr, path, options);
236
- return result;
237
- }
238
-
265
+ let lsatPagesJson = "";
266
+ const { setCache, hasChanged } = useCachedPages();
239
267
  class PageContext {
240
- constructor(userOptions, viteRoot = process.cwd()) {
268
+ constructor(userOptions, viteRoot = process__default.cwd()) {
241
269
  this.pagesPath = [];
242
270
  this.subPagesPath = {};
243
271
  this.pageMetaData = [];
@@ -260,10 +288,10 @@ class PageContext {
260
288
  this.logger = logger;
261
289
  }
262
290
  async loadUserPagesConfig() {
263
- const { config } = await unconfig.loadConfig({ sources: [{ files: "pages.config" }] });
291
+ const { config } = await unconfig.loadConfig({ cwd: this.root, sources: [{ files: "pages.config" }] });
264
292
  if (!config) {
265
293
  this.logger?.warn("Can't found pages.config, please create pages.config.(ts|mts|cts|js|cjs|mjs|json)");
266
- process.exit(-1);
294
+ process__default.exit(-1);
267
295
  }
268
296
  this.pagesGlobConfig = config;
269
297
  debug.options(config);
@@ -295,29 +323,39 @@ class PageContext {
295
323
  const configs = await getPagesConfigSourcePaths();
296
324
  watcher.add(configs);
297
325
  }
326
+ const targetDirs = [...this.options.dirs, ...this.options.subPackages].map((v) => slash(path__default.resolve(this.root, v)));
327
+ const isInTargetDirs = (path2) => targetDirs.some((v) => path2.startsWith(v));
298
328
  watcher.on("add", async (path2) => {
299
329
  path2 = slash(path2);
300
330
  if (!isTargetFile(path2))
301
331
  return;
332
+ if (!isInTargetDirs(path2))
333
+ return;
302
334
  debug.pages(`File added: ${path2}`);
303
- this.updatePagesJSON();
304
- this.onUpdate();
335
+ if (await this.updatePagesJSON())
336
+ this.onUpdate();
305
337
  });
306
338
  watcher.on("change", async (path2) => {
307
339
  path2 = slash(path2);
308
340
  if (!isTargetFile(path2) && !isConfigFile(path2))
309
341
  return;
342
+ if (!isInTargetDirs(path2))
343
+ return;
310
344
  debug.pages(`File changed: ${path2}`);
311
- this.updatePagesJSON();
312
- this.onUpdate();
345
+ debug.pages(targetDirs);
346
+ debug.pages(isInTargetDirs(path2));
347
+ if (await this.updatePagesJSON(path2))
348
+ this.onUpdate();
313
349
  });
314
350
  watcher.on("unlink", async (path2) => {
315
351
  path2 = slash(path2);
316
352
  if (!isTargetFile(path2))
317
353
  return;
354
+ if (!isInTargetDirs(path2))
355
+ return;
318
356
  debug.pages(`File removed: ${path2}`);
319
- this.updatePagesJSON();
320
- this.onUpdate();
357
+ if (await this.updatePagesJSON())
358
+ this.onUpdate();
321
359
  });
322
360
  }
323
361
  onUpdate() {
@@ -331,7 +369,9 @@ class PageContext {
331
369
  }
332
370
  async parsePage(page) {
333
371
  const { relativePath, absolutePath } = page;
334
- const routeBlock = await getRouteBlock(absolutePath, this.options);
372
+ const routeSfcBlock = await getRouteSfcBlock(absolutePath);
373
+ const routeBlock = await getRouteBlock(absolutePath, routeSfcBlock, this.options);
374
+ setCache(absolutePath, routeSfcBlock);
335
375
  const relativePathWithFileName = relativePath.replace(path__default.extname(relativePath), "");
336
376
  const pageMetaDatum = {
337
377
  path: vite.normalizePath(relativePathWithFileName),
@@ -396,7 +436,13 @@ class PageContext {
396
436
  this.subPageMetaData = subPageMetaData;
397
437
  debug.subPages(this.subPageMetaData);
398
438
  }
399
- async updatePagesJSON() {
439
+ async updatePagesJSON(filepath) {
440
+ if (filepath) {
441
+ if (!await hasChanged(filepath)) {
442
+ debug.cache(`The route block on page ${filepath} did not send any changes, skipping`);
443
+ return false;
444
+ }
445
+ }
400
446
  checkPagesJsonFile(this.resolvedPagesJSONPath);
401
447
  this.options.onBeforeLoadUserConfig(this);
402
448
  await this.loadUserPagesConfig();
@@ -418,8 +464,14 @@ class PageContext {
418
464
  subPackages: this.subPageMetaData
419
465
  };
420
466
  const pagesJson = JSON.stringify(data, null, this.options.minify ? void 0 : 2);
467
+ if (lsatPagesJson === pagesJson) {
468
+ debug.pages("PagesJson Not have change");
469
+ return false;
470
+ }
421
471
  writeFileSync(this.resolvedPagesJSONPath, pagesJson);
472
+ lsatPagesJson = pagesJson;
422
473
  this.options.onAfterWriteFile(this);
474
+ return true;
423
475
  }
424
476
  virtualModule() {
425
477
  const pages = `export const pages = ${this.resolveRoutes()};`;
@@ -494,9 +546,9 @@ function VitePluginUniPages(userOptions = {}) {
494
546
  },
495
547
  // Applet do not support custom route block, so we need to remove the route block here
496
548
  async transform(code, id) {
497
- if (!/\.vue$/.test(id))
549
+ if (!/\.n?vue$/.test(id) && !code.includes("</route>"))
498
550
  return null;
499
- const s = new MagicString__default(code.toString());
551
+ const s = new MagicString__default(code);
500
552
  const routeBlockMatches = s.original.matchAll(
501
553
  /<route[^>]*>([\s\S]*?)<\/route>/g
502
554
  );
@@ -505,7 +557,16 @@ function VitePluginUniPages(userOptions = {}) {
505
557
  const length = match[0].length;
506
558
  s.remove(index, index + length);
507
559
  }
508
- return s.toString();
560
+ if (s.hasChanged()) {
561
+ return {
562
+ code: s.toString(),
563
+ map: s.generateMap({
564
+ source: code,
565
+ includeContent: true,
566
+ file: id
567
+ })
568
+ };
569
+ }
509
570
  },
510
571
  configureServer(server) {
511
572
  ctx.setupViteServer(server);
@@ -535,6 +596,7 @@ exports.extsToGlob = extsToGlob;
535
596
  exports.getPageFiles = getPageFiles;
536
597
  exports.getPagesConfigSourcePaths = getPagesConfigSourcePaths;
537
598
  exports.getRouteBlock = getRouteBlock;
599
+ exports.getRouteSfcBlock = getRouteSfcBlock;
538
600
  exports.invalidatePagesModule = invalidatePagesModule;
539
601
  exports.isConfigFile = isConfigFile;
540
602
  exports.isTargetFile = isTargetFile;
@@ -543,4 +605,5 @@ exports.parseCustomBlock = parseCustomBlock;
543
605
  exports.parseSFC = parseSFC;
544
606
  exports.resolveOptions = resolveOptions;
545
607
  exports.resolvePageDirs = resolvePageDirs;
608
+ exports.useCachedPages = useCachedPages;
546
609
  exports.writeFileSync = writeFileSync;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Logger, ViteDevServer, Plugin } from 'vite';
2
2
  import { FSWatcher } from 'chokidar';
3
3
  import Debug from 'debug';
4
- import { SFCDescriptor, SFCBlock } from '@vue/compiler-sfc';
4
+ import { SFCBlock, SFCDescriptor } from '@vue/compiler-sfc';
5
5
 
6
6
  interface EasyCom {
7
7
  autoscan: boolean;
@@ -660,7 +660,7 @@ declare class PageContext {
660
660
  setHomePage(result: PageMetaDatum[]): true | undefined;
661
661
  mergePageMetaData(): Promise<void>;
662
662
  mergeSubPageMetaData(): Promise<void>;
663
- updatePagesJSON(): Promise<void>;
663
+ updatePagesJSON(filepath?: string): Promise<boolean>;
664
664
  virtualModule(): string;
665
665
  resolveRoutes(): string;
666
666
  resolveSubRoutes(): string;
@@ -674,6 +674,7 @@ declare const debug: {
674
674
  pages: Debug.Debugger;
675
675
  subPages: Debug.Debugger;
676
676
  error: Debug.Debugger;
677
+ cache: Debug.Debugger;
677
678
  };
678
679
  declare function extsToGlob(extensions: string[]): string;
679
680
  declare function isTargetFile(path: string): boolean;
@@ -685,6 +686,10 @@ declare function isConfigFile(path: string): boolean;
685
686
  */
686
687
  declare function mergePageMetaDataArray(pageMetaData: PageMetaDatum[]): PageMetaDatum[];
687
688
  declare function getPagesConfigSourcePaths(): Promise<string[]>;
689
+ declare function useCachedPages(): {
690
+ setCache: (filePath: string, routeBlock?: SFCBlock) => void;
691
+ hasChanged: (filePath: string, routeBlock?: SFCBlock) => Promise<boolean>;
692
+ };
688
693
 
689
694
  interface CustomBlock {
690
695
  attr: Record<string, any>;
@@ -806,8 +811,9 @@ declare function resolvePageDirs(dir: string, root: string, exclude: string[]):
806
811
 
807
812
  declare function parseSFC(code: string): Promise<SFCDescriptor>;
808
813
  declare function parseCustomBlock(block: SFCBlock, filePath: string, options: ResolvedOptions): CustomBlock | undefined;
809
- declare function getRouteBlock(path: string, options: ResolvedOptions): Promise<CustomBlock | undefined>;
814
+ declare function getRouteSfcBlock(path: string): Promise<SFCBlock | undefined>;
815
+ declare function getRouteBlock(path: string, blockStr: SFCBlock | undefined, options: ResolvedOptions): Promise<CustomBlock | undefined>;
810
816
 
811
817
  declare function VitePluginUniPages(userOptions?: UserOptions): Plugin;
812
818
 
813
- export { Condition, ConditionItem, CustomBlock, EasyCom, FILE_EXTENSIONS, GlobalStyle, IconFont, MODULE_ID_VIRTUAL, MidButton, OUTPUT_NAME, Options, PageContext, PageMetaDatum, PagePath, PagesConfig, PreloadRule, RESOLVED_MODULE_ID_VIRTUAL, ResolvedOptions, SubPackage, SubPageMetaDatum, TabBar, TabBarItem, TheWindow, UniIdRouter, UserOptions, UserPagesConfig, VitePluginUniPages, checkPagesJsonFile, debug, debugType, VitePluginUniPages as default, defineUniPages, extsToGlob, getPageFiles, getPagesConfigSourcePaths, getRouteBlock, invalidatePagesModule, isConfigFile, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, writeFileSync };
819
+ export { Condition, ConditionItem, CustomBlock, EasyCom, FILE_EXTENSIONS, GlobalStyle, IconFont, MODULE_ID_VIRTUAL, MidButton, OUTPUT_NAME, Options, PageContext, PageMetaDatum, PagePath, PagesConfig, PreloadRule, RESOLVED_MODULE_ID_VIRTUAL, ResolvedOptions, SubPackage, SubPageMetaDatum, TabBar, TabBarItem, TheWindow, UniIdRouter, UserOptions, UserPagesConfig, VitePluginUniPages, checkPagesJsonFile, debug, debugType, VitePluginUniPages as default, defineUniPages, extsToGlob, getPageFiles, getPagesConfigSourcePaths, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isConfigFile, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, useCachedPages, writeFileSync };
package/dist/index.mjs CHANGED
@@ -3,6 +3,7 @@ import { spawn } from 'node:child_process';
3
3
  import { normalizePath, createLogger } from 'vite';
4
4
  import MagicString from 'magic-string';
5
5
  import chokidar from 'chokidar';
6
+ import process$1 from 'node:process';
6
7
  import { loadConfig } from 'unconfig';
7
8
  import { isH5 } from '@uni-helper/uni-env';
8
9
  import Debug from 'debug';
@@ -22,6 +23,72 @@ const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}`;
22
23
  const OUTPUT_NAME = "pages.json";
23
24
  const FILE_EXTENSIONS = ["vue", "nvue", "uvue"];
24
25
 
26
+ async function parseSFC(code) {
27
+ try {
28
+ return parse(code, {
29
+ pad: "space"
30
+ }).descriptor || parse({
31
+ source: code
32
+ });
33
+ } catch {
34
+ throw new Error(
35
+ `[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required.`
36
+ );
37
+ }
38
+ }
39
+ function parseCustomBlock(block, filePath, options) {
40
+ const lang = block.lang ?? options.routeBlockLang;
41
+ const attr = {
42
+ type: "page",
43
+ ...block.attrs
44
+ };
45
+ let content;
46
+ debug.routeBlock(`use ${lang} parser`);
47
+ if (lang === "json5" || lang === "jsonc") {
48
+ try {
49
+ content = JSON5.parse(block.content);
50
+ } catch (err) {
51
+ throw new Error(
52
+ `Invalid JSON5 format of <${block.type}> content in ${filePath}
53
+ ${err.message}`
54
+ );
55
+ }
56
+ } else if (lang === "json") {
57
+ try {
58
+ content = JSON.parse(block.content);
59
+ } catch (err) {
60
+ throw new Error(
61
+ `Invalid JSON format of <${block.type}> content in ${filePath}
62
+ ${err.message}`
63
+ );
64
+ }
65
+ } else if (lang === "yaml" || lang === "yml") {
66
+ try {
67
+ content = parse$1(block.content);
68
+ } catch (err) {
69
+ throw new Error(
70
+ `Invalid YAML format of <${block.type}> content in ${filePath}
71
+ ${err.message}`
72
+ );
73
+ }
74
+ }
75
+ return {
76
+ attr,
77
+ content: content ?? {}
78
+ };
79
+ }
80
+ async function getRouteSfcBlock(path) {
81
+ const content = fs.readFileSync(path, "utf8");
82
+ const parsedSFC = await parseSFC(content);
83
+ const blockStr = parsedSFC?.customBlocks.find((b) => b.type === "route");
84
+ return blockStr;
85
+ }
86
+ async function getRouteBlock(path, blockStr, options) {
87
+ if (!blockStr)
88
+ return;
89
+ return parseCustomBlock(blockStr, path, options);
90
+ }
91
+
25
92
  function invalidatePagesModule(server) {
26
93
  const { moduleGraph } = server;
27
94
  const mods = moduleGraph.getModulesByFile(RESOLVED_MODULE_ID_VIRTUAL);
@@ -38,7 +105,8 @@ const debug = {
38
105
  options: Debug("vite-plugin-uni-pages:options"),
39
106
  pages: Debug("vite-plugin-uni-pages:pages"),
40
107
  subPages: Debug("vite-plugin-uni-pages:subPages"),
41
- error: Debug("vite-plugin-uni-pages:error")
108
+ error: Debug("vite-plugin-uni-pages:error"),
109
+ cache: Debug("vite-plugin-uni-pages:cache")
42
110
  };
43
111
  function extsToGlob(extensions) {
44
112
  return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
@@ -71,6 +139,27 @@ async function getPagesConfigSourcePaths() {
71
139
  absolute: true
72
140
  });
73
141
  }
142
+ function useCachedPages() {
143
+ const pages = /* @__PURE__ */ new Map();
144
+ function parseData(block) {
145
+ return {
146
+ content: block?.loc.source.trim() ?? "",
147
+ attr: block?.attrs ?? ""
148
+ };
149
+ }
150
+ function setCache(filePath, routeBlock) {
151
+ pages.set(filePath, JSON.stringify(parseData(routeBlock)));
152
+ }
153
+ async function hasChanged(filePath, routeBlock) {
154
+ if (!routeBlock)
155
+ routeBlock = await getRouteSfcBlock(normalizePath(filePath));
156
+ return !pages.has(filePath) || JSON.stringify(parseData(routeBlock)) !== pages.get(filePath);
157
+ }
158
+ return {
159
+ setCache,
160
+ hasChanged
161
+ };
162
+ }
74
163
 
75
164
  function resolveOptions(userOptions, viteRoot) {
76
165
  const {
@@ -100,7 +189,7 @@ function resolveOptions(userOptions, viteRoot) {
100
189
  onAfterWriteFile = () => {
101
190
  }
102
191
  } = userOptions;
103
- const root = viteRoot || slash(process.cwd());
192
+ const root = viteRoot || slash(process$1.cwd());
104
193
  const resolvedDirs = resolvePageDirs(dir, root, exclude);
105
194
  const resolvedSubDirs = subPackages.map((dir2) => slash(dir2));
106
195
  const ResolvedHomePage = typeof homePage === "string" ? [homePage] : homePage;
@@ -158,72 +247,10 @@ function writeFileSync(path, content) {
158
247
  fs.writeFileSync(path, content, { encoding: "utf-8" });
159
248
  }
160
249
 
161
- async function parseSFC(code) {
162
- try {
163
- return parse(code, {
164
- pad: "space"
165
- }).descriptor || parse({
166
- source: code
167
- });
168
- } catch {
169
- throw new Error(
170
- `[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required.`
171
- );
172
- }
173
- }
174
- function parseCustomBlock(block, filePath, options) {
175
- const lang = block.lang ?? options.routeBlockLang;
176
- const attr = {
177
- type: "page",
178
- ...block.attrs
179
- };
180
- let content;
181
- debug.routeBlock(`use ${lang} parser`);
182
- if (lang === "json5" || lang === "jsonc") {
183
- try {
184
- content = JSON5.parse(block.content);
185
- } catch (err) {
186
- throw new Error(
187
- `Invalid JSON5 format of <${block.type}> content in ${filePath}
188
- ${err.message}`
189
- );
190
- }
191
- } else if (lang === "json") {
192
- try {
193
- content = JSON.parse(block.content);
194
- } catch (err) {
195
- throw new Error(
196
- `Invalid JSON format of <${block.type}> content in ${filePath}
197
- ${err.message}`
198
- );
199
- }
200
- } else if (lang === "yaml" || lang === "yml") {
201
- try {
202
- content = parse$1(block.content);
203
- } catch (err) {
204
- throw new Error(
205
- `Invalid YAML format of <${block.type}> content in ${filePath}
206
- ${err.message}`
207
- );
208
- }
209
- }
210
- return {
211
- attr,
212
- content: content ?? {}
213
- };
214
- }
215
- async function getRouteBlock(path, options) {
216
- const content = fs.readFileSync(path, "utf8");
217
- const parsedSFC = await parseSFC(content);
218
- const blockStr = parsedSFC?.customBlocks.find((b) => b.type === "route");
219
- if (!blockStr)
220
- return;
221
- const result = parseCustomBlock(blockStr, path, options);
222
- return result;
223
- }
224
-
250
+ let lsatPagesJson = "";
251
+ const { setCache, hasChanged } = useCachedPages();
225
252
  class PageContext {
226
- constructor(userOptions, viteRoot = process.cwd()) {
253
+ constructor(userOptions, viteRoot = process$1.cwd()) {
227
254
  this.pagesPath = [];
228
255
  this.subPagesPath = {};
229
256
  this.pageMetaData = [];
@@ -246,10 +273,10 @@ class PageContext {
246
273
  this.logger = logger;
247
274
  }
248
275
  async loadUserPagesConfig() {
249
- const { config } = await loadConfig({ sources: [{ files: "pages.config" }] });
276
+ const { config } = await loadConfig({ cwd: this.root, sources: [{ files: "pages.config" }] });
250
277
  if (!config) {
251
278
  this.logger?.warn("Can't found pages.config, please create pages.config.(ts|mts|cts|js|cjs|mjs|json)");
252
- process.exit(-1);
279
+ process$1.exit(-1);
253
280
  }
254
281
  this.pagesGlobConfig = config;
255
282
  debug.options(config);
@@ -281,29 +308,39 @@ class PageContext {
281
308
  const configs = await getPagesConfigSourcePaths();
282
309
  watcher.add(configs);
283
310
  }
311
+ const targetDirs = [...this.options.dirs, ...this.options.subPackages].map((v) => slash(path.resolve(this.root, v)));
312
+ const isInTargetDirs = (path2) => targetDirs.some((v) => path2.startsWith(v));
284
313
  watcher.on("add", async (path2) => {
285
314
  path2 = slash(path2);
286
315
  if (!isTargetFile(path2))
287
316
  return;
317
+ if (!isInTargetDirs(path2))
318
+ return;
288
319
  debug.pages(`File added: ${path2}`);
289
- this.updatePagesJSON();
290
- this.onUpdate();
320
+ if (await this.updatePagesJSON())
321
+ this.onUpdate();
291
322
  });
292
323
  watcher.on("change", async (path2) => {
293
324
  path2 = slash(path2);
294
325
  if (!isTargetFile(path2) && !isConfigFile(path2))
295
326
  return;
327
+ if (!isInTargetDirs(path2))
328
+ return;
296
329
  debug.pages(`File changed: ${path2}`);
297
- this.updatePagesJSON();
298
- this.onUpdate();
330
+ debug.pages(targetDirs);
331
+ debug.pages(isInTargetDirs(path2));
332
+ if (await this.updatePagesJSON(path2))
333
+ this.onUpdate();
299
334
  });
300
335
  watcher.on("unlink", async (path2) => {
301
336
  path2 = slash(path2);
302
337
  if (!isTargetFile(path2))
303
338
  return;
339
+ if (!isInTargetDirs(path2))
340
+ return;
304
341
  debug.pages(`File removed: ${path2}`);
305
- this.updatePagesJSON();
306
- this.onUpdate();
342
+ if (await this.updatePagesJSON())
343
+ this.onUpdate();
307
344
  });
308
345
  }
309
346
  onUpdate() {
@@ -317,7 +354,9 @@ class PageContext {
317
354
  }
318
355
  async parsePage(page) {
319
356
  const { relativePath, absolutePath } = page;
320
- const routeBlock = await getRouteBlock(absolutePath, this.options);
357
+ const routeSfcBlock = await getRouteSfcBlock(absolutePath);
358
+ const routeBlock = await getRouteBlock(absolutePath, routeSfcBlock, this.options);
359
+ setCache(absolutePath, routeSfcBlock);
321
360
  const relativePathWithFileName = relativePath.replace(path.extname(relativePath), "");
322
361
  const pageMetaDatum = {
323
362
  path: normalizePath(relativePathWithFileName),
@@ -382,7 +421,13 @@ class PageContext {
382
421
  this.subPageMetaData = subPageMetaData;
383
422
  debug.subPages(this.subPageMetaData);
384
423
  }
385
- async updatePagesJSON() {
424
+ async updatePagesJSON(filepath) {
425
+ if (filepath) {
426
+ if (!await hasChanged(filepath)) {
427
+ debug.cache(`The route block on page ${filepath} did not send any changes, skipping`);
428
+ return false;
429
+ }
430
+ }
386
431
  checkPagesJsonFile(this.resolvedPagesJSONPath);
387
432
  this.options.onBeforeLoadUserConfig(this);
388
433
  await this.loadUserPagesConfig();
@@ -404,8 +449,14 @@ class PageContext {
404
449
  subPackages: this.subPageMetaData
405
450
  };
406
451
  const pagesJson = JSON.stringify(data, null, this.options.minify ? void 0 : 2);
452
+ if (lsatPagesJson === pagesJson) {
453
+ debug.pages("PagesJson Not have change");
454
+ return false;
455
+ }
407
456
  writeFileSync(this.resolvedPagesJSONPath, pagesJson);
457
+ lsatPagesJson = pagesJson;
408
458
  this.options.onAfterWriteFile(this);
459
+ return true;
409
460
  }
410
461
  virtualModule() {
411
462
  const pages = `export const pages = ${this.resolveRoutes()};`;
@@ -480,9 +531,9 @@ function VitePluginUniPages(userOptions = {}) {
480
531
  },
481
532
  // Applet do not support custom route block, so we need to remove the route block here
482
533
  async transform(code, id) {
483
- if (!/\.vue$/.test(id))
534
+ if (!/\.n?vue$/.test(id) && !code.includes("</route>"))
484
535
  return null;
485
- const s = new MagicString(code.toString());
536
+ const s = new MagicString(code);
486
537
  const routeBlockMatches = s.original.matchAll(
487
538
  /<route[^>]*>([\s\S]*?)<\/route>/g
488
539
  );
@@ -491,7 +542,16 @@ function VitePluginUniPages(userOptions = {}) {
491
542
  const length = match[0].length;
492
543
  s.remove(index, index + length);
493
544
  }
494
- return s.toString();
545
+ if (s.hasChanged()) {
546
+ return {
547
+ code: s.toString(),
548
+ map: s.generateMap({
549
+ source: code,
550
+ includeContent: true,
551
+ file: id
552
+ })
553
+ };
554
+ }
495
555
  },
496
556
  configureServer(server) {
497
557
  ctx.setupViteServer(server);
@@ -507,4 +567,4 @@ function VitePluginUniPages(userOptions = {}) {
507
567
  };
508
568
  }
509
569
 
510
- export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, checkPagesJsonFile, debug, VitePluginUniPages as default, defineUniPages, extsToGlob, getPageFiles, getPagesConfigSourcePaths, getRouteBlock, invalidatePagesModule, isConfigFile, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, writeFileSync };
570
+ export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, checkPagesJsonFile, debug, VitePluginUniPages as default, defineUniPages, extsToGlob, getPageFiles, getPagesConfigSourcePaths, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isConfigFile, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, resolveOptions, resolvePageDirs, useCachedPages, writeFileSync };
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.2.3",
4
+ "version": "0.2.5",
5
5
  "description": "File system based routing for uni-app applications using Vite",
6
6
  "author": "KeJun",
7
7
  "license": "MIT",
@@ -32,20 +32,20 @@
32
32
  ],
33
33
  "dependencies": {
34
34
  "@uni-helper/uni-env": "^0.0.3",
35
- "@vue/compiler-sfc": "^3.3.1",
35
+ "@vue/compiler-sfc": "^3.3.4",
36
36
  "chokidar": "^3.5.3",
37
37
  "debug": "^4.3.4",
38
- "fast-glob": "^3.2.12",
38
+ "fast-glob": "^3.3.1",
39
39
  "json5": "^2.2.3",
40
40
  "lodash-unified": "^1.0.3",
41
- "magic-string": "^0.30.0",
42
- "unconfig": "^0.3.7",
43
- "yaml": "^2.2.2"
41
+ "magic-string": "^0.30.2",
42
+ "unconfig": "^0.3.10",
43
+ "yaml": "^2.3.1"
44
44
  },
45
45
  "devDependencies": {
46
- "@antfu/utils": "^0.7.2",
47
- "@types/debug": "^4.1.7",
48
- "@types/node": "^18.16.8"
46
+ "@antfu/utils": "^0.7.5",
47
+ "@types/debug": "^4.1.8",
48
+ "@types/node": "^18.17.1"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "unbuild",