@lark-apaas/cd-elements
v0.1.1-alpha.20260804133313
Published
Custom elements SDK for the buildless runtime (design-html / 创意模式) — self-contained IIFE bundles served from feishucdn, consumed via <script src>
Readme
@lark-apaas/cd-elements
buildless 运行时(design-html / 创意模式,AppType=8)的自定义元素 SDK。TS 源码经 tsup 编译成自包含 IIFE,由 feishucdn 分发,产物用
<script src>引入。
⚠️ 与同目录的 buildless/(registry 包)分发模型相反
两个包都在 packages/registries/ 下、都服务 buildless 运行时,但交付方式完全不同,别混:
| | buildless/(registry) | cd-elements/(本包) |
| ------ | ---------------------------------------------------- | ------------------------------------------------------------------ |
| 分发 | miaoda registry add 抓 tarball,源码拷进项目根 | CDN,产物 <script src> 引远端钉版 URL |
| 可改性 | AI 与用户都能改(改坏只影响该产物) | 产物里改不到,行为在所有引用它的产物间一致 |
| CLI | 由 miaoda-cli 消费 | 不由 CLI 消费(无 miaodaRegistry 块,registry add 抓不到) |
| 适合 | shadcn 式 UI 素材,用户要改样式和结构 | 基建型元素,行为必须全局统一、且不该被产物作者改动 |
<cd-image> 属于后者——它封装 TOS 图片参数拼接、webp 探测、DEFAULT_RESOLUTIONS 阶梯、SRC_ALLOWLIST 白名单。这些用户不该改:改坏 SRC_ALLOWLIST 会让优化静默失效,改坏阶梯会造出踩服务端冷处理的一次性尺寸变体(实测冷启 ~23s)。copy-in 把源码摊在项目根,AI 完全可能"顺手优化"掉它们。
选型判据见 docs/design-html-sdk-spec.md §1.1:用户该改的放 registry,用户不该改的放本包。
⚠️ 不要把 CDN 理解成「升级能自动覆盖存量产物」:产物里写的是钉版 URL(
design-html-sdk-spec.md§8 的固定版本契约要求如此),发新版本只作用于新产物——这点和 copy-in 一样。真实优势是代码不落进产物源码、跨产物共享浏览器缓存,以及为将来的平台注入留了口子(只有注入方统一控制版本时"覆盖存量"才成立)。
目录结构
src/
core/ # 元素间共享的内核(一份,避免各元素复制导致漂移)
tos.ts # TOS 图片处理:applyParamsToUrl / buildSrcSet / supportWebp / 白名单与阶梯常量
dom.ts # DOM 工具:defineOnce(防重复注册)/ injectStyleOnce(防重复注样式)
elements/ # 元素实现,一个元素一个文件
image.ts # <cd-image>
index.ts # 全量入口:引入即注册所有元素
dist/ # tsup 产物(gitignore,发布物)
__tests__/ # vitest(happy-dom 环境)
__gallery/ # 浏览器手工冒烟页元素一览
| 元素 | 单文件产物 | 说明 |
| ------------ | ------------------- | ------------------------------------------------------------------- |
| <cd-image> | dist/image.min.js | 图片性能优化:TOS resize / webp / 响应式 srcSet / 懒加载 / 异步解码 |
每个元素源码顶部有 /* BEGIN USAGE */ … /* END USAGE */ 块,声明注册的标签名、属性与约束。
用法
引全部元素(推荐,元素总量小):
<script src="<CDN_BASE>/@lark-apaas/[email protected]/dist/index.min.js"></script>只引一个元素(各单文件自包含,内核已 inline,无加载顺序要求):
<script src="<CDN_BASE>/@lark-apaas/[email protected]/dist/image.min.js"></script>
<cd-image src="/aily/api/v1/files/static/x.png" width="400" sizes="100vw" alt="…"></cd-image>版本精确 pin,不用浮动版本——与 design-html-sdk-spec.md §8 的 CDN 固定版本契约一致。调试时可把 .min.js 换成 .js(未压缩同源产物)。
CDN 路径从哪来
本包不自己上传 CDN。产物由 apaas/fullstack-plugin 的 coding-unpkg-sdk 镜像产线从 npm 搬到 feishucdn:
<CDN_BASE> = https://sf3-scmcdn-cn.feishucdn.com/obj/feishu-static/miaoda/coding-unpkg-sdk路径与 unpkg 原生对齐(<pkg>@<version>/<包内原始路径>),scoped 包自然嵌套。
为什么必须走 CDN:创意模式产物的 CSP 把 script-src 收口到 feishucdn,引 unpkg.com 会被浏览器拦截。
开发
pnpm --filter @lark-apaas/cd-elements build # tsup → dist/
pnpm --filter @lark-apaas/cd-elements dev # watch 模式
pnpm --filter @lark-apaas/cd-elements typecheck
pnpm --filter @lark-apaas/cd-elements lint
pnpm test # 全仓 vitest(含本包)
open __gallery/image.html # 浏览器冒烟(先 build)__tests__ 直接 import src/(不测产物),所以改源码即可跑测试,不必先 build。
新增一个元素
src/elements/<name>.ts写实现,export class+ 文件末尾defineOnce('cd-<name>', Class)- 顶部补
/* BEGIN USAGE */块(标签名 / 属性 / 约束) tsup.config.ts的ENTRY加一项<name>: 'src/elements/<name>.ts'src/index.ts加一行import './elements/<name>'__tests__/<name>.test.ts加单测(首行// @vitest-environment happy-dom)__gallery/<name>.html加冒烟页- 更新本文「元素一览」
- 让 Agent 知道它存在——在
packages/steering/coding-steering/steering/design-html/补 skill 说明(含 CDN URL 与用法)
共享逻辑放 src/core/,不要在元素间互相 import——每个元素产物必须自包含,能被单独引入。
发版流程(两步,跨仓)
1. 本仓:改元素 → chiya 发 npm(registry.npmjs.org)
2. fullstack-plugin:coding-unpkg-sdk/manifest.json 追加新版本号 → MR → SCM build 上传 feishucdnmanifest 条目形如:
{
"@lark-apaas/cd-elements": {
"versions": ["0.1.0"],
"files": ["dist/*.js"],
},
}versions 是数组、多版本并存——升级时追加而非替换,老产物 pin 的旧 URL 继续可用(保留降级能力)。
⚠️
registry.npmmirror.com(mirror 脚本默认源)同步公网 npm 有延迟。发布脚本末尾虽有npx cnpm sync主动推同步,但那只是触发;SCM 构建环境建议把NPM_MIRROR指向https://registry.npmjs.org(源站无延迟)。
对 docs/conventions.md §9 的两处偏离
§9 的 SDK 模板是给被 import 消费的 npm 包写的,本包消费方是浏览器 <script src>,故:
format: ['iife']而非['esm','cjs']——design-html-sdk-spec.md§2 明令避免type="module"(产物内 Babel 编译基于 classic scripts,window是唯一跨脚本共享机制)- 不出
dts—— 没有 import 型消费者,类型声明无处可用
其余均按 §9:target: 'es2022' 对齐 root tsconfig、src/ 布局、构建前 clean。
License
MIT — see LICENSE.
