Appearance
ADR-023: iframe URL 默认 + 可覆盖
Status: Accepted Date: 2026-07-13
Context
iframe 模式需要一个 URL。是硬编码?让消费方每次填?还是有默认?
Decision
frame-core 内默认 https://sentinel-video.pages.dev,消费方通过 origin / version props 覆盖。
CDN 路径规范:
/embed/v1/— 最新 v1.x.x(默认引用)/embed/v1.2/— 锁 minor/embed/v1.2.3/— 锁死具体版本
embed-app 需支持双通信模式:
- Penpal RPC(SDK 场景,双向)
- 原生 postMessage(静态场景,单向广播)
Rationale
- 默认 URL 让消费方 zero-config 就能跑
origin覆盖支持私有化部署version覆盖支持版本锁定(防上游意外变更)
Consequences
好:
- 消费方零配置起步
- 私有化 / 版本锁 灵活
- CDN 路径规范清晰
代价:
- 需要维护默认 CDN 域名
- 版本策略需要文档化
Update (2026-07-15): 构建期 env 默认(第三层覆盖)
背景:接 examples/team-video-vue 到 apps/playground-vue 时发现,LivePreviewCard / VideoPageWithRec 这类封装组件不透传 origin,本地开发会回退到硬编码 CDN sentinel-video.pages.dev(线上域名),导致 iframe 加载失败。且生产多环境 (staging CDN ≠ prod CDN)也需要"整个 app 一次性指向某个 embed origin",给每个封装组件 逐个传 origin 不可行。
决策:在 origin prop 之外,增加一层构建期 env 默认。buildFrameUrl 的解析优先级:
显式 origin/version 参数(props) > 构建期 env > 硬编码 CDN 默认env 变量:
VITE_SENTINEL_EMBED_ORIGIN— 覆盖默认 originVITE_SENTINEL_EMBED_VERSION— 覆盖默认 version 段(空串 = dev server 根路径,无/embed/vX/)
读取方式(packages/frame-core/src/url-builder.ts 的 readEnv):
- 浏览器 / Vite 客户端:
import.meta.env.VITE_*(消费方构建期静态替换) - node / SSR(Nuxt)/ 单测:
process.env.VITE_*兜底
为什么仍属 ADR-023:这是"可覆盖"的延伸,不改协议 schema、不改公开类型签名、向后兼容 (env 未设时行为与原来完全一致)。它把"覆盖"的粒度从"每组件"补齐到"每 app/每环境"。
消费方用法:app 根目录放 .env.<mode>,例如 playground-vue 的 .env.development 指向 http://localhost:5174;cend-p0 的各环境 .env 指向对应 CDN。
References
- USER-GUIDE.md § 26(iframe URL 详细说明)
- packages/frame-core/src/url-builder.ts(
readEnv+buildFrameUrl解析优先级) - apps/playground-vue/.env.development(本地 dev 覆盖示例)