@lark-apaas/fullstack-rspack-preset 1.0.7 → 1.0.8-alpha.log.10

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.
@@ -2,14 +2,7 @@
2
2
  * 错误容器组件
3
3
  * @param {*} document
4
4
  * @param {*} root
5
- * @param {object} props
6
- * @param {string} props.errorMessage - 错误信息
7
- * @param {function} props.onRepairClick - 修复按钮点击事件
8
- * @param {function} props.onCopyClick - 复制按钮点击事件
5
+ * @param {string} errorTitle 错误标题
9
6
  */
10
- export function ErrorContainer(document: any, root: any, props: {
11
- errorMessage: string;
12
- onRepairClick: Function;
13
- onCopyClick: Function;
14
- }): void;
7
+ export function ErrorContainer(document: any, root: any, errorTitle: string): void;
15
8
  export function RootStyle(document: any, root: any): void;
@@ -3,57 +3,31 @@
3
3
  * 错误容器组件
4
4
  * @param {*} document
5
5
  * @param {*} root
6
- * @param {object} props
7
- * @param {string} props.errorMessage - 错误信息
8
- * @param {function} props.onRepairClick - 修复按钮点击事件
9
- * @param {function} props.onCopyClick - 复制按钮点击事件
6
+ * @param {string} errorTitle 错误标题
10
7
  */
11
- function ErrorContainer(document, root, props) {
8
+ function ErrorContainer(document, root, errorTitle) {
12
9
  // 创建容器元素
13
10
  const container = document.createElement('div');
14
- container.className = 'container';
11
+ container.className = 'overlay-container';
15
12
  // 创建内容元素
16
13
  const content = document.createElement('div');
17
- content.className = 'content';
14
+ content.className = 'overlay-content';
18
15
  container.appendChild(content);
19
16
  // 创建图片元素
20
17
  const img = document.createElement('img');
21
18
  img.src =
22
- 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ylcylz_fsph_ryhs/ljhwZthlaukjlkulzlp/feisuda/template/render_error.svg';
23
- img.alt = 'render error';
19
+ 'https://lf3-static.bytednsdoc.com/obj/eden-cn/ylcylz_fsph_ryhs/ljhwZthlaukjlkulzlp/feisuda/template/illustration_empty_negative_error.svg';
20
+ img.alt = 'Error';
24
21
  // 图片占位
25
- img.width = 120;
26
- img.height = 120;
27
- img.className = 'error-image';
22
+ img.width = 100;
23
+ img.height = 100;
24
+ img.className = 'overlay-error-image';
28
25
  content.appendChild(img);
29
26
  // 创建标题元素
30
27
  const title = document.createElement('p');
31
- title.className = 'title';
32
- title.textContent = '哎呀,写错代码了';
28
+ title.className = 'overlay-title';
29
+ title.textContent = errorTitle;
33
30
  content.appendChild(title);
34
- // 创建描述元素
35
- const description = document.createElement('p');
36
- description.className = 'description';
37
- description.textContent = '可复制错误信息,或告诉妙搭进行修复。';
38
- content.appendChild(description);
39
- // 创建按钮组元素
40
- const buttonGroup = document.createElement('div');
41
- buttonGroup.className = 'button-group';
42
- content.appendChild(buttonGroup);
43
- // 创建复制按钮
44
- const copyBtn = document.createElement('button');
45
- copyBtn.className = 'button button-copy';
46
- copyBtn.id = 'copyBtn';
47
- copyBtn.textContent = '复制错误信息';
48
- copyBtn.addEventListener('click', props.onCopyClick);
49
- buttonGroup.appendChild(copyBtn);
50
- // 创建修复按钮
51
- const repairBtn = document.createElement('button');
52
- repairBtn.className = 'button button-repair';
53
- repairBtn.id = 'repairBtn';
54
- repairBtn.textContent = '告诉妙搭修复';
55
- repairBtn.addEventListener('click', props.onRepairClick);
56
- buttonGroup.appendChild(repairBtn);
57
31
  // 添加到根元素
58
32
  root.appendChild(container);
59
33
  }
@@ -68,22 +42,22 @@ function RootStyle(document, root) {
68
42
  }
69
43
 
70
44
  body {
71
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
45
+ font-family: "PingFang SC", -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
72
46
  'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
73
47
  sans-serif;
74
48
  -webkit-font-smoothing: antialiased;
75
49
  -moz-osx-font-smoothing: grayscale;
76
50
  }
77
51
 
78
- .container {
52
+ .overlay-container {
79
53
  min-height: 100vh;
80
54
  display: flex;
81
55
  align-items: center;
82
56
  justify-content: center;
83
- background-color: #F3F4F6; /* bg-gray-100 */
57
+ background-color: #fff;
84
58
  }
85
59
 
86
- .content {
60
+ .overlay-content {
87
61
  display: flex;
88
62
  flex-direction: column;
89
63
  justify-content: center;
@@ -91,75 +65,21 @@ function RootStyle(document, root) {
91
65
  text-align: center;
92
66
  }
93
67
 
94
- .error-image {
95
- margin-bottom: 16px; /* mb-4 */
96
- width: 120px; /* w-[120px] */
68
+ .overlay-error-image {
69
+ margin-bottom: 12px; /* mb-3 */
70
+ width: 100px; /* w-[100px] */
97
71
  height: auto;
98
72
  }
99
73
 
100
- .title {
101
- font-size: 18px; /* text-l (推测为 text-lg) */
102
- line-height: 22px;
74
+ .overlay-title {
103
75
  color: #1F2329;
104
- font-weight: 500; /* font-medium */
105
- margin-bottom: 8px; /* mb-2 */
106
- }
107
-
108
- .description {
109
- font-size: 14px; /* text-sm */
110
- line-height: 22px;
111
- color: #646A73;
112
- font-weight: 400; /* font-normal */
113
- margin-bottom: 8px; /* mb-2 */
114
- }
115
-
116
- .button-group {
117
- display: flex;
118
- gap: 16px; /* space-x-4 */
119
- }
120
-
121
- .button {
122
- height: 32px; /* h-[32px] */
123
- padding: 0 16px;
124
- border-radius: 6px; /* rounded-[6px] */
125
- font-size: 14px; /* text-sm */
126
- font-weight: 400; /* font-[400] */
127
- cursor: pointer;
128
- transition: all 0.2s;
129
- outline: none; /* focus:outline-hidden */
130
- border: 1px solid;
131
- }
132
-
133
- .button-copy {
134
- background-color: white; /* bg-white */
135
- color: #4B5563; /* text-gray-600 */
136
- border-color: #D0D3D6; /* border-[#D0D3D6] */
137
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); /* shadow-xs */
138
- }
139
-
140
- .button-copy:hover {
141
- background-color: #F3F4F6; /* hover:bg-gray-100 */
142
- }
143
-
144
- .button-copy:active {
145
- background-color: #E5E7EB; /* active:bg-gray-200 */
146
- }
147
-
148
- .button-repair {
149
- background-color: #2563EB; /* bg-blue-600 */
150
- color: white; /* text-white */
151
- border-color: transparent; /* border-transparent */
152
- font-weight: 500; /* font-medium */
153
- box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); /* shadow-xs */
154
- }
155
-
156
- .button-repair:hover {
157
- background-color: #2563EB; /* hover:bg-blue-600 (保持不变) */
76
+ text-align: center;
77
+ font-size: 14px;
78
+ font-style: normal;
79
+ font-weight: 500;
80
+ line-height: 22px;
158
81
  }
159
82
 
160
- .button-repair:active {
161
- background-color: #1E40AF; /* active:bg-blue-700 */
162
- }
163
83
  `;
164
84
  root.appendChild(style);
165
85
  }
@@ -64,9 +64,14 @@ function IframeRoot(document, root, props) {
64
64
  iframe.style.width = '100vw';
65
65
  iframe.style.zIndex = '2147483647';
66
66
  iframe.addEventListener('load', function onLoad() {
67
- // Reset margin of iframe body
68
- iframe.contentDocument.body.style.margin = '0';
69
- props.onIframeLoad();
67
+ try {
68
+ // Reset margin of iframe body
69
+ iframe.contentDocument.body.style.margin = '0';
70
+ props.onIframeLoad();
71
+ }
72
+ catch (error) {
73
+ console.error('Error during iframe load:', error);
74
+ }
70
75
  });
71
76
  // We skip mounting and returns as we need to ensure
72
77
  // the load event is fired after we setup the global variable
@@ -124,52 +129,6 @@ function removeAllChildren(element, skip) {
124
129
  element.removeChild(childList[i]);
125
130
  }
126
131
  }
127
- /**
128
- * 降级复制方案(兼容旧浏览器)
129
- * @param text 要复制的文本
130
- * @returns boolean 复制是否成功
131
- */
132
- function fallbackCopyToClipboard(text) {
133
- try {
134
- // 创建临时的 textarea 元素
135
- const textArea = document.createElement('textarea');
136
- textArea.value = text;
137
- // 设置样式,使其不可见
138
- textArea.style.position = 'fixed';
139
- textArea.style.left = '-999999px';
140
- textArea.style.top = '-999999px';
141
- textArea.setAttribute('readonly', '');
142
- // 添加到 DOM
143
- document.body.appendChild(textArea);
144
- // 选中文本
145
- textArea.focus();
146
- textArea.select();
147
- // 执行复制命令
148
- const successful = document.execCommand('copy');
149
- // 清理:移除临时元素
150
- document.body.removeChild(textArea);
151
- return successful;
152
- }
153
- catch (error) {
154
- console.error('降级复制方案失败:', error);
155
- return false;
156
- }
157
- }
158
- async function copyToClipboard(text) {
159
- try {
160
- // 优先使用现代的 Clipboard API
161
- if (navigator.clipboard && window.isSecureContext) {
162
- await navigator.clipboard.writeText(text);
163
- return true;
164
- }
165
- // 降级方案:使用传统的 execCommand 方法
166
- return fallbackCopyToClipboard(text);
167
- }
168
- catch (error) {
169
- // 执行navigator.clipboard.writeText失败时,降级方案
170
- return fallbackCopyToClipboard(text);
171
- }
172
- }
173
132
  // 获取父窗口 origin
174
133
  function getPreviewParentOrigin() {
175
134
  const { origin } = window.location;
@@ -186,6 +145,64 @@ function getPreviewParentOrigin() {
186
145
  // BOE 环境
187
146
  return 'https://miaoda.feishu-boe.cn';
188
147
  }
148
+ function sendPostMessage(message, targetOrigin) {
149
+ try {
150
+ const origin = targetOrigin || getPreviewParentOrigin();
151
+ window.parent.postMessage(message, origin);
152
+ }
153
+ catch (error) {
154
+ console.error('ReactRefreshPlugin overlay发送 postMessage 失败:', error);
155
+ }
156
+ }
157
+ /**
158
+ * 上报错误信息
159
+ * @param {(string | Error)[]} messages 日志信息
160
+ * @param {'compileError' | 'runtimeError'} mode 日志模式
161
+ */
162
+ function logError(messages, mode) {
163
+ const logMeta = {
164
+ noStacktrace: mode === 'compileError',
165
+ stacktrace: mode === 'compileError' ? [] : undefined,
166
+ type: mode === 'compileError' ? 'compile-error' : 'uncaught-render-error',
167
+ };
168
+ try {
169
+ // 优先使用暴露的 __RUNTIME_LOGGER__ 上报错误
170
+ // 运行时错误出现时,window已经挂载
171
+ if (window.__RUNTIME_LOGGER__) {
172
+ window.__RUNTIME_LOGGER__.get().log({
173
+ level: 'error',
174
+ args: messages,
175
+ meta: logMeta,
176
+ });
177
+ return;
178
+ }
179
+ // 首次执行编译报错会走此处逻辑;
180
+ const parts = [];
181
+ for (const m of messages) {
182
+ if (m instanceof Error) {
183
+ parts.push(m.message, m);
184
+ }
185
+ else {
186
+ parts.push(m);
187
+ }
188
+ }
189
+ const logJSON = {
190
+ id: 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
191
+ const r = Math.random() * 16 | 0;
192
+ const v = c === 'x' ? r : (r & 0x3 | 0x8);
193
+ return v.toString(16);
194
+ }),
195
+ type: 'typedLogV2',
196
+ level: 'error',
197
+ args: parts,
198
+ meta: logMeta,
199
+ };
200
+ sendPostMessage({ type: 'SELECTED_LOG', payload: JSON.stringify(logJSON) });
201
+ }
202
+ catch (e) {
203
+ console.log('上报错误信息失败', e);
204
+ }
205
+ }
189
206
  /**
190
207
  * Creates the main `div` element for the overlay to render.
191
208
  * @returns {void}
@@ -193,57 +210,32 @@ function getPreviewParentOrigin() {
193
210
  function render() {
194
211
  ensureRootExists(function () {
195
212
  removeAllChildren(root);
196
- // 发送 postMessage
197
- const sendPostMessage = (message, targetOrigin) => {
198
- const origin = targetOrigin || getPreviewParentOrigin();
199
- window.parent.postMessage(message, origin);
200
- };
201
213
  // 通知前端,渲染错误页面已准备就绪
202
214
  sendPostMessage({
203
- type: 'PreviewReady'
215
+ type: 'PreviewReady',
204
216
  });
205
217
  // 通知主应用存在自定义 overlay
206
218
  sendPostMessage({
207
219
  type: 'app-features',
208
- payload: [{
220
+ payload: [
221
+ {
209
222
  feature: 'error-overlay',
210
223
  enable: true,
211
- }],
224
+ },
225
+ ],
212
226
  });
213
227
  if (currentCompileErrorMessage) {
214
228
  currentMode = 'compileError';
215
- ErrorContainer(rootDocument, root, {
216
- errorMessage: currentCompileErrorMessage,
217
- onRepairClick: function onRepairClick() {
218
- sendPostMessage({
219
- type: 'RenderErrorRepair',
220
- data: currentCompileErrorMessage,
221
- });
222
- },
223
- onCopyClick: function onCopyClick() {
224
- copyToClipboard(currentCompileErrorMessage);
225
- },
226
- });
229
+ // 发送编译错误
230
+ logError(['Compile Error', currentCompileErrorMessage], currentMode);
231
+ ErrorContainer(rootDocument, root, '编译出错');
227
232
  }
228
233
  else if (currentRuntimeErrors.length) {
229
234
  currentMode = 'runtimeError';
230
- let errors = '';
231
- currentRuntimeErrors.forEach(error => {
232
- errors += `${error.message}\n${error.stack}\n`;
233
- });
235
+ // 发送运行错误
236
+ logError(['Uncaught Render Error', ...currentRuntimeErrors], currentMode);
234
237
  // 叠加全部报错,将报错信息发送到妙搭
235
- ErrorContainer(rootDocument, root, {
236
- errorMessage: errors,
237
- onRepairClick: function onRepairClick() {
238
- sendPostMessage({
239
- type: 'RenderErrorRepair',
240
- data: errors,
241
- });
242
- },
243
- onCopyClick: function onCopyClick() {
244
- copyToClipboard(errors);
245
- },
246
- });
238
+ ErrorContainer(rootDocument, root, '页面出错了');
247
239
  }
248
240
  });
249
241
  }
@@ -102,7 +102,7 @@ function getSlardarScriptContent(option = {}) {
102
102
 
103
103
  // 添加 TTI 监控脚本
104
104
  const performanceScript = document.createElement('script');
105
- performanceScript.src = 'https://sf3-scmcdn-cn.feishucdn.com/obj/unpkg/byted/performance/0.1.0/dist/performance.iife.js';
105
+ performanceScript.src = 'https://sf3-scmcdn-cn.feishucdn.com/obj/unpkg/byted/performance/0.1.2/dist/performance.iife.js';
106
106
  document.head.appendChild(performanceScript);
107
107
  `;
108
108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-rspack-preset",
3
- "version": "1.0.7",
3
+ "version": "1.0.8-alpha.log.10",
4
4
  "files": [
5
5
  "lib",
6
6
  "preset.config.js"