@cfp-studio/iframe 18.4.5 → 18.4.7
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
|
+
//#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.
|
|
3
|
+
"version": "18.4.7",
|
|
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.
|
|
13
|
+
"@cfp-studio/analyzer-api": "0.1.16",
|
|
14
14
|
"@cfp-studio/fiber-reader": "0.3.0"
|
|
15
15
|
},
|
|
16
16
|
"devDependencies": {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { LogLevel } from "../../src";
|
|
3
3
|
// @ts-ignore
|
|
4
4
|
import inspect from "./object-inspect";
|
|
5
|
+
import { publishToHost } 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
|
|
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,73 @@ 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
|
+
* ## `source` 为什么必须显式给
|
|
163
|
+
*
|
|
164
|
+
* 宿主过去按**级别**分频道(`log`/`info` → Preview Console,`warn`/`error` → 运行时频道),
|
|
165
|
+
* 但级别不等于说话者:React 把**所有**开发期警告都打到 `console.error`,于是
|
|
166
|
+
* 「Function components cannot be given refs」「Each child in a list should have a unique key」
|
|
167
|
+
* 这类**用户代码的输出**全被当成了我們自己的运行时告警。
|
|
168
|
+
*
|
|
169
|
+
* 反过来,本文件的限流汇总用 `warn` 发出,却是**我们自己的话**。两边都按级别推断会同时猜错,
|
|
170
|
+
* 所以说话者只能由生产方标注。
|
|
171
|
+
*/
|
|
172
|
+
const LOG_BURST_WINDOW_MS = 1_000;
|
|
173
|
+
/** 一个窗口内最多转发多少条。超出部分计数后丢弃。 */
|
|
174
|
+
const LOG_BURST_LIMIT = 50;
|
|
175
|
+
|
|
176
|
+
let burstWindowStart = 0;
|
|
177
|
+
let burstCount = 0;
|
|
178
|
+
let droppedInWindow = 0;
|
|
179
|
+
|
|
180
|
+
function publishLogToHost(level: LogLevel, message: string): void {
|
|
181
|
+
try {
|
|
182
|
+
const now = Date.now();
|
|
183
|
+
if (now - burstWindowStart > LOG_BURST_WINDOW_MS) {
|
|
184
|
+
// 上一个窗口结束时若有丢弃,补一条汇总(用 warn,确保宿主默认看得见)。
|
|
185
|
+
if (droppedInWindow > 0) {
|
|
186
|
+
publishToHost({
|
|
187
|
+
kind: "cfp-log",
|
|
188
|
+
level: "warn",
|
|
189
|
+
message: `[预览页日志过多] 上一秒另有 ${droppedInWindow} 条被丢弃(上限 ${LOG_BURST_LIMIT}/秒)`,
|
|
190
|
+
// 这条是**我们自己**的限流提示,不是用户代码打的 —— 宿主据此把它留在运行时频道。
|
|
191
|
+
source: "runtime",
|
|
192
|
+
timestamp: now,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
burstWindowStart = now;
|
|
196
|
+
burstCount = 0;
|
|
197
|
+
droppedInWindow = 0;
|
|
198
|
+
}
|
|
199
|
+
if (burstCount >= LOG_BURST_LIMIT) {
|
|
200
|
+
droppedInWindow += 1;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
burstCount += 1;
|
|
204
|
+
// 用 `publishToHost` 而不是 `postToParent`:后者在 **browser 模式**下
|
|
205
|
+
// (预览页是顶层窗口,`window.parent === window`)直接 return 0,
|
|
206
|
+
// 日志会静默丢失 —— 而组件 console 恰恰是最需要传出去的东西。
|
|
207
|
+
publishToHost({ kind: "cfp-log", level, message, source: "user", timestamp: now });
|
|
208
|
+
} catch {
|
|
209
|
+
// 上报失败绝不能影响页面本身 —— console 拦截已经改了全局行为,这里必须静默。
|
|
210
|
+
}
|
|
211
|
+
}
|
|
@@ -581,11 +581,19 @@ export function publishRuntimeSnapshot(): void {
|
|
|
581
581
|
}
|
|
582
582
|
|
|
583
583
|
/**
|
|
584
|
-
*
|
|
585
|
-
*
|
|
586
|
-
*
|
|
584
|
+
* 把 `cfp-*` 消息上送宿主。
|
|
585
|
+
*
|
|
586
|
+
* ## 两条子路,两种预览模式各走一条
|
|
587
|
+
*
|
|
588
|
+
* - **browser**:预览页是顶层窗口(`window.parent === window`),`postMessage` 根本无处可发;
|
|
589
|
+
* 必须走 CDP `Runtime.addBinding` 注入的 `__cfpBridge`。
|
|
590
|
+
* - **embedded**:预览页嵌在 `@cfp-studio/app` 里,走 `parent.postMessage`,
|
|
591
|
+
* 由中间层原样转发给 webview。
|
|
592
|
+
*
|
|
593
|
+
* 这就是它存在的原因:任何想要「两种模式都能上送」的消息都必须用它,
|
|
594
|
+
* 而不是直接调 `postToParent` —— 后者在 browser 模式下会静默地什么都不做。
|
|
587
595
|
*/
|
|
588
|
-
function publishToHost(message: unknown): void {
|
|
596
|
+
export function publishToHost(message: unknown): void {
|
|
589
597
|
if (typeof window.__cfpBridge === "function") {
|
|
590
598
|
try {
|
|
591
599
|
window.__cfpBridge(JSON.stringify(message));
|