@uni-helper/vite-plugin-uni-pages 0.3.2 → 0.3.4

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.mjs CHANGED
@@ -1,22 +1,34 @@
1
- import path, { join, dirname, resolve } from 'node:path';
2
1
  import { spawn } from 'node:child_process';
2
+ import path, { join, dirname, resolve, extname } from 'node:path';
3
3
  import process from 'node:process';
4
- import { normalizePath, createLogger } from 'vite';
5
- import MagicString from 'magic-string';
4
+ import { babelParse, isCallOf } from 'ast-kit';
6
5
  import chokidar from 'chokidar';
7
- import { loadConfig } from 'unconfig';
8
- import Debug from 'debug';
6
+ import { lightYellow, bold, link, dim } from 'kolorist';
7
+ import MagicString from 'magic-string';
8
+ import { normalizePath, createLogger } from 'vite';
9
9
  import { platform } from '@uni-helper/uni-env';
10
+ import { stringify, parse, assign } from 'comment-json';
11
+ import Debug from 'debug';
10
12
  import detectIndent from 'detect-indent';
11
13
  import detectNewline from 'detect-newline';
12
- import { parse as parse$1, stringify, assign } from 'comment-json';
13
- import fs, { existsSync } from 'node:fs';
14
+ import { loadConfig } from 'unconfig';
15
+ import fs, { existsSync, readFileSync as readFileSync$1 } from 'node:fs';
14
16
  import { readFile, mkdir, writeFile as writeFile$1 } from 'node:fs/promises';
17
+ import fg from 'fast-glob';
18
+ import { createRequire } from 'node:module';
19
+ import vm from 'node:vm';
20
+ import babelGenerator from '@babel/generator';
15
21
  import groupBy from 'lodash.groupby';
22
+ import * as ts from 'typescript';
23
+ import * as t from '@babel/types';
24
+ import { parse as parse$2 } from '@vue/compiler-sfc';
16
25
  import JSON5 from 'json5';
17
- import { parse as parse$2 } from 'yaml';
18
- import { parse } from '@vue/compiler-sfc';
19
- import fg from 'fast-glob';
26
+ import { parse as parse$1 } from 'yaml';
27
+
28
+ const MODULE_ID_VIRTUAL = "virtual:uni-pages";
29
+ const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}`;
30
+ const OUTPUT_NAME = "pages.json";
31
+ const FILE_EXTENSIONS = ["vue", "nvue", "uvue"];
20
32
 
21
33
  function slash(str) {
22
34
  return str.replace(/\\/g, "/");
@@ -68,86 +80,6 @@ async function writeDeclaration(ctx, filepath) {
68
80
  await writeFile(filepath, code);
69
81
  }
70
82
 
71
- const MODULE_ID_VIRTUAL = "virtual:uni-pages";
72
- const RESOLVED_MODULE_ID_VIRTUAL = `\0${MODULE_ID_VIRTUAL}`;
73
- const OUTPUT_NAME = "pages.json";
74
- const FILE_EXTENSIONS = ["vue", "nvue", "uvue"];
75
-
76
- async function parseSFC(code) {
77
- try {
78
- return parse(code, {
79
- pad: "space"
80
- }).descriptor || parse({
81
- source: code
82
- });
83
- } catch (error) {
84
- throw new Error(`[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required.
85
- Original error:
86
- ${error}`);
87
- }
88
- }
89
- function parseCustomBlock(block, filePath, options) {
90
- const lang = block.lang ?? options.routeBlockLang;
91
- const attr = {
92
- type: "page",
93
- ...block.attrs
94
- };
95
- let content;
96
- debug.routeBlock(`use ${lang} parser`);
97
- if (lang === "json5") {
98
- try {
99
- content = JSON5.parse(block.content);
100
- } catch (err) {
101
- throw new Error(
102
- `Invalid JSON5 format of <${block.type}> content in ${filePath}
103
- ${err.message}`
104
- );
105
- }
106
- } else if (lang === "jsonc") {
107
- try {
108
- content = parse$1(block.content);
109
- } catch (err) {
110
- throw new Error(
111
- `Invalid JSONC format of <${block.type}> content in ${filePath}
112
- ${err.message}`
113
- );
114
- }
115
- } else if (lang === "json") {
116
- try {
117
- content = JSON.parse(block.content);
118
- } catch (err) {
119
- throw new Error(
120
- `Invalid JSON format of <${block.type}> content in ${filePath}
121
- ${err.message}`
122
- );
123
- }
124
- } else if (lang === "yaml" || lang === "yml") {
125
- try {
126
- content = parse$2(block.content);
127
- } catch (err) {
128
- throw new Error(
129
- `Invalid YAML format of <${block.type}> content in ${filePath}
130
- ${err.message}`
131
- );
132
- }
133
- }
134
- return {
135
- attr,
136
- content: content ?? {}
137
- };
138
- }
139
- async function getRouteSfcBlock(path) {
140
- const content = fs.readFileSync(path, "utf8");
141
- const parsedSFC = await parseSFC(content);
142
- const blockStr = parsedSFC?.customBlocks.find((b) => b.type === "route");
143
- return blockStr;
144
- }
145
- async function getRouteBlock(path, blockStr, options) {
146
- if (!blockStr)
147
- return;
148
- return parseCustomBlock(blockStr, path, options);
149
- }
150
-
151
83
  function invalidatePagesModule(server) {
152
84
  const { moduleGraph } = server;
153
85
  const mods = moduleGraph.getModulesByFile(RESOLVED_MODULE_ID_VIRTUAL);
@@ -166,20 +98,21 @@ const debug = {
166
98
  subPages: Debug("vite-plugin-uni-pages:subPages"),
167
99
  error: Debug("vite-plugin-uni-pages:error"),
168
100
  cache: Debug("vite-plugin-uni-pages:cache"),
169
- declaration: Debug("vite-plugin-uni-pages:declaration")
101
+ declaration: Debug("vite-plugin-uni-pages:declaration"),
102
+ definePage: Debug("vite-plugin-uni-pages:definePage")
170
103
  };
171
104
  function extsToGlob(extensions) {
172
105
  return extensions.length > 1 ? `{${extensions.join(",")}}` : extensions[0] || "";
173
106
  }
174
- function isTargetFile(path) {
175
- const ext = path.split(".").pop();
107
+ function isTargetFile(path2) {
108
+ const ext = path2.split(".").pop();
176
109
  return FILE_EXTENSIONS.includes(ext);
177
110
  }
178
111
  function mergePageMetaDataArray(pageMetaData) {
179
112
  const pageMetaDataObj = groupBy(pageMetaData, "path");
180
113
  const result = [];
181
- for (const path in pageMetaDataObj) {
182
- const _pageMetaData = pageMetaDataObj[path];
114
+ for (const path2 in pageMetaDataObj) {
115
+ const _pageMetaData = pageMetaDataObj[path2];
183
116
  const options = _pageMetaData[0];
184
117
  for (const page of _pageMetaData) {
185
118
  options.style = Object.assign(options.style ?? {}, page.style ?? {});
@@ -189,26 +122,64 @@ function mergePageMetaDataArray(pageMetaData) {
189
122
  }
190
123
  return result;
191
124
  }
192
- function useCachedPages() {
193
- const pages = /* @__PURE__ */ new Map();
194
- function parseData(block) {
195
- return {
196
- content: block?.loc.source.trim() ?? "",
197
- attr: block?.attrs ?? ""
198
- };
125
+ async function execScript(code, filename) {
126
+ const jsCode = ts.transpileModule(code, {
127
+ compilerOptions: {
128
+ module: ts.ModuleKind.CommonJS,
129
+ target: ts.ScriptTarget.ESNext
130
+ }
131
+ }).outputText;
132
+ const dir = path.dirname(filename);
133
+ const vmContext = {
134
+ require: createRequire(dir),
135
+ module: {},
136
+ exports: {},
137
+ __filename: filename,
138
+ __dirname: dir
139
+ };
140
+ const script = new vm.Script(jsCode);
141
+ try {
142
+ script.runInNewContext(vmContext);
143
+ } catch (error) {
144
+ throw new Error(`${filename}: ${error.message}`);
199
145
  }
200
- function setCache(filePath, routeBlock) {
201
- pages.set(filePath, stringify(parseData(routeBlock)));
146
+ const result = vmContext.exports.default || vmContext.exports;
147
+ if (typeof result === "function") {
148
+ return Promise.resolve(result());
202
149
  }
203
- async function hasChanged(filePath, routeBlock) {
204
- if (!routeBlock)
205
- routeBlock = await getRouteSfcBlock(normalizePath(filePath));
206
- return !pages.has(filePath) || stringify(parseData(routeBlock)) !== pages.get(filePath);
150
+ return Promise.resolve(result);
151
+ }
152
+ function getDefaultExport(expr) {
153
+ return expr.default === void 0 ? expr : expr.default;
154
+ }
155
+ const babelGenerate = getDefaultExport(babelGenerator);
156
+
157
+ function getPageFiles(path, options) {
158
+ const { exclude } = options;
159
+ const ext = extsToGlob(FILE_EXTENSIONS);
160
+ const files = fg.sync(`**/*.${ext}`, {
161
+ ignore: exclude,
162
+ onlyFiles: true,
163
+ cwd: path
164
+ });
165
+ return files;
166
+ }
167
+ function checkPagesJsonFile(path) {
168
+ if (!fs.existsSync(path)) {
169
+ writeFileSync(path, stringify({ pages: [{ path: "" }] }, null, 2));
170
+ return false;
207
171
  }
208
- return {
209
- setCache,
210
- hasChanged
211
- };
172
+ return true;
173
+ }
174
+ function readFileSync(path) {
175
+ try {
176
+ return fs.readFileSync(path, { encoding: "utf-8" });
177
+ } catch {
178
+ return "";
179
+ }
180
+ }
181
+ function writeFileSync(path, content) {
182
+ fs.writeFileSync(path, content, { encoding: "utf-8" });
212
183
  }
213
184
 
214
185
  function resolveOptions(userOptions, viteRoot = process.cwd()) {
@@ -282,32 +253,190 @@ function resolvePageDirs(dir, root, exclude) {
282
253
  return dirs;
283
254
  }
284
255
 
285
- function getPageFiles(path, options) {
286
- const { exclude } = options;
287
- const ext = extsToGlob(FILE_EXTENSIONS);
288
- const files = fg.sync(`**/*.${ext}`, {
289
- ignore: exclude,
290
- onlyFiles: true,
291
- cwd: path
292
- });
293
- return files;
256
+ function parseCustomBlock(block, filePath, routeBlockLang) {
257
+ const lang = block.lang ?? routeBlockLang;
258
+ const attr = {
259
+ type: "page",
260
+ ...block.attrs
261
+ };
262
+ let content;
263
+ debug.routeBlock(`use ${lang} parser`);
264
+ if (lang === "json5") {
265
+ try {
266
+ content = JSON5.parse(block.content);
267
+ } catch (err) {
268
+ throw new Error(
269
+ `Invalid JSON5 format of <${block.type}> content in ${filePath}
270
+ ${err.message}`
271
+ );
272
+ }
273
+ } else if (lang === "jsonc") {
274
+ try {
275
+ content = parse(block.content);
276
+ } catch (err) {
277
+ throw new Error(
278
+ `Invalid JSONC format of <${block.type}> content in ${filePath}
279
+ ${err.message}`
280
+ );
281
+ }
282
+ } else if (lang === "json") {
283
+ try {
284
+ content = JSON.parse(block.content);
285
+ } catch (err) {
286
+ throw new Error(
287
+ `Invalid JSON format of <${block.type}> content in ${filePath}
288
+ ${err.message}`
289
+ );
290
+ }
291
+ } else if (lang === "yaml" || lang === "yml") {
292
+ try {
293
+ content = parse$1(block.content);
294
+ } catch (err) {
295
+ throw new Error(
296
+ `Invalid YAML format of <${block.type}> content in ${filePath}
297
+ ${err.message}`
298
+ );
299
+ }
300
+ }
301
+ return {
302
+ attr,
303
+ content: content ?? {}
304
+ };
294
305
  }
295
- function checkPagesJsonFile(path) {
296
- if (!fs.existsSync(path)) {
297
- writeFileSync(path, stringify({ pages: [{ path: "" }] }, null, 2));
298
- return false;
306
+ function getRouteSfcBlock(sfc) {
307
+ return sfc?.customBlocks.find((b) => b.type === "route");
308
+ }
309
+ function getRouteBlock(path, blockStr, routeBlockLang) {
310
+ if (!blockStr)
311
+ return;
312
+ return parseCustomBlock(blockStr, path, routeBlockLang);
313
+ }
314
+
315
+ var __defProp$1 = Object.defineProperty;
316
+ var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
317
+ var __publicField$1 = (obj, key, value) => {
318
+ __defNormalProp$1(obj, typeof key !== "symbol" ? key + "" : key, value);
319
+ return value;
320
+ };
321
+ class Page {
322
+ constructor(ctx, path) {
323
+ __publicField$1(this, "ctx");
324
+ __publicField$1(this, "path");
325
+ __publicField$1(this, "rawOptions", "");
326
+ __publicField$1(this, "options");
327
+ this.ctx = ctx;
328
+ this.path = path;
329
+ }
330
+ async getPageMeta(forceUpdate = false) {
331
+ if (forceUpdate || !this.options) {
332
+ await this.readPageMeta();
333
+ }
334
+ return this.options;
335
+ }
336
+ async hasChanged() {
337
+ const { hasChanged } = await this.readPageMeta();
338
+ return hasChanged;
339
+ }
340
+ async readPageMeta() {
341
+ try {
342
+ const { relativePath } = this.path;
343
+ const { path, ...others } = await this.readPageMetaFromFile();
344
+ this.options = {
345
+ path: path ?? normalizePath(relativePath.replace(extname(relativePath), "")),
346
+ ...others
347
+ };
348
+ const raw = this.options ? JSON.stringify(this.options) : "";
349
+ const hasChanged = this.rawOptions !== raw;
350
+ this.rawOptions = raw;
351
+ return {
352
+ options: this.options,
353
+ hasChanged
354
+ };
355
+ } catch (err) {
356
+ throw new Error(`Read page options fail in ${this.path.relativePath}
357
+ ${err.message}`);
358
+ }
359
+ }
360
+ async readPageMetaFromFile() {
361
+ const content = readFileSync$1(this.path.absolutePath, "utf-8");
362
+ const sfc = parseSFC(content, { filename: this.path.absolutePath });
363
+ const meta = await tryPageMetaFromMacro(sfc);
364
+ if (meta) {
365
+ return meta;
366
+ }
367
+ return tryPageMetaFromCustomBlock(sfc, this.ctx.options.routeBlockLang);
299
368
  }
300
- return true;
301
369
  }
302
- function readFileSync(path) {
370
+ function parseSFC(code, options) {
303
371
  try {
304
- return fs.readFileSync(path, { encoding: "utf-8" });
305
- } catch {
306
- return "";
372
+ return parse$2(code, {
373
+ pad: "space",
374
+ ...options
375
+ }).descriptor || parse$2({
376
+ source: code,
377
+ ...options
378
+ });
379
+ } catch (error) {
380
+ throw new Error(`[vite-plugin-uni-pages] Vue3's "@vue/compiler-sfc" is required.
381
+ Original error:
382
+ ${error}`);
307
383
  }
308
384
  }
309
- function writeFileSync(path, content) {
310
- fs.writeFileSync(path, content, { encoding: "utf-8" });
385
+ async function tryPageMetaFromMacro(sfc) {
386
+ const sfcScript = sfc.scriptSetup || sfc.script;
387
+ if (!sfcScript) {
388
+ return void 0;
389
+ }
390
+ const ast = babelParse(sfcScript.content, sfcScript.lang || "js", {
391
+ plugins: [["importAttributes", { deprecatedAssertSyntax: true }]]
392
+ });
393
+ const macro = findMacro(ast.body, sfc.filename);
394
+ if (macro) {
395
+ const imports = findImports(ast.body).map((imp) => babelGenerate(imp).code);
396
+ const [macroOption] = macro.arguments;
397
+ const code = babelGenerate(macroOption).code;
398
+ let script = "";
399
+ const importScript = imports.join("");
400
+ script += importScript;
401
+ script += `export default ${code}`;
402
+ const result = await execScript(script, sfc.filename);
403
+ return result;
404
+ }
405
+ return void 0;
406
+ }
407
+ async function tryPageMetaFromCustomBlock(sfc, routeBlockLang) {
408
+ const block = getRouteSfcBlock(sfc);
409
+ const routeBlock = getRouteBlock(sfc.filename, block, routeBlockLang);
410
+ const pageMeta = {
411
+ type: routeBlock?.attr.type ?? "page"
412
+ };
413
+ if (routeBlock) {
414
+ assign(pageMeta, routeBlock.content);
415
+ }
416
+ return pageMeta;
417
+ }
418
+ function findMacro(stmts, filename) {
419
+ const nodes = stmts.map((raw) => {
420
+ let node = raw;
421
+ if (raw.type === "ExpressionStatement")
422
+ node = raw.expression;
423
+ return isCallOf(node, "definePage") ? node : void 0;
424
+ }).filter((node) => !!node);
425
+ if (!nodes.length)
426
+ return;
427
+ if (nodes.length > 1) {
428
+ throw new Error(`\u6BCF\u4E2A\u6587\u4EF6\u53EA\u5141\u8BB8\u8C03\u7528\u4E00\u6B21 definePage(): ${filename}`);
429
+ }
430
+ const macro = nodes[0];
431
+ const [opt] = macro.arguments;
432
+ if (opt && !t.isFunctionExpression(opt) && !t.isArrowFunctionExpression(opt) && !t.isObjectExpression(opt)) {
433
+ debug.definePage(`definePage() only accept argument in function or object: ${filename}`);
434
+ return;
435
+ }
436
+ return macro;
437
+ }
438
+ function findImports(stmts) {
439
+ return stmts.map((node) => node.type === "ImportDeclaration" ? node : void 0).filter((node) => !!node);
311
440
  }
312
441
 
313
442
  var __defProp = Object.defineProperty;
@@ -317,14 +446,15 @@ var __publicField = (obj, key, value) => {
317
446
  return value;
318
447
  };
319
448
  let lsatPagesJson = "";
320
- const { setCache, hasChanged } = useCachedPages();
321
449
  class PageContext {
322
450
  constructor(userOptions, viteRoot = process.cwd()) {
323
451
  __publicField(this, "_server");
324
452
  __publicField(this, "pagesGlobConfig");
325
453
  __publicField(this, "pagesConfigSourcePaths", []);
326
- __publicField(this, "pagesPath", []);
327
- __publicField(this, "subPagesPath", {});
454
+ __publicField(this, "pages", /* @__PURE__ */ new Map());
455
+ // abs path -> Page
456
+ __publicField(this, "subPages", /* @__PURE__ */ new Map());
457
+ // root -> abs path -> page
328
458
  __publicField(this, "pageMetaData", []);
329
459
  __publicField(this, "subPageMetaData", []);
330
460
  __publicField(this, "resolvedPagesJSONPath", "");
@@ -367,17 +497,30 @@ class PageContext {
367
497
  const pageDirFiles = this.options.dirs.map((dir) => {
368
498
  return { dir, files: getPagePaths(dir, this.options) };
369
499
  });
370
- this.pagesPath = pageDirFiles.map((page) => page.files).flat();
371
- debug.pages(this.pagesPath);
500
+ const paths = pageDirFiles.map((page) => page.files).flat();
501
+ debug.pages(paths);
502
+ const pages = /* @__PURE__ */ new Map();
503
+ for (const path2 of paths) {
504
+ const page = this.pages.get(path2.absolutePath) || new Page(this, path2);
505
+ pages.set(path2.absolutePath, page);
506
+ }
507
+ this.pages = pages;
372
508
  }
373
509
  async scanSubPages() {
374
- const subPagesPath = {};
510
+ const paths = {};
511
+ const subPages = /* @__PURE__ */ new Map();
375
512
  for (const dir of this.options.subPackages) {
376
513
  const pagePaths = getPagePaths(dir, this.options);
377
- subPagesPath[dir] = pagePaths;
514
+ paths[dir] = pagePaths;
515
+ const pages = /* @__PURE__ */ new Map();
516
+ for (const path2 of pagePaths) {
517
+ const page = this.subPages.get(dir)?.get(path2.absolutePath) || new Page(this, path2);
518
+ pages.set(path2.absolutePath, page);
519
+ }
520
+ subPages.set(dir, pages);
378
521
  }
379
- this.subPagesPath = subPagesPath;
380
- debug.subPages(this.subPagesPath);
522
+ debug.subPages(JSON.stringify(paths, null, 2));
523
+ this.subPages = subPages;
381
524
  }
382
525
  setupViteServer(server) {
383
526
  if (this._server === server)
@@ -438,20 +581,6 @@ class PageContext {
438
581
  type: "full-reload"
439
582
  });
440
583
  }
441
- async parsePage(page) {
442
- const { relativePath, absolutePath } = page;
443
- const routeSfcBlock = await getRouteSfcBlock(absolutePath);
444
- const routeBlock = await getRouteBlock(absolutePath, routeSfcBlock, this.options);
445
- setCache(absolutePath, routeSfcBlock);
446
- const relativePathWithFileName = relativePath.replace(path.extname(relativePath), "");
447
- const pageMetaDatum = {
448
- path: normalizePath(relativePathWithFileName),
449
- type: routeBlock?.attr.type ?? "page"
450
- };
451
- if (routeBlock)
452
- assign(pageMetaDatum, routeBlock.content);
453
- return pageMetaDatum;
454
- }
455
584
  /**
456
585
  * parse pages rules && set page type
457
586
  * @param pages page path array
@@ -460,7 +589,11 @@ class PageContext {
460
589
  * @returns pages rules
461
590
  */
462
591
  async parsePages(pages, type, overrides) {
463
- const generatedPageMetaData = await Promise.all(pages.map(async (page) => await this.parsePage(page)));
592
+ const jobs = [];
593
+ for (const [_, page] of pages) {
594
+ jobs.push(page.getPageMeta());
595
+ }
596
+ const generatedPageMetaData = await Promise.all(jobs);
464
597
  const customPageMetaData = overrides || [];
465
598
  const result = customPageMetaData.length ? mergePageMetaDataArray(generatedPageMetaData.concat(customPageMetaData)) : generatedPageMetaData;
466
599
  const parseMeta = result.filter(
@@ -492,14 +625,14 @@ class PageContext {
492
625
  return result;
493
626
  }
494
627
  async mergePageMetaData() {
495
- const pageMetaData = await this.parsePages(this.pagesPath, "main", this.pagesGlobConfig?.pages);
628
+ const pageMetaData = await this.parsePages(this.pages, "main", this.pagesGlobConfig?.pages);
496
629
  this.pageMetaData = pageMetaData;
497
630
  debug.pages(this.pageMetaData);
498
631
  }
499
632
  async mergeSubPageMetaData() {
500
633
  const subPageMaps = {};
501
634
  const subPackages = this.pagesGlobConfig?.subPackages || [];
502
- for (const [dir, pages] of Object.entries(this.subPagesPath)) {
635
+ for (const [dir, pages] of this.subPages) {
503
636
  const basePath = slash(path.join(this.options.root, this.options.outDir));
504
637
  const root = slash(path.relative(basePath, path.join(this.options.root, dir)));
505
638
  const globPackage = subPackages?.find((v) => v.root === root);
@@ -516,7 +649,18 @@ class PageContext {
516
649
  }
517
650
  async updatePagesJSON(filepath) {
518
651
  if (filepath) {
519
- if (!await hasChanged(filepath)) {
652
+ let page = this.pages.get(filepath);
653
+ if (!page) {
654
+ let subPage;
655
+ for (const [_, pages2] of this.subPages) {
656
+ subPage = pages2.get(filepath);
657
+ if (subPage) {
658
+ break;
659
+ }
660
+ }
661
+ page = subPage;
662
+ }
663
+ if (page && !await page.hasChanged()) {
520
664
  debug.cache(`The route block on page ${filepath} did not send any changes, skipping`);
521
665
  return false;
522
666
  }
@@ -644,16 +788,39 @@ function VitePluginUniPages(userOptions = {}) {
644
788
  },
645
789
  // Applet do not support custom route block, so we need to remove the route block here
646
790
  async transform(code, id) {
647
- if (!/\.n?vue$/.test(id) && !code.includes("</route>"))
791
+ if (!FILE_EXTENSIONS.find((ext) => id.endsWith(ext))) {
648
792
  return null;
793
+ }
794
+ const sfc = parseSFC(code, { filename: id });
795
+ let macro;
796
+ if (sfc.scriptSetup) {
797
+ const ast = babelParse(sfc.scriptSetup.content, sfc.scriptSetup.lang || "js");
798
+ macro = findMacro(ast.body, sfc.filename);
799
+ }
800
+ if (!macro && sfc.script) {
801
+ const ast = babelParse(sfc.script.content, sfc.script.lang || "js");
802
+ macro = findMacro(ast.body, sfc.filename);
803
+ }
804
+ const routeBlock = sfc.customBlocks.find((block) => block.type === "route");
805
+ if (!macro && !routeBlock)
806
+ return null;
807
+ if (macro && routeBlock)
808
+ throw new Error(`\u4E0D\u652F\u6301\u6DF7\u5408\u4F7F\u7528 definePage() \u548C <route/> ${id}`);
649
809
  const s = new MagicString(code);
650
- const routeBlockMatches = s.original.matchAll(
651
- /<route[^>]*>([\s\S]*?)<\/route>/g
652
- );
653
- for (const match of routeBlockMatches) {
654
- const index = match.index;
655
- const length = match[0].length;
656
- s.remove(index, index + length);
810
+ if (macro)
811
+ s.remove(macro.start, macro.end);
812
+ if (routeBlock) {
813
+ console.log(lightYellow("\u8B66\u544A\uFF1A"), `${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${link("\u67E5\u770B\u8FC1\u79FB\u6307\u5357", "https://uni-helper.js.org/vite-plugin-uni-pages/definePage")}\u3002`);
814
+ console.log(dim(id));
815
+ console.log();
816
+ const routeBlockMatches = s.original.matchAll(
817
+ /<route[^>]*>([\s\S]*?)<\/route>/g
818
+ );
819
+ for (const match of routeBlockMatches) {
820
+ const index = match.index;
821
+ const length = match[0].length;
822
+ s.remove(index, index + length);
823
+ }
657
824
  }
658
825
  if (s.hasChanged()) {
659
826
  return {
@@ -680,4 +847,4 @@ function VitePluginUniPages(userOptions = {}) {
680
847
  };
681
848
  }
682
849
 
683
- export { FILE_EXTENSIONS, MODULE_ID_VIRTUAL, OUTPUT_NAME, PageContext, RESOLVED_MODULE_ID_VIRTUAL, VitePluginUniPages, checkPagesJsonFile, debug, VitePluginUniPages as default, defineUniPages, extsToGlob, getPageFiles, getRouteBlock, getRouteSfcBlock, invalidatePagesModule, isTargetFile, mergePageMetaDataArray, parseCustomBlock, parseSFC, readFileSync, resolveOptions, resolvePageDirs, useCachedPages, writeFileSync };
850
+ 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 };
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /// <reference path="./client.d.ts" />
2
+
3
+ export * from './dist'
4
+
5
+ export { default } from './dist'