导出 web-component
Flamo 可以把经过验证的 Artifact Export 投影为 W3C Custom Element。导出物使用同一 public surface 生成 attributes、DOM properties、CustomEvent、methods、light DOM slots、.d.ts 和 custom-elements.json,避免手工 wrapper 与组件事实漂移。
从 Studio 导出节点
Section titled “从 Studio 导出节点”在画布上或左侧节点树中右键目标节点,选择“导出为 Web Component”,确认组件标签名,配置画布是否可移动、可缩放及内容适应方式,然后点击“导出”。导出目标始终是被右键的节点。普通节点也可以直接导出;临时导出边界只建立在打包副本中,原 Artifact 场景不变。
节点 card 默认导出为 flamo-card,不自动追加节点 ID 或版本。已有显式标签名会沿用;公开标签名可在导出面板编辑,确认后按节点保存到项目 .flamo/component-exports.json。后续节点改名仍沿用保存的标签,同项目导出节点重名会提示调整。版本、revision 和哈希留在 manifest 中。升级时整体替换包内资源,并检查 slot/prop/event 合同是否兼容。
默认不可移动、不可缩放、等比适应。画布背景默认透明,无需配置;节点自身设计的填充仍会保留。
“Source Map”默认不勾选。勾选后,导出包携带组件入口和用户交互脚本中可用的 Source Map,便于调试;闭源 Runtime 的 Source Map 始终不会随包导出。不勾选时不包含 .map 文件及对应引用。该配置记录在 manifest.json 的 packaging.sourceMap 字段。
“携带公共资源”默认勾选,组件包包含 Runtime 和画布适配模块,可以放到静态服务器直接使用。多个组件需要共用资源时:
- 取消勾选“携带公共资源”,填写公共资源根地址,例如
http://192.168.1.25:8080/common/v0.0.1/。 - 点击“下载公共资源包”,将解压目录中的
flamo-runtime/文件夹和component-viewport.js文件直接部署到该地址下。保留 Runtime 文件夹中的依赖与许可证,并配置 JavaScript MIME 类型及跨域模块请求所需的 CORS。 - 点击“导出”,获得已配置完整资源 URL 的组件包,无需修改
dist中的 JS。上述地址会生成http://192.168.1.25:8080/common/v0.0.1/flamo-runtime/index.es.js?v=v0.0.1和http://192.168.1.25:8080/common/v0.0.1/component-viewport.js?v=v0.0.1。
根地址最后一级是版本号(如 v0.0.1、0.0.1)时,自动使用该版本作为 v 查询参数;其他目录使用资源内容哈希作为 v 参数。查询参数不属于文件名。公共资源更新时,使用新的版本目录,并用新地址重新导出组件;同一版本可供多个组件共享。
interactions/ 中的项目脚本始终保留在组件包内,不会进入公共资源包,也不会被改成 CDN 脚本。它们对 Runtime 的引用会指向组件使用的同一地址。填写地址只配置引用,不会自动上传。
Runtime 公共资源包含独立的第三方依赖文件及许可正文。Runtime 核心采用混淆保护,@vue 等第三方依赖仅压缩;组件使用仍受包内 FLAMO-RUNTIME-LICENSE 和第三方许可证约束。
Runtime 不再默认携带可选的 HarfBuzz WASM 和后备字体。普通 Canvas 文字与已有字形轮廓不需要这些资源;显式使用 HarfBuzz 后备或字体处理 API 时,由使用方提供所需资源并通过 FlamoConfig.set({ wasmPath, fontPath, defaultFont }) 配置。用于布局的 Yoga WASM 仍保留在 Runtime 依赖中。
| 适应方式 | 缩放与滚动 |
|---|---|
| 等比适应 | 内容完整适配容器,保持宽高比例并居中 |
| 宽度适应 | 宽度填满容器,高度等比缩放;超出容器时出现纵向滚动条 |
| 高度适应 | 高度填满容器,宽度等比缩放;超出容器时出现横向滚动条 |
导出配置保存在包内 manifest.json 的 viewport 字段。用 CSS 设置自定义元素的宽高,组件会随容器尺寸变化重新适配。例如:
flamo-search-panel { width: 100%; height: 400px; background: #f5f5f5;}未设置 CSS 尺寸时,容器默认为 300px × 150px。百分比高度需要父容器有确定高度。滚动条不受“可移动”开关限制,该开关控制用户对画布相机的平移操作。
通过 MCP 导出
Section titled “通过 MCP 导出”使用 Flamo Design 插件时,也可通过 flamo_component_export 按节点和固定 Artifact revision 直接导出。先 dryRun,再 apply,下载后核对 ZIP 的 SHA-256、manifest 中的 revision 和 contractId。详见 Flamo Design 插件。
避免刷新时插槽内容闪现
Section titled “避免刷新时插槽内容闪现”浏览器在 Custom Element 定义前会直接显示标签内的 light DOM。推荐使用导出包提供的轻量加载入口和固定尺寸占位容器;将下面的样式和资源引用放在页面 head,容器放在正文。将示例标签替换为实际导出的标签名。
<style>[data-flamo-component]:not([data-flamo-state="ready"]){opacity:0;pointer-events:none}</style><link rel="stylesheet" href="./dist/component-loading.css"><script type="module" src="./dist/flamo-search-panel.loader.js"></script>
<div class="flamo-component-shell" style="width:100%;height:400px"> <flamo-search-panel data-flamo-component inert aria-busy="true" loading-label="正在加载查询面板…"> <span slot="empty">没有结果</span> </flamo-search-panel> <div data-flamo-status role="status" aria-live="polite"> <span data-flamo-message>正在加载查询面板…</span> <button type="button" hidden>刷新重试</button> </div></div>占位保持组件尺寸,页面其他区域可以继续加载。组件在场景、交互、初始插槽图片和画布已请求的图片资源就绪并完成绘制后,派发 flamo-ready 并淡入;paused 组件也会完成初始绘制。模块或运行时错误显示刷新入口,等待超过 45 秒时提示检查网络,之后成功仍会恢复。data-flamo-state 为 loading、ready 或 error,aria-busy 同步更新。
可通过容器的 --flamo-loading-accent、--flamo-loading-color 自定义颜色;系统开启减少动画时关闭旋转和淡入。使用 CDN 时应同时更新对应公共 Runtime 资源。
为 AI 提供 Slot 接入说明
Section titled “为 AI 提供 Slot 接入说明”选择 Figma 主组件,在右侧 Properties 中编辑对应 Slot property 的 description。同步并重新导出后,说明会出现在 manifest.json、custom-elements.json 和 README 真实 slot 骨架的 data-mark 中。Slot 名称精确保留大小写。已有默认内容的占位会注释,防止空 div 覆盖默认内容。
描述应说明内容用途、状态表现、未知状态和资源约束。具体 API、点位字段和实际值映射由接入项目提供,AI 不应根据 slot 缩写推导。把导出包与宿主项目交给 AI,按包内 AGENTS.md 读取真实合同、现有接口与素材后生成接入代码;业务文件放在导出目录外,便于整体升级组件包。
const component = document.querySelector('flamo-card');component.slotStyles = '[slot="header"] { color: white; }';// 只修改源 light DOM,Runtime 会同步各个独立 outlet。component.querySelector('[slot="header"]').textContent = '最新内容';slotStyles 可以在组件定义前、ready 前或 ready 后设置,空字符串清除。CSS 应限定到 slot 内容;相对资源 URL 相对于宿主文档。宿主无需查询 ShadowRoot 或复制样式到内部。源 DOM 的属性、文字、子节点变化会同步,但 JS property 和 addEventListener 不会随克隆复制;有独立交互的内容使用自行初始化、断开时清理的 Custom Element,或声明的 slot props/events。
导出合同检查
Section titled “导出合同检查”- boundary 有稳定
tagName,并且只包含连字符形式的合法自定义元素名; - Artifact Export 的 props/events/methods/slots 已验证;
- composition dependency lock、Artifact hash、surface hash 与 Runtime ABI 可追踪;
- 脚本、字体、图片和其他资源进入 package closure;
- duplicate tag、ABI mismatch、asset/module 404 与 partial mount 有失败证据。
两种发布模式
Section titled “两种发布模式”| 模式 | 适合场景 | 边界 |
|---|---|---|
browser-esm |
目录式 ESM 发布,组件、Runtime、interaction 与资源按 manifest 组织 | 允许静态 HTTP + import maps,无需宿主 bundler |
thin-single-js |
每个组件使用精简入口,共享外部 Runtime | Runtime 与资源仍是外部依赖,不是完全 standalone |
Flamo 不提供 standalone-single-js:不会把 Runtime、Artifact、脚本、字体、图片和全部依赖永久内联为一个巨型文件。
直接在 HTML 中使用
Section titled “直接在 HTML 中使用”导出的 direct entry 会注册自定义元素:
<script type="module" src="./dist/flamo-search-panel.js"></script>
<flamo-search-panel query="Flamo"> <span slot="empty">没有结果</span></flamo-search-panel>
<script type="module"> const panel = document.querySelector('flamo-search-panel'); panel.query = 'Artifact'; // DOM property panel.addEventListener('submit', event => console.log(event.detail)); await panel.focus(); // public method</script>如果使用不自动注册的 .module.js entry,先导入并调用 registerFlamoComponent()。同一 tagName 已由不同 identity 注册时必须失败,不能覆盖浏览器 registry 中的已有类。
Browser manifest 与安全
Section titled “Browser manifest 与安全”每个发布模式都生成 versioned browser manifest,记录 exact Component Ref、entry、resource base、integrity、surface/composition hash、dependencies 与 assets。Loader 在 import 前应用 allowed origins、CORS、integrity、timeout、retry、cache 和 script allowlist 策略;一个模块失败时,不应污染已经运行的其他组件实例。
包中还包含 manifest.json、custom-elements.json、精确 .d.ts 和 Packaging IR;source maps 按导出时的选项携带。宿主集成以这些生成合同为准,不从内部 Artifact 结构猜 props 或事件。