@cfp-studio/iframe 18.4.5 → 18.4.6

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.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_13c54df9746541450cb8a36e10ae9cdd/node_modules/vite/types/hmrPayload.d.ts
1
+ //#region ../../../../node_modules/.pnpm/vite@6.4.5_@types+node@24.1_d5dfe5fcbde62b2ff1de970aa6c74477/node_modules/vite/types/hmrPayload.d.ts
2
2
  interface UpdatePayload {
3
3
  type: 'update';
4
4
  updates: Update[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cfp-studio/iframe",
3
- "version": "18.4.5",
3
+ "version": "18.4.6",
4
4
  "license": "MIT",
5
5
  "files": [
6
6
  "dist",
@@ -10,7 +10,7 @@
10
10
  "main": "./dist/index.mjs",
11
11
  "types": "./dist/index.d.mts",
12
12
  "dependencies": {
13
- "@cfp-studio/analyzer-api": "0.1.15",
13
+ "@cfp-studio/analyzer-api": "0.1.16",
14
14
  "@cfp-studio/fiber-reader": "0.3.0"
15
15
  },
16
16
  "devDependencies": {
@@ -1,4 +1,4 @@
1
- import { clearErrorPanel } from "@cfp-studio/analyzer-api";
1
+ import { clearErrorPanel } from "@cfp-studio/analyzer-api/error-panel";
2
2
 
3
3
  import { overrideCopyCutPaste } from "./copy-cut-paste";
4
4
  import { setUpLinkInterception } from "./links";
@@ -2,6 +2,7 @@
2
2
  import type { LogLevel } from "../../src";
3
3
  // @ts-ignore
4
4
  import inspect from "./object-inspect";
5
+ import { postToParent } from "./runtime-bridge";
5
6
 
6
7
  // 注意: 请与 vite 保持同步:
7
8
  // https://github.com/vitejs/vite/blob/2de425d0288bfae345c5ced5c84cf67ffccaef48/packages/vite/src/client/client.ts#L117
@@ -31,12 +32,21 @@ export function setUpLogInterception() {
31
32
  return;
32
33
  }
33
34
  }
35
+ const message = formatLogMessage(...args);
34
36
  window.__PREVIEWJS_IFRAME__.reportEvent({
35
37
  kind: "log-message",
36
38
  level,
37
- message: formatLogMessage(...args),
39
+ message,
38
40
  timestamp: Date.now(),
39
41
  });
42
+ // 同时往上广播一份给宿主(`docs/todo/38` 的 P1)。
43
+ //
44
+ // 为什么需要两条路:`reportEvent` 只落到 iframe 自己的 `state.logs`,
45
+ // 而 `app/client/src/main.ts` 的 `onStateUpdate` 从未消费它 ——
46
+ // 组件的 console 输出在宿主完全不可见,用户只能开 Webview DevTools。
47
+ // 这里走 `cfp-*` 前缀是为了复用已有的转发链:
48
+ // iframe → app/client 的通用转发 → webview 的 classifyShellMessage → 宿主
49
+ publishLogToHost(level, message);
40
50
  } finally {
41
51
  console[level] = self;
42
52
  }
@@ -129,3 +139,58 @@ function formatValue(value: any) {
129
139
  }
130
140
  return formatted;
131
141
  }
142
+
143
+ /**
144
+ * 把一条 console 消息广播给宿主。
145
+ *
146
+ * ## 为什么单独一个函数
147
+ *
148
+ * `reportEvent` 那条路(`state.logs`)与这条(`cfp-log`)**消费者不重叠**:
149
+ * 前者留在 iframe 内部供 UI 用,后者往上传。和 `cfp-rendered` 的双通路是同一个模式,
150
+ * 见 `docs/analysis/preview-event-channels.md`。
151
+ *
152
+ * ## 为什么要限流
153
+ *
154
+ * 组件在 render 里打 `console.log` 时,一次刷新可能几十条。不设上限的话
155
+ * `OutputChannel` 会瞬间被刷满、`postMessage` 也会拖慢渲染。这里按
156
+ * {@link LOG_BURST_WINDOW_MS} 的窗口做**简单丢弃计数**:超限后只统计,
157
+ * 窗口结束时补一条汇总。
158
+ *
159
+ * 不追求精确(不需要漏桶/令牌桶):排查时要的是「知道有过量日志 + 看到样本」,
160
+ * 不是一份完整的日志归档。
161
+ */
162
+ const LOG_BURST_WINDOW_MS = 1_000;
163
+ /** 一个窗口内最多转发多少条。超出部分计数后丢弃。 */
164
+ const LOG_BURST_LIMIT = 50;
165
+
166
+ let burstWindowStart = 0;
167
+ let burstCount = 0;
168
+ let droppedInWindow = 0;
169
+
170
+ function publishLogToHost(level: LogLevel, message: string): void {
171
+ try {
172
+ const now = Date.now();
173
+ if (now - burstWindowStart > LOG_BURST_WINDOW_MS) {
174
+ // 上一个窗口结束时若有丢弃,补一条汇总(用 warn,确保宿主默认看得见)。
175
+ if (droppedInWindow > 0) {
176
+ postToParent({
177
+ kind: "cfp-log",
178
+ level: "warn",
179
+ message: `[预览页日志过多] 上一秒另有 ${droppedInWindow} 条被丢弃(上限 ${LOG_BURST_LIMIT}/秒)`,
180
+ timestamp: now,
181
+ });
182
+ }
183
+ burstWindowStart = now;
184
+ burstCount = 0;
185
+ droppedInWindow = 0;
186
+ }
187
+ if (burstCount >= LOG_BURST_LIMIT) {
188
+ droppedInWindow += 1;
189
+ return;
190
+ }
191
+ burstCount += 1;
192
+ postToParent({ kind: "cfp-log", level, message, timestamp: now });
193
+ } catch {
194
+ // 上报失败绝不能影响页面本身 —— console 拦截已经改了全局行为,这里必须静默。
195
+ }
196
+ }