@lark-apaas/coding-preset-vite-react 0.1.0

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.
Files changed (93) hide show
  1. package/LICENSE +13 -0
  2. package/lib/index.d.ts +52 -0
  3. package/lib/index.d.ts.map +1 -0
  4. package/lib/index.js +410 -0
  5. package/lib/index.js.map +1 -0
  6. package/lib/plugins/capabilities.d.ts +23 -0
  7. package/lib/plugins/capabilities.d.ts.map +1 -0
  8. package/lib/plugins/capabilities.js +151 -0
  9. package/lib/plugins/capabilities.js.map +1 -0
  10. package/lib/plugins/dev-logs.d.ts +44 -0
  11. package/lib/plugins/dev-logs.d.ts.map +1 -0
  12. package/lib/plugins/dev-logs.js +544 -0
  13. package/lib/plugins/dev-logs.js.map +1 -0
  14. package/lib/plugins/error-overlay.d.ts +19 -0
  15. package/lib/plugins/error-overlay.d.ts.map +1 -0
  16. package/lib/plugins/error-overlay.js +136 -0
  17. package/lib/plugins/error-overlay.js.map +1 -0
  18. package/lib/plugins/fonts-mirror.d.ts +14 -0
  19. package/lib/plugins/fonts-mirror.d.ts.map +1 -0
  20. package/lib/plugins/fonts-mirror.js +70 -0
  21. package/lib/plugins/fonts-mirror.js.map +1 -0
  22. package/lib/plugins/health.d.ts +19 -0
  23. package/lib/plugins/health.d.ts.map +1 -0
  24. package/lib/plugins/health.js +36 -0
  25. package/lib/plugins/health.js.map +1 -0
  26. package/lib/plugins/hmr-timing.d.ts +13 -0
  27. package/lib/plugins/hmr-timing.d.ts.map +1 -0
  28. package/lib/plugins/hmr-timing.js +93 -0
  29. package/lib/plugins/hmr-timing.js.map +1 -0
  30. package/lib/plugins/html-minify.d.ts +18 -0
  31. package/lib/plugins/html-minify.d.ts.map +1 -0
  32. package/lib/plugins/html-minify.js +100 -0
  33. package/lib/plugins/html-minify.js.map +1 -0
  34. package/lib/plugins/module-alias.d.ts +12 -0
  35. package/lib/plugins/module-alias.d.ts.map +1 -0
  36. package/lib/plugins/module-alias.js +78 -0
  37. package/lib/plugins/module-alias.js.map +1 -0
  38. package/lib/plugins/og-meta.d.ts +21 -0
  39. package/lib/plugins/og-meta.d.ts.map +1 -0
  40. package/lib/plugins/og-meta.js +60 -0
  41. package/lib/plugins/og-meta.js.map +1 -0
  42. package/lib/plugins/polyfill.d.ts +11 -0
  43. package/lib/plugins/polyfill.d.ts.map +1 -0
  44. package/lib/plugins/polyfill.js +140 -0
  45. package/lib/plugins/polyfill.js.map +1 -0
  46. package/lib/plugins/routes.d.ts +26 -0
  47. package/lib/plugins/routes.d.ts.map +1 -0
  48. package/lib/plugins/routes.js +265 -0
  49. package/lib/plugins/routes.js.map +1 -0
  50. package/lib/plugins/slardar.d.ts +24 -0
  51. package/lib/plugins/slardar.d.ts.map +1 -0
  52. package/lib/plugins/slardar.js +74 -0
  53. package/lib/plugins/slardar.js.map +1 -0
  54. package/lib/plugins/static-assets.d.ts +10 -0
  55. package/lib/plugins/static-assets.d.ts.map +1 -0
  56. package/lib/plugins/static-assets.js +297 -0
  57. package/lib/plugins/static-assets.js.map +1 -0
  58. package/lib/plugins/view-context.d.ts +22 -0
  59. package/lib/plugins/view-context.d.ts.map +1 -0
  60. package/lib/plugins/view-context.js +132 -0
  61. package/lib/plugins/view-context.js.map +1 -0
  62. package/lib/plugins/vite-client-patch.d.ts +4 -0
  63. package/lib/plugins/vite-client-patch.d.ts.map +1 -0
  64. package/lib/plugins/vite-client-patch.js +37 -0
  65. package/lib/plugins/vite-client-patch.js.map +1 -0
  66. package/lib/plugins/ws-watchdog.d.ts +22 -0
  67. package/lib/plugins/ws-watchdog.d.ts.map +1 -0
  68. package/lib/plugins/ws-watchdog.js +103 -0
  69. package/lib/plugins/ws-watchdog.js.map +1 -0
  70. package/lib/polyfills/index.d.ts +15 -0
  71. package/lib/polyfills/index.d.ts.map +1 -0
  72. package/lib/polyfills/index.js +36 -0
  73. package/lib/polyfills/index.js.map +1 -0
  74. package/lib/utils/normalize-base-path.d.ts +37 -0
  75. package/lib/utils/normalize-base-path.d.ts.map +1 -0
  76. package/lib/utils/normalize-base-path.js +57 -0
  77. package/lib/utils/normalize-base-path.js.map +1 -0
  78. package/lib/utils/snapdom-proxy.d.ts +12 -0
  79. package/lib/utils/snapdom-proxy.d.ts.map +1 -0
  80. package/lib/utils/snapdom-proxy.js +75 -0
  81. package/lib/utils/snapdom-proxy.js.map +1 -0
  82. package/package.json +63 -0
  83. package/src/empty.css +1 -0
  84. package/src/inspector-stub.js +6 -0
  85. package/src/module-alias/clsx.mjs +8 -0
  86. package/src/module-alias/echarts-for-react.mjs +130 -0
  87. package/src/module-alias/echarts.mjs +43 -0
  88. package/src/module-alias/registry_echarts_theme.mjs +390 -0
  89. package/src/overlay/components.js +94 -0
  90. package/src/overlay/index.js +443 -0
  91. package/src/overlay/vite-client.js +555 -0
  92. package/src/polyfills/index.ts +35 -0
  93. package/src/runtime/ws-watchdog-client.mjs +148 -0
@@ -0,0 +1,555 @@
1
+ /* eslint-disable */
2
+ /**
3
+ * Vite Error Overlay Client
4
+ *
5
+ * 自定义错误 overlay,替换 Vite 原生 overlay,与 rspack-preset 功能对齐。
6
+ *
7
+ * 功能:
8
+ * - 编译错误展示:监听 vite:error 事件,显示编译错误 overlay
9
+ * - 运行时错误展示:监听 window.error 和 unhandledrejection 事件
10
+ * - 错误修复检测:监听 vite:afterUpdate 事件,修复后自动刷新页面
11
+ * - PostMessage 通信:向父窗口发送 PreviewReady、RenderError 等消息
12
+ * - 错误上报:通过 __RUNTIME_LOGGER__ 或 postMessage 上报错误日志
13
+ *
14
+ * 实现原理:
15
+ * - 使用 iframe 隔离样式,避免影响应用样式
16
+ * - 通过 createHotContext 创建 HMR context 监听 Vite 事件
17
+ * - 使用 debounce 防止运行时错误频繁触发渲染
18
+ *
19
+ * 暴露的全局 API (window.__VITE_ERROR_OVERLAY__):
20
+ * - showCompileError(message: string): 显示编译错误
21
+ * - clearCompileError(shouldReload?: boolean): 清除编译错误
22
+ * - showRuntimeErrors(errors: Error[]): 显示运行时错误
23
+ * - clearRuntimeErrors(dismissOverlay?: boolean): 清除运行时错误
24
+ * - handleRuntimeError(error: Error): 处理单个运行时错误
25
+ *
26
+ * @see https://vite.dev/guide/api-hmr.html
27
+ */
28
+
29
+ // 防止重复初始化
30
+ if (!window.__VITE_ERROR_OVERLAY_INITIALIZED__) {
31
+ window.__VITE_ERROR_OVERLAY_INITIALIZED__ = true;
32
+
33
+ /* ===== Overlay Core (iframe) ===== */
34
+
35
+ let iframeRoot = null;
36
+ let rootDocument = null;
37
+ let root = null;
38
+ let scheduledRenderFn = null;
39
+
40
+ // Overlay State
41
+ let currentCompileErrorMessage = '';
42
+ let currentRuntimeErrors = [];
43
+ let currentMode = null;
44
+
45
+ // ===== HMR API State (用于 toolkit 的统一 HMR API) =====
46
+ let hasErrorInCurrentUpdate = false;
47
+ const hmrBeforeApplyCallbacks = new Set();
48
+ const hmrSuccessCallbacks = new Set();
49
+ const hmrErrorCallbacks = new Set();
50
+
51
+ // ===== Components =====
52
+ function ErrorContainer(doc, parentRoot, errorTitle) {
53
+ const container = doc.createElement('div');
54
+ container.className = 'overlay-container';
55
+
56
+ const content = doc.createElement('div');
57
+ content.className = 'overlay-content';
58
+ container.appendChild(content);
59
+
60
+ const img = doc.createElement('img');
61
+ img.src =
62
+ 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ylcylz_fsph_ryhs/ljhwZthlaukjlkulzlp/feisuda/template/illustration_empty_negative_error.svg';
63
+ img.alt = 'Error';
64
+ img.width = 100;
65
+ img.height = 100;
66
+ img.className = 'overlay-error-image';
67
+ content.appendChild(img);
68
+
69
+ const title = doc.createElement('p');
70
+ title.className = 'overlay-title';
71
+ title.textContent = errorTitle;
72
+ content.appendChild(title);
73
+
74
+ parentRoot.appendChild(container);
75
+ }
76
+
77
+ function RootStyle(doc, parentRoot) {
78
+ const style = doc.createElement('style');
79
+ style.id = 'vite-error-overlay-style';
80
+ style.textContent = `
81
+ * {
82
+ margin: 0;
83
+ padding: 0;
84
+ box-sizing: border-box;
85
+ }
86
+ body {
87
+ font-family: "PingFang SC", -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
88
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
89
+ sans-serif;
90
+ -webkit-font-smoothing: antialiased;
91
+ -moz-osx-font-smoothing: grayscale;
92
+ }
93
+ .overlay-container {
94
+ min-height: 100vh;
95
+ display: flex;
96
+ align-items: center;
97
+ justify-content: center;
98
+ background-color: #fff;
99
+ }
100
+ .overlay-content {
101
+ display: flex;
102
+ flex-direction: column;
103
+ justify-content: center;
104
+ align-items: center;
105
+ text-align: center;
106
+ }
107
+ .overlay-error-image {
108
+ margin-bottom: 12px;
109
+ width: 100px;
110
+ height: auto;
111
+ }
112
+ .overlay-title {
113
+ color: #1F2329;
114
+ text-align: center;
115
+ font-size: 14px;
116
+ font-style: normal;
117
+ font-weight: 500;
118
+ line-height: 22px;
119
+ }
120
+ `;
121
+ parentRoot.appendChild(style);
122
+ }
123
+
124
+ // ===== PostMessage 通信 (与 rspack 对齐) =====
125
+ function getParentOriginFromParams() {
126
+ try {
127
+ var params = new URLSearchParams(window.location.search);
128
+ var origin = params.get('__parentOrigin');
129
+ if (origin) {
130
+ sessionStorage.setItem('__parentOrigin', origin);
131
+ return origin;
132
+ }
133
+ } catch (e) {
134
+ // ignore
135
+ }
136
+ try {
137
+ return sessionStorage.getItem('__parentOrigin') || '';
138
+ } catch (e) {
139
+ return '';
140
+ }
141
+ }
142
+
143
+ function getLegacyParentOrigin() {
144
+ const currentOrigin = window.location?.origin || '';
145
+ if (currentOrigin.includes('force.feishuapp.net')) {
146
+ return 'https://force.feishu.cn';
147
+ }
148
+ if (currentOrigin.includes('force-pre.feishuapp.net')) {
149
+ return 'https://force.feishu-pre.cn';
150
+ }
151
+ if (currentOrigin.includes('force.byted.org')) {
152
+ return 'https://force.feishu-boe.cn';
153
+ }
154
+ if (currentOrigin.includes('feishuapp.cn') || currentOrigin.includes('miaoda.feishuapp.net')) {
155
+ return 'https://miaoda.feishu.cn';
156
+ }
157
+ if (currentOrigin.includes('fsapp.kundou.cn') || currentOrigin.includes('miaoda-pre.feishuapp.net')) {
158
+ return 'https://miaoda.feishu-pre.cn';
159
+ }
160
+ return 'https://miaoda.feishu-boe.cn';
161
+ }
162
+
163
+ function sendPostMessage(message, targetOrigin) {
164
+ try {
165
+ const parentOrigin = getParentOriginFromParams() || process.env.FORCE_FRAMEWORK_DOMAIN_MAIN || getLegacyParentOrigin();
166
+ const origin = targetOrigin || parentOrigin;
167
+ window.parent.postMessage(message, origin);
168
+ } catch (error) {
169
+ // ignore postMessage errors
170
+ }
171
+ }
172
+
173
+ // ===== 错误上报 (与 rspack 对齐) =====
174
+ function logError(messages, mode) {
175
+ const logMeta = {
176
+ noStacktrace: mode === 'compileError',
177
+ stacktrace: mode === 'compileError' ? [] : undefined,
178
+ type: mode === 'compileError' ? 'compile-error' : 'uncaught-render-error',
179
+ };
180
+ try {
181
+ // 优先使用暴露的 __RUNTIME_LOGGER__ 上报错误
182
+ if (window.__RUNTIME_LOGGER__) {
183
+ window.__RUNTIME_LOGGER__.get().log({
184
+ level: 'error',
185
+ args: messages,
186
+ meta: logMeta,
187
+ });
188
+ return;
189
+ }
190
+ // 首次执行编译报错会走此处逻辑
191
+ const parts = [];
192
+ for (const m of messages) {
193
+ if (m instanceof Error) {
194
+ parts.push(m.message, m);
195
+ } else {
196
+ parts.push(m);
197
+ }
198
+ }
199
+ const logJSON = {
200
+ id: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
201
+ const r = Math.random() * 16 | 0;
202
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
203
+ return v.toString(16);
204
+ }),
205
+ type: 'typedLogV2',
206
+ level: 'error',
207
+ args: parts,
208
+ meta: logMeta,
209
+ };
210
+ sendPostMessage({ type: 'SELECTED_LOG', payload: JSON.stringify(logJSON) });
211
+ } catch (e) {
212
+ // ignore log errors
213
+ }
214
+ }
215
+
216
+ // ===== Iframe Management =====
217
+ function IframeRoot(doc, parent, props) {
218
+ const iframe = doc.createElement('iframe');
219
+ iframe.id = 'vite-error-overlay';
220
+ iframe.src = 'about:blank';
221
+
222
+ iframe.style.border = 'none';
223
+ iframe.style.height = '100%';
224
+ iframe.style.left = '0';
225
+ iframe.style.minHeight = '100vh';
226
+ iframe.style.minHeight = '-webkit-fill-available';
227
+ iframe.style.position = 'fixed';
228
+ iframe.style.top = '0';
229
+ iframe.style.width = '100vw';
230
+ iframe.style.zIndex = '2147483647';
231
+
232
+ iframe.addEventListener('load', function onLoad() {
233
+ try {
234
+ iframe.contentDocument.body.style.margin = '0';
235
+ props.onIframeLoad();
236
+ } catch (error) {
237
+ // ignore
238
+ }
239
+ });
240
+
241
+ return iframe;
242
+ }
243
+
244
+ function OverlayRoot(doc, parent) {
245
+ const div = doc.createElement('div');
246
+ div.id = 'container';
247
+ parent.appendChild(div);
248
+ return div;
249
+ }
250
+
251
+ function ensureRootExists(renderFn) {
252
+ if (root) {
253
+ renderFn();
254
+ return;
255
+ }
256
+
257
+ scheduledRenderFn = renderFn;
258
+
259
+ if (iframeRoot) {
260
+ return;
261
+ }
262
+
263
+ iframeRoot = IframeRoot(document, document.body, {
264
+ onIframeLoad: function onIframeLoad() {
265
+ rootDocument = iframeRoot.contentDocument;
266
+ RootStyle(rootDocument, rootDocument.head);
267
+ root = OverlayRoot(rootDocument, rootDocument.body);
268
+ scheduledRenderFn();
269
+ },
270
+ });
271
+
272
+ document.body.appendChild(iframeRoot);
273
+ }
274
+
275
+ function removeAllChildren(element) {
276
+ const childList = Array.prototype.slice.call(element.childNodes, 0);
277
+ for (let i = 0; i < childList.length; i += 1) {
278
+ element.removeChild(childList[i]);
279
+ }
280
+ }
281
+
282
+ // ===== Render =====
283
+ function render() {
284
+ ensureRootExists(function () {
285
+ removeAllChildren(root);
286
+
287
+ // 通知前端,渲染错误页面已准备就绪
288
+ sendPostMessage({ type: 'PreviewReady' });
289
+
290
+ // 通知主应用存在自定义 overlay
291
+ sendPostMessage({
292
+ type: 'app-features',
293
+ payload: [{ feature: 'error-overlay', enable: true }],
294
+ });
295
+
296
+ if (currentCompileErrorMessage) {
297
+ currentMode = 'compileError';
298
+
299
+ // 通知主应用,当前出现渲染报错
300
+ sendPostMessage({ type: 'RenderError', data: currentMode });
301
+
302
+ // 发送编译错误
303
+ logError(['Compile Error', currentCompileErrorMessage], currentMode);
304
+ ErrorContainer(rootDocument, root, '编译出错');
305
+ } else if (currentRuntimeErrors.length) {
306
+ currentMode = 'runtimeError';
307
+
308
+ // 通知主应用,当前出现渲染报错
309
+ sendPostMessage({ type: 'RenderError', data: currentMode });
310
+
311
+ // 发送运行错误
312
+ logError(['Uncaught Render Error', ...currentRuntimeErrors], currentMode);
313
+ ErrorContainer(rootDocument, root, '页面出错了');
314
+ }
315
+ });
316
+ }
317
+
318
+ function cleanup() {
319
+ try {
320
+ if (iframeRoot && iframeRoot.parentNode) {
321
+ iframeRoot.parentNode.removeChild(iframeRoot);
322
+ }
323
+ } catch (e) {
324
+ // ignore
325
+ }
326
+ scheduledRenderFn = null;
327
+ root = null;
328
+ iframeRoot = null;
329
+ rootDocument = null;
330
+ }
331
+
332
+ // ===== Debounce (与 rspack 对齐) =====
333
+ function debounce(fn, wait) {
334
+ let timer;
335
+ function debounced() {
336
+ const context = this;
337
+ const args = arguments;
338
+ clearTimeout(timer);
339
+ timer = setTimeout(function () {
340
+ return fn.apply(context, args);
341
+ }, wait);
342
+ }
343
+ return debounced;
344
+ }
345
+
346
+ // ===== Public API =====
347
+ function clearCompileError(shouldReload) {
348
+ if (!root || currentMode !== 'compileError') {
349
+ return;
350
+ }
351
+ currentCompileErrorMessage = '';
352
+ currentMode = null;
353
+ cleanup();
354
+
355
+ // 编译错误修复后需要刷新页面,因为错误期间模块可能没有正确加载
356
+ if (shouldReload) {
357
+ window.location.reload();
358
+ }
359
+ }
360
+
361
+ function clearRuntimeErrors(dismissOverlay) {
362
+ if (!root || currentMode !== 'runtimeError') {
363
+ return;
364
+ }
365
+ currentRuntimeErrors = [];
366
+ if (typeof dismissOverlay === 'undefined' || dismissOverlay) {
367
+ currentMode = null;
368
+ cleanup();
369
+ }
370
+ }
371
+
372
+ function showCompileError(message) {
373
+ if (!message) {
374
+ return;
375
+ }
376
+ currentCompileErrorMessage = message;
377
+ render();
378
+ }
379
+
380
+ function showRuntimeErrors(errors) {
381
+ if (!errors || !errors.length) {
382
+ return;
383
+ }
384
+ currentRuntimeErrors = errors;
385
+ render();
386
+ }
387
+
388
+ // Debounced version to prevent frequent renders
389
+ const debouncedShowRuntimeErrors = debounce(showRuntimeErrors, 30);
390
+
391
+ // 检测是否为编译/模块加载错误(适配 Vite 错误格式)
392
+ function isCompileError(error) {
393
+ const message = error.message || '';
394
+ return (
395
+ // Vite 模块加载错误
396
+ /Failed to fetch dynamically imported module/.test(message) ||
397
+ /Failed to load module script/.test(message) ||
398
+ /Unable to preload CSS/.test(message) ||
399
+ // 通用模块错误
400
+ /Cannot find module/.test(message) ||
401
+ /Module not found/.test(message) ||
402
+ // Webpack 格式(兼容)
403
+ /Module [A-z ]+\(from/.test(message)
404
+ );
405
+ }
406
+
407
+ // 处理运行时错误(与 rspack 对齐)
408
+ function handleRuntimeError(error) {
409
+ // 如果是编译相关的错误,忽略它(会由 vite:error 事件处理)
410
+ if (!error || isCompileError(error)) {
411
+ return;
412
+ }
413
+
414
+ if (currentRuntimeErrors.indexOf(error) === -1) {
415
+ currentRuntimeErrors = currentRuntimeErrors.concat(error);
416
+ }
417
+ debouncedShowRuntimeErrors(currentRuntimeErrors);
418
+ }
419
+
420
+ // ===== Vite HMR Integration (using createHotContext) =====
421
+ const CLIENT_BASE_PATH = process.env.CLIENT_BASE_PATH || '';
422
+
423
+ async function setupViteHMRListener() {
424
+ try {
425
+ const { createHotContext } = await import(CLIENT_BASE_PATH + '/@vite/client');
426
+ const hot = createHotContext(CLIENT_BASE_PATH + '/@error-overlay.js');
427
+
428
+ // ===== HMR API: beforeUpdate - 通知 onBeforeApply 回调 + 重置错误标志 =====
429
+ hot.on('vite:beforeUpdate', () => {
430
+ hmrBeforeApplyCallbacks.forEach((cb) => {
431
+ try {
432
+ cb();
433
+ } catch (e) {
434
+ console.warn('[VITE_HMR] onBeforeApply callback error:', e);
435
+ }
436
+ });
437
+ hasErrorInCurrentUpdate = false;
438
+ });
439
+
440
+ // ===== HMR API: error - 设置错误标志并通知回调 =====
441
+ hot.on('vite:error', (payload) => {
442
+ hasErrorInCurrentUpdate = true;
443
+
444
+ // 通知 HMR 错误回调
445
+ hmrErrorCallbacks.forEach((cb) => {
446
+ try {
447
+ cb(payload.err);
448
+ } catch (e) {
449
+ // ignore callback errors
450
+ }
451
+ });
452
+
453
+ // 显示错误 overlay
454
+ if (payload.err) {
455
+ const msg = payload.err.message + (payload.err.frame ? '\n\n' + payload.err.frame : '');
456
+ showCompileError(msg);
457
+ }
458
+ });
459
+
460
+ // ===== HMR API: afterUpdate - 使用 queueMicrotask 等待 error 事件 =====
461
+ hot.on('vite:afterUpdate', () => {
462
+ // 使用 queueMicrotask 延迟执行,确保 vite:error 事件先处理
463
+ // Vite 事件顺序: beforeUpdate -> afterUpdate -> error
464
+ // microtask 会在所有同步事件处理完后执行
465
+ queueMicrotask(() => {
466
+ if (!hasErrorInCurrentUpdate) {
467
+ // 没有错误,通知成功回调
468
+ hmrSuccessCallbacks.forEach((cb) => {
469
+ try {
470
+ cb();
471
+ } catch (e) {
472
+ // ignore callback errors
473
+ }
474
+ });
475
+ }
476
+ });
477
+
478
+ // 清除编译错误 overlay(如果之前有的话)
479
+ clearCompileError(true);
480
+ });
481
+
482
+ // 自定义事件
483
+ hot.on('fullstack:error', (data) => {
484
+ showCompileError(data?.message || 'Unknown error');
485
+ });
486
+ } catch (e) {
487
+ // Failed to setup HMR listener
488
+ }
489
+ }
490
+
491
+ // ===== Global Error Listeners =====
492
+ function setupGlobalErrorListeners() {
493
+ window.addEventListener('error', (event) => {
494
+ // 忽略编译错误模式下的运行时错误
495
+ if (currentMode === 'compileError') return;
496
+
497
+ if (event.error) {
498
+ handleRuntimeError(event.error);
499
+ }
500
+ });
501
+
502
+ window.addEventListener('unhandledrejection', (event) => {
503
+ if (currentMode === 'compileError') return;
504
+
505
+ if (event.reason instanceof Error) {
506
+ handleRuntimeError(event.reason);
507
+ }
508
+ });
509
+ }
510
+
511
+ // ===== Expose Error Overlay API =====
512
+ window.__VITE_ERROR_OVERLAY__ = {
513
+ showCompileError,
514
+ clearCompileError,
515
+ showRuntimeErrors,
516
+ clearRuntimeErrors,
517
+ handleRuntimeError,
518
+ };
519
+
520
+ // ===== Expose HMR API (用于 toolkit 的统一 HMR API) =====
521
+ // @see docs/RFC_HMR_API.md
522
+ window.__VITE_HMR__ = {
523
+ /**
524
+ * 注册 HMR 更新前回调(vite:beforeUpdate 阶段,模块替换之前)
525
+ * @param {Function} callback 回调函数
526
+ * @returns {Function} cleanup 函数
527
+ */
528
+ onBeforeApply(callback) {
529
+ hmrBeforeApplyCallbacks.add(callback);
530
+ return () => hmrBeforeApplyCallbacks.delete(callback);
531
+ },
532
+ /**
533
+ * 注册 HMR 成功回调
534
+ * @param {Function} callback 成功回调函数
535
+ * @returns {Function} cleanup 函数
536
+ */
537
+ onSuccess(callback) {
538
+ hmrSuccessCallbacks.add(callback);
539
+ return () => hmrSuccessCallbacks.delete(callback);
540
+ },
541
+ /**
542
+ * 注册 HMR 失败回调
543
+ * @param {Function} callback 失败回调函数
544
+ * @returns {Function} cleanup 函数
545
+ */
546
+ onError(callback) {
547
+ hmrErrorCallbacks.add(callback);
548
+ return () => hmrErrorCallbacks.delete(callback);
549
+ },
550
+ };
551
+
552
+ // ===== Initialize =====
553
+ setupViteHMRListener();
554
+ setupGlobalErrorListeners();
555
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * iOS 兼容性 Polyfills
3
+ *
4
+ * 使用 core-js 提供 iOS 15.4 以下版本需要的 polyfill
5
+ * 此文件会被单独打包成 polyfills.js,按需加载
6
+ */
7
+
8
+ // ECMAScript polyfills (core-js)
9
+ import 'core-js/actual/array/at';
10
+ import 'core-js/actual/string/at';
11
+ import 'core-js/actual/array/find-last';
12
+ import 'core-js/actual/array/find-last-index';
13
+ import 'core-js/actual/object/has-own';
14
+ import 'core-js/actual/promise/any';
15
+ import 'core-js/actual/aggregate-error';
16
+ import 'core-js/actual/structured-clone';
17
+
18
+ // Web Crypto API polyfill (不在 core-js 范围内)
19
+ if (typeof crypto !== 'undefined' && typeof crypto.randomUUID !== 'function') {
20
+ Object.defineProperty(crypto, 'randomUUID', {
21
+ value: function randomUUID(): string {
22
+ const bytes = new Uint8Array(16);
23
+ crypto.getRandomValues(bytes);
24
+ bytes[6] = (bytes[6] & 0x0f) | 0x40;
25
+ bytes[8] = (bytes[8] & 0x3f) | 0x80;
26
+ let hex = '';
27
+ for (let i = 0; i < 16; i++) {
28
+ hex += (bytes[i] < 16 ? '0' : '') + bytes[i].toString(16);
29
+ }
30
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
31
+ },
32
+ writable: true,
33
+ configurable: true,
34
+ });
35
+ }