fix(console): preview 画廊的 page 样例改用注册过的块类型,并加注册表可解析断言 - #3453
Merged
Conversation
`preview-samples.ts` 的 page 样例用 `{ type: 'heading' }` 开头,而 `heading`
在本仓从未注册过——全仓 `register('heading'` / `registerLazy('heading'` 零命中。
spec 并不会拦下它:`PageComponentSchema.type` 是 `z.union([PageComponentType,
z.string()])`,枚举**或**任意字符串(好让插件贡献块),所以拼错的类型是完全合法的
元数据。两个节点因此一路解析干净、渲染成 ComponentRegistry fallback:画廊里
「一个组合页面长什么样」的样板,标题与小节标题的位置各摆着一个红色错误框。
同一处还有第二个毛病:配置放在 `props` 下。`PageComponentSchema` 是 `.strict()`,
按名字拒收 `props`(ADR-0089 D3a)——这正是 `page` 一直躺在
`preview-samples-spec-valid.test.ts` 的 KNOWN_STALE 账本里的唯一原因。两件事其实
是一个缺陷的两张脸:`page:header` 从 `schema` / `schema.properties` 上读 `title`,
只改类型不改 bag 的话,标题栏照样是空的。
改法(类型全部取自 `PageComponentType`):
• 页面标题 → `page:header`,由它承担 h1、副标题、面包屑/操作槽与下边框;
`recordChrome: false` 选择非记录页的裸标题布局。
• 正文小节标题 → `element:text` + `variant: 'subheading'`(渲染 h3,正是原来
`level: 3` 想要的)。`heading` 是 element:text 的**变体**,从来不是类型——
原样例就错在这个擦肩而过。
• 分隔线 → `element:divider`。原来的裸 `separator` 确实能解析(`ui:separator`
占着裸名),但它不是页面块类型。
新增 `preview-samples-registry-resolvable.test.ts`:递归走遍所有样例的
`regions[].components[]`(含嵌套 children/body/items 与 properties.* 下的同名键),
断言每个 type 都能 `has()` 或 `hasLazy()`。注册表从 console 真正启动的那两个模块图
读取,不手抄已知类型清单——手抄的清单只会自己跟自己吻合。另配两道防空转断言:
遍历确实走到了 page 样例;以及塞进 page:card 里的未注册类型确实会被报出来。
`page` 随之从 KNOWN_STALE 提升进 SPEC_CLEAN——这不是可选项,账本的反向断言
(「修好了就提升」)在样例变得合法的那一刻就会红。
浏览器复核(preview-gallery.html?only=page,无后端):改前两个 `heading` 是
「Unknown component type: heading (OBJUI-001)」错误框,两个 `text` 是空白卡片
(`ui:text` 读 `schema.content`,根本不看 `props.text`);改后 h1「Welcome to the
CRM」、h3「Quick links」、正文与分隔线齐全,页面上再无 fallback 标记。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3446
前提复核(先证实,再动手)
在
origin/main上逐条验证了 issue 的说法,全部成立:apps/console/src/preview-samples.ts:29,32两个{ type: 'heading' }仍在。heading仍未注册:全仓register('heading'/registerLazy('heading'零命中。仅有的两处同名物是packages/components/src/renderers/basic/elements.tsx:84里element:text的 variant'heading'(渲染 h2),以及不经注册表的ui/typography排版原语。text→ui:text、separator→ui:separator(element:text/element:divider是skipFallback: true,不占裸名)。spec 拦不住它,而且是设计如此:
PageComponentSchema.type是z.union([ PageComponentType, z.string() ])—— 枚举或任意字符串,好让插件贡献自己的块。所以拼错/杜撰的类型是完全合法的元数据,preview-samples-spec-valid.test.ts永远看不见它。这正是本 issue 要求补一道注册表断言的原因。顺带查出的第二张脸:
props同一个样例把配置放在
props下。PageComponentSchema是.strict(),按名字拒收props(ADR-0089 D3a)—— 这是page一直躺在preview-samples-spec-valid.test.ts的KNOWN_STALE账本里的唯一原因(实测:改前 4 条 issue,全部是props)。两件事其实是一个缺陷的两张脸,必须一起修:
page:header从schema/schema.properties上读title(containers.tsx:920),只改类型不改 bag,标题栏照样是空的。浏览器复核也确认了原样例里两个text节点本就是空白卡片 ——ui:text读schema.content || schema.value,从不看props.text。改法
类型全部取自
PageComponentType,与 designer 调色板(block-types.ts的BLOCK_TYPE_META)一致:headinglevel 1page:headerrecordChrome: false选非记录页的裸标题布局textelement:textcontent,不是textseparatorelement:dividerseparator确实能解析(ui:separator占着裸名),但它不是页面块类型headinglevel 3element:text+variant: 'subheading'level: 3想要的。heading是 element:text 的变体,从来不是类型 —— 原样例就错在这个擦肩而过新增断言:
preview-samples-registry-resolvable.test.ts递归走遍所有样例的
regions[].components[](含嵌套children/body/items及properties.*下的同名键 —— 与运行时容器自己走的候选键一致),断言每个type都能has()或hasLazy()。@object-ui/components+../register-plugins),与public-contract.test.ts同一姿势:手抄一份已知类型清单只会自己跟自己吻合。hasLazy一并算数:懒注册的 tag 是契约的正式成员,只是 chunk 何时导入不同(objectui#2953)。page:card里的未注册类型确实会被报出来(证明递归有牙,而不是靠"什么都没找到"绿着)。widgets[]:其中metric/pivot/dashboard-grid只由preview-gallery.tsx自己的registerLazy块注册,而该模块在导入时就 mount React,测试无法 import;照这个 bootstrap 去查会报出一批在画廊里其实解析得好好的类型,而把画廊那份清单再抄一遍就正是上面说的自我吻合。范围写在文件头,免得把绿色读过头。验证(仓根跑,均为实跑输出)
新断言对 origin/main 的样例是红的 —— 方向预先声明后再跑,命中预测:预测「恰好两条
heading,text/separator不出现(裸名别名能解析)」,实测:账本方向的反向验证(把
page临时放回KNOWN_STALE再跑),预测「反向断言收到 0 条 issue 而失败」,实测:—— 所以把
page提升进SPEC_CLEAN不是可选项,是账本自身的反向断言强制的("A sample only leaves this ledger by being FIXED")。这也是本 PR 动到第三个文件的原因。修完后:
浏览器复核(
preview-gallery.html?only=page,无后端,Playwright 驱动):Unknown component type: heading (OBJUI-001)红框,两个text是空白卡片,页面上h1/h3一个都没有。H1 :: Welcome to the CRM、H3 :: Quick links、正文与分隔线齐全,Unknown component/heading标记全部为false。范围说明
无 changeset:改的是 dev-only 画廊素材(文件头写明 Not shipped in production builds)与测试,不面向用户;仓里也没有强制 changeset 的闸门(
changeset-guard.yml只在.changeset/**变动时触发,且只拦 major)。未碰
packages/**—— 样例去适配注册表,而不是反过来。Generated by Claude Code