@open-wxa/wxa-runner-core 0.9.0 → 0.10.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.
@@ -8,11 +8,15 @@
8
8
  var MINI_PROGRAM_ERROR = /^(\(in promise\) )?MiniProgramError\n/;
9
9
  var MODULE_URL = /\bhttps?:\/\/[^/\s]+\/__wxa__\/module\/([^?\s)]+?)(?:\?[^:\s)]*)?:(\d+):(\d+)/;
10
10
  var ConsoleForwarder = class {
11
- /** @param pageOf 出错的页面路径,不知道时返回 undefined */
12
- constructor(mode, send, pageOf) {
11
+ /**
12
+ * @param pageOf 出错的页面路径,不知道时返回 undefined
13
+ * @param hintsOf 附在报错后面的提示,帮开发者认出 wxa-runner 和真机不同造成的错误
14
+ */
15
+ constructor(mode, send, pageOf, hintsOf = () => []) {
13
16
  this.mode = mode;
14
17
  this.send = send;
15
18
  this.pageOf = pageOf;
19
+ this.hintsOf = hintsOf;
16
20
  this.recentErrors = /* @__PURE__ */ new Map();
17
21
  }
18
22
  /** 运行时错误:全局 error、未处理的 Promise 拒绝、基础库捕获的业务代码错误 */
@@ -20,8 +24,10 @@
20
24
  const frames = businessFrames(stack);
21
25
  if (!this.mode || this.isRepeated(`${kind}:${webviewId}:${message}
22
26
  ${frames}`)) return;
27
+ const hints = this.hintsOf(kind).map((hint) => `
28
+ \u63D0\u793A\uFF1A${hint}`).join("");
23
29
  this.post("error", `${this.origin(kind, webviewId)}\u62A5\u9519\uFF1A${message}${frames ? `
24
- ${frames}` : ""}`);
30
+ ${frames}` : ""}${hints}`);
25
31
  }
26
32
  /** 运行时自己的提醒,如调用了未实现的 wx API */
27
33
  warn(text) {
@@ -1299,9 +1305,9 @@ ${frames}` : "");
1299
1305
  }
1300
1306
  function sleep(ms, signal) {
1301
1307
  return new Promise((resolve, reject) => {
1302
- if (signal?.aborted) return reject(signal.reason);
1308
+ if (signal.aborted) return reject(signal.reason);
1303
1309
  const timer = setTimeout(resolve, ms);
1304
- signal?.addEventListener("abort", () => {
1310
+ signal.addEventListener("abort", () => {
1305
1311
  clearTimeout(timer);
1306
1312
  reject(signal.reason);
1307
1313
  }, { once: true });
@@ -2144,6 +2150,29 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2144
2150
  }
2145
2151
  };
2146
2152
 
2153
+ // src/runtime/host/ui/tabBarView.ts
2154
+ function tabBarView(config, selectedPath) {
2155
+ return {
2156
+ background: config.backgroundColor || "#f7f7f7",
2157
+ borderTopColor: config.borderStyle === "white" ? "rgba(255,255,255,.3)" : "rgba(0,0,0,.1)",
2158
+ items: config.list.map((item) => itemView(config, item, item.pagePath === selectedPath))
2159
+ };
2160
+ }
2161
+ function itemView(config, item, selected) {
2162
+ const icon = selected ? item.selectedIconPath || item.iconPath : item.iconPath;
2163
+ return {
2164
+ pagePath: item.pagePath,
2165
+ selected,
2166
+ color: selected ? config.selectedColor || "#07c160" : config.color || "#7a7e83",
2167
+ icon: icon ? iconUrl(icon) : null,
2168
+ text: item.text || "",
2169
+ mark: item.mark || null
2170
+ };
2171
+ }
2172
+ function iconUrl(path) {
2173
+ return /^https?:\/\//.test(path) ? path : "/" + path.replace(/^\//, "");
2174
+ }
2175
+
2147
2176
  // src/runtime/host/ui/PhoneShell.ts
2148
2177
  var SCALE_STORAGE_KEY = "wxa-runner:scale";
2149
2178
  var MIN_SCALE = 0.5;
@@ -2324,29 +2353,27 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2324
2353
  const visible = this.tabBarVisible();
2325
2354
  this.tabBar.classList.toggle("is-hidden", !visible);
2326
2355
  if (!config || !visible) return;
2327
- this.tabBar.style.background = config.backgroundColor || "#f7f7f7";
2328
- this.tabBar.style.borderTopColor = config.borderStyle === "white" ? "rgba(255,255,255,.3)" : "rgba(0,0,0,.1)";
2329
- this.tabBar.innerHTML = "";
2330
- config.list.forEach((item, index) => {
2331
- const selected = item.pagePath === selectedPath;
2332
- const el = document.createElement("div");
2333
- el.className = "wxa-tabbar-item" + (selected ? " is-selected" : "");
2334
- el.dataset.pagePath = item.pagePath;
2335
- el.style.color = selected ? config.selectedColor || "#07c160" : config.color || "#7a7e83";
2336
- const icon = selected ? item.selectedIconPath || item.iconPath : item.iconPath;
2337
- const iconBox = element("span", "wxa-tabbar-icon");
2338
- if (icon) {
2339
- const img = document.createElement("img");
2340
- img.src = /^https?:\/\//.test(icon) ? icon : "/" + icon.replace(/^\//, "");
2341
- iconBox.appendChild(img);
2342
- el.appendChild(iconBox);
2343
- }
2344
- const text = element("span", "wxa-tabbar-text", item.text || "");
2345
- el.appendChild(text);
2346
- if (item.mark) (icon ? iconBox : text).appendChild(markElement(item.mark));
2347
- el.addEventListener("click", () => this.onTabTap(item.pagePath, index));
2348
- this.tabBar.appendChild(el);
2349
- });
2356
+ const view = tabBarView(config, selectedPath);
2357
+ this.tabBar.style.background = view.background;
2358
+ this.tabBar.style.borderTopColor = view.borderTopColor;
2359
+ this.tabBar.replaceChildren(...view.items.map((item, index) => this.tabBarItemElement(item, index)));
2360
+ }
2361
+ tabBarItemElement(item, index) {
2362
+ const el = element("div", "wxa-tabbar-item" + (item.selected ? " is-selected" : ""));
2363
+ el.dataset.pagePath = item.pagePath;
2364
+ el.style.color = item.color;
2365
+ const iconBox = element("span", "wxa-tabbar-icon");
2366
+ if (item.icon) {
2367
+ const img = document.createElement("img");
2368
+ img.src = item.icon;
2369
+ iconBox.appendChild(img);
2370
+ el.appendChild(iconBox);
2371
+ }
2372
+ const text = element("span", "wxa-tabbar-text", item.text);
2373
+ el.appendChild(text);
2374
+ if (item.mark) (item.icon ? iconBox : text).appendChild(markElement(item.mark));
2375
+ el.addEventListener("click", () => this.onTabTap(item.pagePath, index));
2376
+ return el;
2350
2377
  }
2351
2378
  tabBarVisible() {
2352
2379
  return this.tabBarPath !== null && this.hasTabBar(this.tabBarPath);
@@ -2547,7 +2574,8 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2547
2574
  this.forwarder = new ConsoleForwarder(
2548
2575
  info.forwardConsole ?? false,
2549
2576
  sendReport,
2550
- (kind, webviewId) => kind === "service" ? this.currentPage()?.path : this.pages.get(webviewId)?.path
2577
+ (kind, webviewId) => kind === "service" ? this.currentPage()?.path : this.pages.get(webviewId)?.path,
2578
+ (kind) => this.launchHints(kind)
2551
2579
  );
2552
2580
  this.shell = new PhoneShell(root, info.device);
2553
2581
  this.tabPaths = new Set((info.wxConfig.tabBar?.list || []).map((item) => stripHtml(item.pagePath)));
@@ -2698,6 +2726,13 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2698
2726
  this.errors.push({ kind: "service", webviewId: 0, api, message });
2699
2727
  this.forwarder.warn(message);
2700
2728
  }
2729
+ /**
2730
+ * 逻辑层在首页创建前出错时的提示:onLaunch、启动阶段的接口回调里读 getCurrentPages()[0] 是常见原因,
2731
+ * 而报错本身只说读不到某个属性。被拦截的请求立即返回,比真机更容易在首页创建前执行回调
2732
+ */
2733
+ launchHints(kind) {
2734
+ return kind === "service" && !this.currentPage() ? ["\u51FA\u9519\u65F6\u9996\u9875\u8FD8\u6CA1\u521B\u5EFA\uFF0CgetCurrentPages() \u8FD4\u56DE\u7684\u662F\u7A7A\u6570\u7EC4"] : [];
2735
+ }
2701
2736
  // ---------------------------------------------------------------------------
2702
2737
  // 路由
2703
2738
  // ---------------------------------------------------------------------------
@@ -2997,32 +3032,30 @@ html, body { margin: 0; height: 100%; background: radial-gradient(120% 80% at 50
2997
3032
 
2998
3033
  // src/runtime/host/hmr.ts
2999
3034
  async function applyHotUpdate(host, update) {
3000
- const hasTemplates = update.templates.length > 0;
3001
- const hasStyles = update.styles.length > 0;
3002
- const v = `?v=${update.version}`;
3003
- const [pageStyles, pageTemplates, serviceTemplates, moduleScripts] = await Promise.all([
3004
- hasStyles ? fetchText(`/__wxa__/page-styles.js${v}`) : "",
3005
- hasTemplates ? fetchText(`/__wxa__/page-templates.js${v}`) : "",
3006
- hasTemplates ? fetchText(`/__wxa__/service-templates.js${v}`) : "",
3007
- Promise.all(update.scripts.map((id) => fetchText(`/__wxa__/module/${encodeURI(id)}.js${v}`)))
3008
- ]);
3035
+ const code = await fetchHotCode(update);
3009
3036
  await host.enqueueRoute(async () => {
3010
3037
  const service = host.serviceWindow();
3011
3038
  if (!service?.__virtualDOM__?.updateWxAppCode) throw new Error("\u57FA\u7840\u5E93\u7684\u70ED\u66F4\u65B0\u5F00\u5173\u6CA1\u6709\u6253\u5F00");
3012
- if (hasStyles) {
3013
- for (const page of host.livePages()) {
3014
- if (page.win) updateStyles(page.win, pageStyles);
3015
- }
3039
+ const pageWindows = host.livePages().flatMap((page) => page.win ? [page.win] : []);
3040
+ if (code.pageStyles !== null) {
3041
+ for (const win of pageWindows) updateStyles(win, code.pageStyles);
3016
3042
  }
3017
- if (hasTemplates) {
3018
- for (const page of host.livePages()) {
3019
- if (page.win) updateTemplates(page.win, pageTemplates, update.templates);
3020
- }
3021
- updateTemplates(service, serviceTemplates, update.templates);
3043
+ if (code.templates) {
3044
+ for (const win of pageWindows) updateTemplates(win, code.templates.page, update.templates);
3045
+ updateTemplates(service, code.templates.service, update.templates);
3022
3046
  }
3023
- update.scripts.forEach((id, index) => updateScript(service, host, id, moduleScripts[index]));
3047
+ update.scripts.forEach((id, index) => updateScript(service, host, id, code.scripts[index]));
3024
3048
  });
3025
3049
  }
3050
+ async function fetchHotCode(update) {
3051
+ const v = `?v=${update.version}`;
3052
+ const [pageStyles, templates, scripts] = await Promise.all([
3053
+ update.styles.length > 0 ? fetchText(`/__wxa__/page-styles.js${v}`) : null,
3054
+ update.templates.length > 0 ? Promise.all([fetchText(`/__wxa__/page-templates.js${v}`), fetchText(`/__wxa__/service-templates.js${v}`)]).then(([page, service]) => ({ page, service })) : null,
3055
+ Promise.all(update.scripts.map((id) => fetchText(`/__wxa__/module/${encodeURI(id)}.js${v}`)))
3056
+ ]);
3057
+ return { pageStyles, templates, scripts };
3058
+ }
3026
3059
  function updateStyles(win, code) {
3027
3060
  const sheets = win.__styleSheetManager2__?._pathMap;
3028
3061
  if (!sheets) throw new Error("\u57FA\u7840\u5E93\u6CA1\u6709\u6837\u5F0F\u8868\u7BA1\u7406\u5668\uFF0C\u65E0\u6CD5\u70ED\u66FF\u6362\u6837\u5F0F");