@weapp-vite/web 1.1.0 → 1.2.1

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
@@ -28,8 +28,10 @@ import * as t from "@babel/types";
28
28
  import fs from "fs-extra";
29
29
  import MagicString from "magic-string";
30
30
  import { dirname as dirname2, extname, join, normalize, posix, relative as relative2, resolve } from "pathe";
31
+ import { bundleRequire } from "rolldown-require";
31
32
 
32
33
  // src/compiler/wxml.ts
34
+ import { readFileSync } from "fs";
33
35
  import { parseDocument } from "htmlparser2";
34
36
  import { dirname, relative } from "pathe";
35
37
 
@@ -96,6 +98,8 @@ function normalizeTagName(name) {
96
98
  return "select";
97
99
  case "block":
98
100
  return "#fragment";
101
+ case "slot":
102
+ return "slot";
99
103
  default:
100
104
  return name || "div";
101
105
  }
@@ -111,6 +115,13 @@ function normalizeAttributeName(name) {
111
115
  }
112
116
 
113
117
  // src/compiler/wxml.ts
118
+ function shouldMarkWxsImport(pathname) {
119
+ const lower = pathname.toLowerCase();
120
+ if (lower.endsWith(".wxs") || lower.endsWith(".wxs.ts") || lower.endsWith(".wxs.js")) {
121
+ return false;
122
+ }
123
+ return lower.endsWith(".ts") || lower.endsWith(".js");
124
+ }
114
125
  function isRenderableNode(node) {
115
126
  if (node.type === "directive" || node.type === "comment") {
116
127
  return false;
@@ -317,6 +328,140 @@ function buildExpression(parts, scopeVar, wxsVar) {
317
328
  });
318
329
  return `(${segments.join(" + ")})`;
319
330
  }
331
+ function hasTopLevelColon(expression) {
332
+ let depth = 0;
333
+ let inSingleQuote = false;
334
+ let inDoubleQuote = false;
335
+ let inTemplate = false;
336
+ let escaped = false;
337
+ let sawTopLevelQuestion = false;
338
+ for (let index = 0; index < expression.length; index += 1) {
339
+ const char = expression[index];
340
+ if (inSingleQuote) {
341
+ if (escaped) {
342
+ escaped = false;
343
+ continue;
344
+ }
345
+ if (char === "\\") {
346
+ escaped = true;
347
+ continue;
348
+ }
349
+ if (char === "'") {
350
+ inSingleQuote = false;
351
+ }
352
+ continue;
353
+ }
354
+ if (inDoubleQuote) {
355
+ if (escaped) {
356
+ escaped = false;
357
+ continue;
358
+ }
359
+ if (char === "\\") {
360
+ escaped = true;
361
+ continue;
362
+ }
363
+ if (char === '"') {
364
+ inDoubleQuote = false;
365
+ }
366
+ continue;
367
+ }
368
+ if (inTemplate) {
369
+ if (escaped) {
370
+ escaped = false;
371
+ continue;
372
+ }
373
+ if (char === "\\") {
374
+ escaped = true;
375
+ continue;
376
+ }
377
+ if (char === "`") {
378
+ inTemplate = false;
379
+ }
380
+ continue;
381
+ }
382
+ if (char === "'") {
383
+ inSingleQuote = true;
384
+ continue;
385
+ }
386
+ if (char === '"') {
387
+ inDoubleQuote = true;
388
+ continue;
389
+ }
390
+ if (char === "`") {
391
+ inTemplate = true;
392
+ continue;
393
+ }
394
+ if (char === "(" || char === "[" || char === "{") {
395
+ depth += 1;
396
+ continue;
397
+ }
398
+ if (char === ")" || char === "]" || char === "}") {
399
+ depth = Math.max(0, depth - 1);
400
+ continue;
401
+ }
402
+ if (depth !== 0) {
403
+ continue;
404
+ }
405
+ if (char === "?") {
406
+ sawTopLevelQuestion = true;
407
+ continue;
408
+ }
409
+ if (char === ":") {
410
+ return !sawTopLevelQuestion;
411
+ }
412
+ }
413
+ return false;
414
+ }
415
+ function shouldWrapShorthandObject(expression) {
416
+ const trimmed = expression.trim();
417
+ if (!trimmed) {
418
+ return false;
419
+ }
420
+ if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.startsWith("(")) {
421
+ return false;
422
+ }
423
+ return hasTopLevelColon(trimmed);
424
+ }
425
+ function buildTemplateDataExpression(raw, scopeVar, wxsVar) {
426
+ const trimmed = raw.trim();
427
+ const parts = parseInterpolations(trimmed);
428
+ if (parts.length === 1 && parts[0]?.type === "expr") {
429
+ const expr = parts[0].value.trim();
430
+ if (expr) {
431
+ const normalizedExpr = shouldWrapShorthandObject(expr) ? `{ ${expr} }` : expr;
432
+ return buildExpression([{ type: "expr", value: normalizedExpr }], scopeVar, wxsVar);
433
+ }
434
+ }
435
+ return buildExpression(parseInterpolations(raw), scopeVar, wxsVar);
436
+ }
437
+ function createDependencyContext() {
438
+ return {
439
+ warnings: [],
440
+ dependencies: [],
441
+ dependencySet: /* @__PURE__ */ new Set(),
442
+ visited: /* @__PURE__ */ new Set(),
443
+ active: /* @__PURE__ */ new Set(),
444
+ circularWarnings: /* @__PURE__ */ new Set()
445
+ };
446
+ }
447
+ function addDependency(value, context, direct) {
448
+ if (!context.dependencySet.has(value)) {
449
+ context.dependencySet.add(value);
450
+ context.dependencies.push(value);
451
+ direct?.push(value);
452
+ }
453
+ }
454
+ function warnReadTemplate(context, target) {
455
+ context.warnings.push(`[web] \u65E0\u6CD5\u8BFB\u53D6\u6A21\u677F\u4F9D\u8D56: ${target}`);
456
+ }
457
+ function warnCircularTemplate(context, from, target) {
458
+ const key = `${from}=>${target}`;
459
+ if (context.circularWarnings.has(key)) {
460
+ return;
461
+ }
462
+ context.circularWarnings.add(key);
463
+ context.warnings.push(`[web] WXML \u5FAA\u73AF\u5F15\u7528: ${from} -> ${target}`);
464
+ }
320
465
  function extractFor(attribs) {
321
466
  const expr = attribs["wx:for"];
322
467
  const itemName = attribs["wx:for-item"]?.trim() || "item";
@@ -491,7 +636,7 @@ var Renderer = class {
491
636
  renderTemplateInvoke(node, scopeVar, wxsVar, _componentTags) {
492
637
  const attribs = node.attribs ?? {};
493
638
  const isExpr = buildExpression(parseInterpolations(attribs.is ?? ""), scopeVar, wxsVar);
494
- const dataExpr = attribs.data ? buildExpression(parseInterpolations(attribs.data), scopeVar, wxsVar) : void 0;
639
+ const dataExpr = attribs.data ? buildTemplateDataExpression(attribs.data, scopeVar, wxsVar) : void 0;
495
640
  const scopeExpr = dataExpr ? `ctx.mergeScope(${scopeVar}, ${dataExpr})` : scopeVar;
496
641
  return `ctx.renderTemplate(__templates, ${isExpr}, ${scopeExpr}, ctx)`;
497
642
  }
@@ -546,29 +691,38 @@ function collectSpecialNodes(nodes, context) {
546
691
  });
547
692
  continue;
548
693
  }
549
- if (name === "import" && node.attribs?.src) {
694
+ if ((name === "import" || name === "wx-import") && node.attribs?.src) {
550
695
  const resolved = context.resolveTemplate(node.attribs.src);
551
696
  if (resolved) {
552
697
  context.imports.push({
553
698
  id: resolved,
554
699
  importName: `__wxml_import_${context.imports.length}`
555
700
  });
701
+ } else {
702
+ context.warnings.push(`[web] \u65E0\u6CD5\u89E3\u6790\u6A21\u677F\u4F9D\u8D56: ${node.attribs.src} (from ${context.sourceId})`);
556
703
  }
557
704
  continue;
558
705
  }
559
- if (name === "include" && node.attribs?.src) {
706
+ if ((name === "include" || name === "wx-include") && node.attribs?.src) {
560
707
  const resolved = context.resolveTemplate(node.attribs.src);
561
708
  if (resolved) {
562
709
  context.includes.push({
563
710
  id: resolved,
564
711
  importName: `__wxml_include_${context.includes.length}`
565
712
  });
713
+ } else {
714
+ context.warnings.push(`[web] \u65E0\u6CD5\u89E3\u6790\u6A21\u677F\u4F9D\u8D56: ${node.attribs.src} (from ${context.sourceId})`);
566
715
  }
567
716
  continue;
568
717
  }
569
718
  if (name === "wxs") {
570
719
  const moduleName = node.attribs?.module?.trim();
571
720
  if (moduleName) {
721
+ const previousSource = context.wxsModules.get(moduleName);
722
+ if (previousSource) {
723
+ context.warnings.push(`[web] WXS \u6A21\u5757\u540D\u91CD\u590D: ${moduleName} (from ${context.sourceId})`);
724
+ }
725
+ context.wxsModules.set(moduleName, context.sourceId);
572
726
  if (node.attribs?.src) {
573
727
  const resolved = context.resolveWxs(node.attribs.src);
574
728
  if (resolved) {
@@ -603,7 +757,8 @@ function toRelativeImport(from, target) {
603
757
  const fromDir = dirname(from);
604
758
  const rel = relative(fromDir, target);
605
759
  if (!rel || rel.startsWith(".")) {
606
- return rel || `./${target.split("/").pop() ?? ""}`;
760
+ const fallback = normalizeTemplatePath(target).split("/").pop() ?? "";
761
+ return rel || `./${fallback}`;
607
762
  }
608
763
  return `./${rel}`;
609
764
  }
@@ -611,8 +766,50 @@ function normalizeTemplatePath(pathname) {
611
766
  return pathname.split("\\").join("/");
612
767
  }
613
768
  function compileWxml(options) {
769
+ const dependencyContext = options.dependencyContext ?? createDependencyContext();
770
+ const expandDependencies = options.expandDependencies ?? !options.dependencyContext;
771
+ const warnings = dependencyContext.warnings;
772
+ const expandDependencyTree = (dependencies2, importer) => {
773
+ for (const target of dependencies2) {
774
+ if (!target) {
775
+ continue;
776
+ }
777
+ if (dependencyContext.active.has(target)) {
778
+ warnCircularTemplate(dependencyContext, importer, target);
779
+ continue;
780
+ }
781
+ if (dependencyContext.visited.has(target)) {
782
+ continue;
783
+ }
784
+ dependencyContext.visited.add(target);
785
+ dependencyContext.active.add(target);
786
+ let source;
787
+ try {
788
+ source = readFileSync(target, "utf8");
789
+ } catch {
790
+ warnReadTemplate(dependencyContext, target);
791
+ dependencyContext.active.delete(target);
792
+ continue;
793
+ }
794
+ try {
795
+ const result = compileWxml({
796
+ id: target,
797
+ source,
798
+ resolveTemplatePath: options.resolveTemplatePath,
799
+ resolveWxsPath: options.resolveWxsPath,
800
+ dependencyContext,
801
+ expandDependencies: false
802
+ });
803
+ expandDependencyTree(result.dependencies, target);
804
+ } catch (error) {
805
+ if (error instanceof Error && error.message) {
806
+ warnings.push(`[web] \u65E0\u6CD5\u89E3\u6790\u6A21\u677F\u4F9D\u8D56: ${target} ${error.message}`);
807
+ }
808
+ }
809
+ dependencyContext.active.delete(target);
810
+ }
811
+ };
614
812
  let nodes = parseWxml(options.source);
615
- const warnings = [];
616
813
  let navigationBarAttrs;
617
814
  if (options.navigationBar) {
618
815
  const extracted = extractNavigationBarFromPageMeta(nodes);
@@ -626,11 +823,15 @@ function compileWxml(options) {
626
823
  const includes = [];
627
824
  const imports = [];
628
825
  const wxs = [];
826
+ const wxsModules = /* @__PURE__ */ new Map();
629
827
  const renderNodesList = collectSpecialNodes(nodes, {
630
828
  templates,
631
829
  includes,
632
830
  imports,
633
831
  wxs,
832
+ wxsModules,
833
+ warnings,
834
+ sourceId: options.id,
634
835
  resolveTemplate: (raw) => options.resolveTemplatePath(raw, options.id),
635
836
  resolveWxs: (raw) => options.resolveWxsPath(raw, options.id)
636
837
  });
@@ -647,22 +848,23 @@ function compileWxml(options) {
647
848
  `import { repeat } from 'lit/directives/repeat.js'`
648
849
  ];
649
850
  const bodyLines = [];
650
- const dependencies = [];
851
+ const directDependencies = [];
651
852
  for (const entry of imports) {
652
853
  const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.id));
653
854
  importLines.push(`import { templates as ${entry.importName} } from '${importPath}'`);
654
- dependencies.push(entry.id);
855
+ addDependency(entry.id, dependencyContext, directDependencies);
655
856
  }
656
857
  for (const entry of includes) {
657
858
  const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.id));
658
859
  importLines.push(`import { render as ${entry.importName} } from '${importPath}'`);
659
- dependencies.push(entry.id);
860
+ addDependency(entry.id, dependencyContext, directDependencies);
660
861
  }
661
862
  for (const entry of wxs) {
662
863
  if (entry.kind === "src") {
663
- const importPath = normalizeTemplatePath(toRelativeImport(options.id, entry.value));
864
+ const baseImport = normalizeTemplatePath(toRelativeImport(options.id, entry.value));
865
+ const importPath = shouldMarkWxsImport(entry.value) ? `${baseImport}?wxs` : baseImport;
664
866
  importLines.push(`import ${entry.importName} from '${importPath}'`);
665
- dependencies.push(entry.value);
867
+ addDependency(entry.value, dependencyContext, directDependencies);
666
868
  }
667
869
  }
668
870
  if (templates.length > 0 || imports.length > 0) {
@@ -718,7 +920,14 @@ function compileWxml(options) {
718
920
  bodyLines.push(`}`);
719
921
  bodyLines.push(`export const templates = __templates`);
720
922
  bodyLines.push(`export default render`);
923
+ if (expandDependencies) {
924
+ dependencyContext.visited.add(options.id);
925
+ dependencyContext.active.add(options.id);
926
+ expandDependencyTree(directDependencies, options.id);
927
+ dependencyContext.active.delete(options.id);
928
+ }
721
929
  const code = [...importLines, "", ...bodyLines].join("\n");
930
+ const dependencies = expandDependencies ? dependencyContext.dependencies : directDependencies;
722
931
  return {
723
932
  code,
724
933
  dependencies,
@@ -727,37 +936,78 @@ function compileWxml(options) {
727
936
  }
728
937
 
729
938
  // src/compiler/wxs.ts
730
- var REQUIRE_RE = /require\\(\\s*['"]([^'"]+)['"]\\s*\\)/g;
939
+ var REQUIRE_RE = /require\(\s*['"]([^'"]+)['"]\s*\)/g;
731
940
  function normalizePath(p) {
732
941
  return p.split("\\\\").join("/");
733
942
  }
734
- function ensureWxsExtension(pathname) {
735
- if (pathname.endsWith(".wxs") || pathname.endsWith(".wxs.ts") || pathname.endsWith(".wxs.js")) {
943
+ function isPlainWxsScript(pathname) {
944
+ const lower = pathname.toLowerCase();
945
+ if (lower.endsWith(".wxs") || lower.endsWith(".wxs.ts") || lower.endsWith(".wxs.js")) {
946
+ return false;
947
+ }
948
+ return lower.endsWith(".ts") || lower.endsWith(".js");
949
+ }
950
+ function appendWxsQuery(pathname) {
951
+ if (pathname.includes("?wxs") || pathname.includes("&wxs")) {
736
952
  return pathname;
737
953
  }
738
- return `${pathname}.wxs`;
954
+ return `${pathname}${pathname.includes("?") ? "&" : "?"}wxs`;
955
+ }
956
+ function isSupportedRequirePath(request) {
957
+ const normalized = request.replace(/\\/g, "/");
958
+ return normalized.startsWith(".") || normalized.startsWith("/");
739
959
  }
740
960
  function transformWxsToEsm(code, id, options) {
741
961
  const dependencies = [];
742
962
  const importLines = [];
743
963
  const mapEntries = [];
744
- let match;
964
+ const warnings = [];
745
965
  const seen = /* @__PURE__ */ new Set();
746
- while (match = REQUIRE_RE.exec(code)) {
966
+ while (true) {
967
+ const match = REQUIRE_RE.exec(code);
968
+ if (!match) {
969
+ break;
970
+ }
747
971
  const request = match[1];
748
972
  if (!request || seen.has(request)) {
749
973
  continue;
750
974
  }
751
975
  seen.add(request);
752
- const resolved = ensureWxsExtension(options.resolvePath(request, id) ?? request);
753
- const importPath = normalizePath(options.toImportPath?.(resolved, id) ?? resolved);
976
+ if (!isSupportedRequirePath(request)) {
977
+ warnings.push(`[@weapp-vite/web] WXS require \u4EC5\u652F\u6301\u76F8\u5BF9\u6216\u7EDD\u5BF9\u8DEF\u5F84: ${request} (from ${id})`);
978
+ continue;
979
+ }
980
+ const normalizedRequest = request.replace(/\\/g, "/");
981
+ const resolved = options.resolvePath(normalizedRequest, id);
982
+ if (!resolved) {
983
+ warnings.push(`[@weapp-vite/web] \u65E0\u6CD5\u89E3\u6790 WXS require: ${request} (from ${id})`);
984
+ continue;
985
+ }
986
+ let importPath = normalizePath(options.toImportPath?.(resolved, id) ?? resolved);
987
+ if (isPlainWxsScript(resolved)) {
988
+ importPath = appendWxsQuery(importPath);
989
+ }
754
990
  const importName = `__wxs_dep_${dependencies.length}`;
755
991
  importLines.push(`import ${importName} from '${importPath}'`);
756
992
  mapEntries.push(`[${JSON.stringify(request)}, ${importName}]`);
757
993
  dependencies.push(resolved);
758
994
  }
759
995
  const requireMap = `const __wxs_require_map = new Map([${mapEntries.join(", ")}])`;
760
- const requireFn = `function require(id) { return __wxs_require_map.get(id) }`;
996
+ const requireFn = [
997
+ `const __wxs_require_warned = new Set()`,
998
+ `function require(id) {`,
999
+ ` if (__wxs_require_map.has(id)) {`,
1000
+ ` return __wxs_require_map.get(id)`,
1001
+ ` }`,
1002
+ ` if (!__wxs_require_warned.has(id)) {`,
1003
+ ` __wxs_require_warned.add(id)`,
1004
+ ` if (typeof console !== 'undefined' && typeof console.warn === 'function') {`,
1005
+ ` console.warn(\`[@weapp-vite/web] WXS require \u672A\u89E3\u6790: \${id}\`)`,
1006
+ ` }`,
1007
+ ` }`,
1008
+ ` return undefined`,
1009
+ `}`
1010
+ ].join("\\n");
761
1011
  const moduleInit = `const module = { exports: {} }\\nconst exports = module.exports`;
762
1012
  const helpers = `const getRegExp = (pattern, flags) => new RegExp(pattern, flags)\\nconst getDate = (value) => (value == null ? new Date() : new Date(value))`;
763
1013
  const body = [
@@ -769,7 +1019,11 @@ function transformWxsToEsm(code, id, options) {
769
1019
  code,
770
1020
  `export default module.exports`
771
1021
  ].join("\\n");
772
- return { code: body, dependencies };
1022
+ return {
1023
+ code: body,
1024
+ dependencies,
1025
+ warnings: warnings.length > 0 ? warnings : void 0
1026
+ };
773
1027
  }
774
1028
 
775
1029
  // src/shared/slugify.ts
@@ -801,6 +1055,7 @@ var STYLE_EXTS = [".wxss", ".scss", ".less", ".css"];
801
1055
  var TRANSFORM_STYLE_EXTS = [".wxss"];
802
1056
  var TEMPLATE_EXTS = [".wxml", ".axml", ".swan", ".ttml", ".qml", ".ksml", ".xhsml", ".html"];
803
1057
  var WXS_EXTS = [".wxs", ".wxs.ts", ".wxs.js"];
1058
+ var WXS_RESOLVE_EXTS = [".wxs", ".wxs.ts", ".wxs.js", ".ts", ".js"];
804
1059
  var ENTRY_ID = "\0@weapp-vite/web/entry";
805
1060
  function isTemplateFile(id) {
806
1061
  const lower = id.toLowerCase();
@@ -810,6 +1065,9 @@ function isWxsFile(id) {
810
1065
  const lower = id.toLowerCase();
811
1066
  return WXS_EXTS.some((ext) => lower.endsWith(ext));
812
1067
  }
1068
+ function hasWxsQuery(id) {
1069
+ return id.includes("?wxs") || id.includes("&wxs");
1070
+ }
813
1071
  function weappWebPlugin(options = {}) {
814
1072
  let root = process.cwd();
815
1073
  let srcRoot = resolve(root, options.srcDir ?? "src");
@@ -817,6 +1075,7 @@ function weappWebPlugin(options = {}) {
817
1075
  const moduleMeta = /* @__PURE__ */ new Map();
818
1076
  const pageNavigationMap = /* @__PURE__ */ new Map();
819
1077
  const templateComponentMap = /* @__PURE__ */ new Map();
1078
+ const templatePathSet = /* @__PURE__ */ new Set();
820
1079
  const componentTagMap = /* @__PURE__ */ new Map();
821
1080
  const componentIdMap = /* @__PURE__ */ new Map();
822
1081
  let appNavigationDefaults = {};
@@ -862,7 +1121,18 @@ function weappWebPlugin(options = {}) {
862
1121
  transform(code, id) {
863
1122
  const clean = cleanUrl(id);
864
1123
  if (isTemplateFile(clean)) {
1124
+ if (isHtmlEntry(clean, root)) {
1125
+ return null;
1126
+ }
865
1127
  const normalizedId = normalizePath2(clean);
1128
+ if (templatePathSet.size > 0) {
1129
+ if (!isInsideDir(clean, srcRoot)) {
1130
+ return null;
1131
+ }
1132
+ if (!templatePathSet.has(normalizedId)) {
1133
+ return null;
1134
+ }
1135
+ }
866
1136
  const navigationConfig = pageNavigationMap.get(normalizedId);
867
1137
  const componentTags = templateComponentMap.get(normalizedId);
868
1138
  const { code: compiled, dependencies, warnings } = compileWxml({
@@ -885,8 +1155,8 @@ function weappWebPlugin(options = {}) {
885
1155
  }
886
1156
  return { code: compiled, map: null };
887
1157
  }
888
- if (isWxsFile(clean)) {
889
- const { code: compiled, dependencies } = transformWxsToEsm(code, clean, {
1158
+ if (isWxsFile(clean) || hasWxsQuery(id)) {
1159
+ const { code: compiled, dependencies, warnings } = transformWxsToEsm(code, clean, {
890
1160
  resolvePath: resolveWxsPath,
891
1161
  toImportPath: (resolved, importer) => normalizePath2(toRelativeImport2(importer, resolved))
892
1162
  });
@@ -895,6 +1165,11 @@ function weappWebPlugin(options = {}) {
895
1165
  this.addWatchFile(dep);
896
1166
  }
897
1167
  }
1168
+ if (warnings?.length && "warn" in this) {
1169
+ for (const warning of warnings) {
1170
+ this.warn(warning);
1171
+ }
1172
+ }
898
1173
  return { code: compiled, map: null };
899
1174
  }
900
1175
  if (TRANSFORM_STYLE_EXTS.some((ext) => clean.endsWith(ext))) {
@@ -1029,6 +1304,7 @@ if (import.meta.hot) { import.meta.hot.accept() }
1029
1304
  moduleMeta.clear();
1030
1305
  pageNavigationMap.clear();
1031
1306
  templateComponentMap.clear();
1307
+ templatePathSet.clear();
1032
1308
  componentTagMap.clear();
1033
1309
  componentIdMap.clear();
1034
1310
  appNavigationDefaults = {};
@@ -1040,7 +1316,9 @@ if (import.meta.hot) { import.meta.hot.accept() }
1040
1316
  warn(message);
1041
1317
  return;
1042
1318
  }
1043
- console.warn(message);
1319
+ if (typeof process !== "undefined" && typeof process.emitWarning === "function") {
1320
+ process.emitWarning(message);
1321
+ }
1044
1322
  };
1045
1323
  const appScript = await resolveScriptFile(join(srcRoot, "app"));
1046
1324
  if (appScript) {
@@ -1054,8 +1332,9 @@ if (import.meta.hot) { import.meta.hot.accept() }
1054
1332
  }
1055
1333
  );
1056
1334
  }
1057
- const appJsonPath = join(srcRoot, "app.json");
1058
- if (await fs.pathExists(appJsonPath)) {
1335
+ const appJsonBasePath = join(srcRoot, "app.json");
1336
+ const appJsonPath = await resolveJsonPath(appJsonBasePath);
1337
+ if (appJsonPath) {
1059
1338
  const appJson = await readJsonFile(appJsonPath);
1060
1339
  if (appJson) {
1061
1340
  appComponentTags = await collectComponentTagsFromConfig(appJson, srcRoot, appJsonPath, reportWarning, (tags) => {
@@ -1102,9 +1381,13 @@ if (import.meta.hot) { import.meta.hot.accept() }
1102
1381
  return;
1103
1382
  }
1104
1383
  const template = await resolveTemplateFile(base);
1384
+ if (template) {
1385
+ templatePathSet.add(normalizePath2(template));
1386
+ }
1105
1387
  const style = await resolveStyleFile(base);
1106
- const pageJsonPath = join(srcRoot, `${pageId}.json`);
1107
- const pageJson = await readJsonFile(pageJsonPath);
1388
+ const pageJsonBasePath = join(srcRoot, `${pageId}.json`);
1389
+ const pageJsonPath = await resolveJsonPath(pageJsonBasePath);
1390
+ const pageJson = pageJsonPath ? await readJsonFile(pageJsonPath) : void 0;
1108
1391
  moduleMeta.set(
1109
1392
  normalizePath2(script),
1110
1393
  {
@@ -1119,7 +1402,7 @@ if (import.meta.hot) { import.meta.hot.accept() }
1119
1402
  script,
1120
1403
  id: toPosixId(pageId)
1121
1404
  });
1122
- const pageComponentTags = pageJson ? await collectComponentTagsFromConfig(pageJson, dirname2(script), pageJsonPath, reportWarning) : await collectComponentTagsFromJson(pageJsonPath, dirname2(script), reportWarning);
1405
+ const pageComponentTags = pageJson && pageJsonPath ? await collectComponentTagsFromConfig(pageJson, dirname2(script), pageJsonPath, reportWarning) : await collectComponentTagsFromJson(pageJsonBasePath, dirname2(script), reportWarning);
1123
1406
  if (template) {
1124
1407
  const mergedTags = mergeComponentTags(appComponentTags, pageComponentTags);
1125
1408
  if (Object.keys(mergedTags).length > 0) {
@@ -1149,6 +1432,9 @@ if (import.meta.hot) { import.meta.hot.accept() }
1149
1432
  const idRelative = relative2(srcRoot, script).replace(new RegExp(`${extname(script)}$`), "");
1150
1433
  const componentIdPosix = toPosixId(idRelative);
1151
1434
  const template = await resolveTemplateFile(script);
1435
+ if (template) {
1436
+ templatePathSet.add(normalizePath2(template));
1437
+ }
1152
1438
  const style = await resolveStyleFile(script);
1153
1439
  moduleMeta.set(
1154
1440
  normalizePath2(script),
@@ -1164,8 +1450,8 @@ if (import.meta.hot) { import.meta.hot.accept() }
1164
1450
  script,
1165
1451
  id: componentIdPosix
1166
1452
  });
1167
- const componentJsonPath = `${script.replace(new RegExp(`${extname(script)}$`), "")}.json`;
1168
- const componentTags = await collectComponentTagsFromJson(componentJsonPath, dirname2(script), reportWarning);
1453
+ const componentJsonBasePath = `${script.replace(new RegExp(`${extname(script)}$`), "")}.json`;
1454
+ const componentTags = await collectComponentTagsFromJson(componentJsonBasePath, dirname2(script), reportWarning);
1169
1455
  if (template) {
1170
1456
  const mergedTags = mergeComponentTags(appComponentTags, componentTags);
1171
1457
  if (Object.keys(mergedTags).length > 0) {
@@ -1207,12 +1493,16 @@ if (import.meta.hot) { import.meta.hot.accept() }
1207
1493
  }
1208
1494
  return tags;
1209
1495
  }
1210
- async function collectComponentTagsFromJson(jsonPath, importerDir, warn2) {
1211
- const json = await readJsonFile(jsonPath);
1496
+ async function collectComponentTagsFromJson(jsonBasePath, importerDir, warn2) {
1497
+ const resolvedPath = await resolveJsonPath(jsonBasePath);
1498
+ if (!resolvedPath) {
1499
+ return {};
1500
+ }
1501
+ const json = await readJsonFile(resolvedPath);
1212
1502
  if (!json) {
1213
1503
  return {};
1214
1504
  }
1215
- return collectComponentTagsFromConfig(json, importerDir, jsonPath, warn2);
1505
+ return collectComponentTagsFromConfig(json, importerDir, resolvedPath, warn2);
1216
1506
  }
1217
1507
  function mergeComponentTags(base, overrides) {
1218
1508
  if (!Object.keys(base).length && !Object.keys(overrides).length) {
@@ -1278,14 +1568,44 @@ function isRecord(value) {
1278
1568
  return typeof value === "object" && value !== null && !Array.isArray(value);
1279
1569
  }
1280
1570
  async function readJsonFile(pathname) {
1281
- if (!await fs.pathExists(pathname)) {
1282
- return void 0;
1571
+ const candidates = [pathname];
1572
+ if (pathname.endsWith(".json")) {
1573
+ candidates.push(`${pathname}.ts`, `${pathname}.js`);
1283
1574
  }
1284
- const json = await fs.readJson(pathname).catch(() => void 0);
1285
- if (!isRecord(json)) {
1286
- return void 0;
1575
+ for (const candidate of candidates) {
1576
+ if (!await fs.pathExists(candidate)) {
1577
+ continue;
1578
+ }
1579
+ if (candidate.endsWith(".json")) {
1580
+ const json = await fs.readJson(candidate).catch(() => void 0);
1581
+ if (!isRecord(json)) {
1582
+ return void 0;
1583
+ }
1584
+ return json;
1585
+ }
1586
+ const { mod } = await bundleRequire({
1587
+ filepath: candidate,
1588
+ preserveTemporaryFile: true
1589
+ });
1590
+ const resolved = typeof mod.default === "function" ? await mod.default() : mod.default;
1591
+ if (!isRecord(resolved)) {
1592
+ return void 0;
1593
+ }
1594
+ return resolved;
1595
+ }
1596
+ return void 0;
1597
+ }
1598
+ async function resolveJsonPath(basePath) {
1599
+ const candidates = [basePath];
1600
+ if (basePath.endsWith(".json")) {
1601
+ candidates.push(`${basePath}.ts`, `${basePath}.js`);
1602
+ }
1603
+ for (const candidate of candidates) {
1604
+ if (await fs.pathExists(candidate)) {
1605
+ return candidate;
1606
+ }
1287
1607
  }
1288
- return json;
1608
+ return void 0;
1289
1609
  }
1290
1610
  function pickNavigationConfig(source) {
1291
1611
  const config = {};
@@ -1315,6 +1635,16 @@ function mergeNavigationConfig(base, overrides) {
1315
1635
  function normalizePath2(p) {
1316
1636
  return posix.normalize(p.split("\\").join("/"));
1317
1637
  }
1638
+ function isInsideDir(filePath, dir) {
1639
+ const rel = relative2(dir, filePath);
1640
+ return rel === "" || !rel.startsWith("..") && !posix.isAbsolute(rel);
1641
+ }
1642
+ function isHtmlEntry(filePath, root) {
1643
+ if (!filePath.toLowerCase().endsWith(".html")) {
1644
+ return false;
1645
+ }
1646
+ return normalizePath2(filePath) === normalizePath2(resolve(root, "index.html"));
1647
+ }
1318
1648
  function resolveImportBase(raw, importer, srcRoot) {
1319
1649
  if (!raw) {
1320
1650
  return void 0;
@@ -1347,11 +1677,18 @@ function resolveTemplatePathSync(raw, importer, srcRoot) {
1347
1677
  return resolveFileWithExtensionsSync(base, TEMPLATE_EXTS);
1348
1678
  }
1349
1679
  function resolveWxsPathSync(raw, importer, srcRoot) {
1350
- const base = resolveImportBase(raw, importer, srcRoot);
1351
- if (!base) {
1680
+ if (!raw) {
1681
+ return void 0;
1682
+ }
1683
+ let base;
1684
+ if (raw.startsWith(".")) {
1685
+ base = resolve(dirname2(importer), raw);
1686
+ } else if (raw.startsWith("/")) {
1687
+ base = resolve(srcRoot, raw.slice(1));
1688
+ } else {
1352
1689
  return void 0;
1353
1690
  }
1354
- return resolveFileWithExtensionsSync(base, WXS_EXTS);
1691
+ return resolveFileWithExtensionsSync(base, WXS_RESOLVE_EXTS);
1355
1692
  }
1356
1693
  async function resolveScriptFile(basePath) {
1357
1694
  const ext = extname(basePath);
@@ -2143,7 +2480,7 @@ function normalizeKey(rawKey, item, index, scope) {
2143
2480
  const expr = key.replace(/^\{\{\s*/, "").replace(/\s*\}\}$/, "");
2144
2481
  return evaluateExpression(expr, scope);
2145
2482
  }
2146
- if (!/[\.\[\(\)]/.test(key) && item && typeof item === "object" && key in item) {
2483
+ if (!/[.[()]/.test(key) && item && typeof item === "object" && key in item) {
2147
2484
  return item[key];
2148
2485
  }
2149
2486
  return evaluateExpression(key, scope);
@@ -2192,6 +2529,16 @@ function createWxsModule(code, id, requireMap) {
2192
2529
  return module.exports;
2193
2530
  }
2194
2531
  function createRenderContext(instance, methods) {
2532
+ const warnedTemplates = /* @__PURE__ */ new Set();
2533
+ const warnMissingTemplate = (name) => {
2534
+ if (warnedTemplates.has(name)) {
2535
+ return;
2536
+ }
2537
+ warnedTemplates.add(name);
2538
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
2539
+ console.warn(`[@weapp-vite/web] \u672A\u627E\u5230\u6A21\u677F: ${name}`);
2540
+ }
2541
+ };
2195
2542
  return {
2196
2543
  instance,
2197
2544
  eval: (expression, scope, wxs) => {
@@ -2214,11 +2561,10 @@ function createRenderContext(instance, methods) {
2214
2561
  return normalizeKey(rawKey, item, index, renderScope);
2215
2562
  },
2216
2563
  renderTemplate: (templates, name, scope, ctx) => {
2217
- if (!name) {
2218
- return "";
2219
- }
2220
- const template = templates?.[name];
2564
+ const resolvedName = typeof name === "string" ? name : String(name);
2565
+ const template = templates?.[resolvedName];
2221
2566
  if (typeof template !== "function") {
2567
+ warnMissingTemplate(resolvedName);
2222
2568
  return "";
2223
2569
  }
2224
2570
  return template(scope, ctx);
@@ -2327,6 +2673,78 @@ function coerceValue(value, type) {
2327
2673
  }
2328
2674
  return value;
2329
2675
  }
2676
+ function isPlainObject(value) {
2677
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2678
+ }
2679
+ function mergeLifetimes(target, source) {
2680
+ if (!source) {
2681
+ return;
2682
+ }
2683
+ const keys = ["created", "attached", "ready", "detached"];
2684
+ for (const key of keys) {
2685
+ const next = source[key];
2686
+ if (!next) {
2687
+ continue;
2688
+ }
2689
+ const current = target[key];
2690
+ target[key] = current ? function merged() {
2691
+ current.call(this);
2692
+ next.call(this);
2693
+ } : next;
2694
+ }
2695
+ }
2696
+ function normalizeBehaviors(component) {
2697
+ if (!component) {
2698
+ return { component: void 0, warnings: [] };
2699
+ }
2700
+ const warnings = [];
2701
+ const visited = /* @__PURE__ */ new Set();
2702
+ const merged = {};
2703
+ const mergeComponent = (source) => {
2704
+ if (source.properties) {
2705
+ merged.properties = { ...merged.properties ?? {}, ...source.properties };
2706
+ }
2707
+ if (source.data) {
2708
+ const nextData = typeof source.data === "function" ? source.data() : source.data;
2709
+ if (isPlainObject(nextData)) {
2710
+ merged.data = { ...merged.data ?? {}, ...nextData };
2711
+ }
2712
+ }
2713
+ if (source.methods) {
2714
+ merged.methods = { ...merged.methods ?? {}, ...source.methods };
2715
+ }
2716
+ if (source.lifetimes) {
2717
+ merged.lifetimes = merged.lifetimes ?? {};
2718
+ mergeLifetimes(merged.lifetimes, source.lifetimes);
2719
+ }
2720
+ };
2721
+ const walk = (source) => {
2722
+ if (visited.has(source)) {
2723
+ warnings.push("[@weapp-vite/web] behaviors \u5B58\u5728\u5FAA\u73AF\u5F15\u7528\uFF0C\u5DF2\u8DF3\u8FC7\u3002");
2724
+ return;
2725
+ }
2726
+ visited.add(source);
2727
+ const behaviors = source.behaviors ?? [];
2728
+ if (Array.isArray(behaviors)) {
2729
+ for (const behavior of behaviors) {
2730
+ if (!behavior || !isPlainObject(behavior)) {
2731
+ warnings.push("[@weapp-vite/web] behaviors \u4EC5\u652F\u6301\u5BF9\u8C61\uFF0C\u5DF2\u5FFD\u7565\u975E\u5BF9\u8C61\u6761\u76EE\u3002");
2732
+ continue;
2733
+ }
2734
+ walk(behavior);
2735
+ mergeComponent(behavior);
2736
+ }
2737
+ } else if (behaviors) {
2738
+ warnings.push("[@weapp-vite/web] behaviors \u4EC5\u652F\u6301\u6570\u7EC4\uFF0C\u5DF2\u5FFD\u7565\u3002");
2739
+ }
2740
+ };
2741
+ walk(component);
2742
+ mergeComponent(component);
2743
+ return {
2744
+ component: merged,
2745
+ warnings
2746
+ };
2747
+ }
2330
2748
  function defineComponent(tagName, options) {
2331
2749
  if (!options || typeof options !== "object") {
2332
2750
  throw new TypeError("[@weapp-vite/web] defineComponent \u9700\u8981\u63D0\u4F9B\u914D\u7F6E\u5BF9\u8C61\u3002");
@@ -2337,13 +2755,20 @@ function defineComponent(tagName, options) {
2337
2755
  return existing;
2338
2756
  }
2339
2757
  const BaseElement3 = supportsLit ? LitElement : globalThis.HTMLElement ?? FallbackElement;
2340
- const { template, style = "", component = {} } = options;
2758
+ const { template, style = "", component = {}, observerInit = false } = options;
2341
2759
  if (!template) {
2342
2760
  throw new Error("[@weapp-vite/web] defineComponent \u9700\u8981\u63D0\u4F9B\u6A21\u677F\u6E32\u67D3\u51FD\u6570\u3002");
2343
2761
  }
2762
+ const normalized = normalizeBehaviors(component);
2763
+ for (const warning of normalized.warnings) {
2764
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
2765
+ console.warn(warning);
2766
+ }
2767
+ }
2344
2768
  let templateRef = template;
2345
2769
  let styleRef = style;
2346
- let componentRef = component;
2770
+ let componentRef = normalized.component ?? component;
2771
+ let observerInitEnabled = Boolean(observerInit);
2347
2772
  let propertyEntries = Object.entries(componentRef.properties ?? {});
2348
2773
  let observedAttributes = propertyEntries.map(([name]) => hyphenate(name));
2349
2774
  let defaultPropertyValues = propertyEntries.reduce((acc, [name, prop]) => {
@@ -2367,6 +2792,8 @@ function defineComponent(tagName, options) {
2367
2792
  #renderContext = createRenderContext(this, {});
2368
2793
  #usesLegacyTemplate = false;
2369
2794
  #readyFired = false;
2795
+ #observerInitDone = false;
2796
+ #observedKeys = /* @__PURE__ */ new Set();
2370
2797
  constructor() {
2371
2798
  super();
2372
2799
  const dataOption = typeof componentRef.data === "function" ? componentRef.data() : componentRef.data ?? {};
@@ -2417,6 +2844,9 @@ function defineComponent(tagName, options) {
2417
2844
  superConnected.call(this);
2418
2845
  }
2419
2846
  this.#applyAttributes();
2847
+ if (observerInitEnabled) {
2848
+ this.#runInitialObservers();
2849
+ }
2420
2850
  lifetimes.attached?.call(this);
2421
2851
  this.#isMounted = true;
2422
2852
  if (!supportsLit) {
@@ -2497,7 +2927,11 @@ function defineComponent(tagName, options) {
2497
2927
  this.#state[key] = value;
2498
2928
  if (Object.prototype.hasOwnProperty.call(this.#properties, key)) {
2499
2929
  this.#properties[key] = value;
2500
- componentRef.properties?.[key]?.observer?.call(this, value, oldValue);
2930
+ const propOption = componentRef.properties?.[key];
2931
+ if (propOption?.observer) {
2932
+ propOption.observer.call(this, value, oldValue);
2933
+ this.#observedKeys.add(key);
2934
+ }
2501
2935
  }
2502
2936
  changed = true;
2503
2937
  }
@@ -2518,7 +2952,24 @@ function defineComponent(tagName, options) {
2518
2952
  if (this.#isMounted) {
2519
2953
  this.requestUpdate();
2520
2954
  }
2521
- propOption?.observer?.call(this, coerced, oldValue);
2955
+ if (propOption?.observer) {
2956
+ propOption.observer.call(this, coerced, oldValue);
2957
+ this.#observedKeys.add(name);
2958
+ }
2959
+ }
2960
+ #runInitialObservers() {
2961
+ if (this.#observerInitDone) {
2962
+ return;
2963
+ }
2964
+ this.#observerInitDone = true;
2965
+ for (const [propName, propOption] of propertyEntries) {
2966
+ if (!propOption.observer || this.#observedKeys.has(propName)) {
2967
+ continue;
2968
+ }
2969
+ const value = this.#state[propName];
2970
+ propOption.observer.call(this, value, void 0);
2971
+ this.#observedKeys.add(propName);
2972
+ }
2522
2973
  }
2523
2974
  #syncMethods(nextMethods) {
2524
2975
  const resolved = nextMethods ?? {};
@@ -2566,7 +3017,14 @@ function defineComponent(tagName, options) {
2566
3017
  }
2567
3018
  templateRef = nextOptions.template;
2568
3019
  styleRef = nextOptions.style ?? "";
2569
- componentRef = nextOptions.component ?? {};
3020
+ const nextNormalized = normalizeBehaviors(nextOptions.component ?? {});
3021
+ for (const warning of nextNormalized.warnings) {
3022
+ if (typeof console !== "undefined" && typeof console.warn === "function") {
3023
+ console.warn(warning);
3024
+ }
3025
+ }
3026
+ componentRef = nextNormalized.component ?? nextOptions.component ?? {};
3027
+ observerInitEnabled = Boolean(nextOptions.observerInit);
2570
3028
  lifetimes = componentRef.lifetimes ?? {};
2571
3029
  propertyEntries = Object.entries(componentRef.properties ?? {});
2572
3030
  observedAttributes = propertyEntries.map(([name]) => hyphenate(name));
@@ -3496,6 +3954,8 @@ function normalizeTagName2(name) {
3496
3954
  return "select";
3497
3955
  case "block":
3498
3956
  return "#fragment";
3957
+ case "slot":
3958
+ return "slot";
3499
3959
  default:
3500
3960
  return name || "div";
3501
3961
  }