Skip to content

fix(console): declare type: 'home' on the page preview sample (#3454) - #3473

Merged
yinlianghui merged 1 commit into
mainfrom
claude/issue-3454-preview-page-type
Aug 6, 2026
Merged

fix(console): declare type: 'home' on the page preview sample (#3454)#3473
yinlianghui merged 1 commit into
mainfrom
claude/issue-3454-preview-page-type

Conversation

@yinlianghui

Copy link
Copy Markdown
Collaborator

Fixes #3454

问题

apps/console/src/preview-samples.tspage 样例只声明了 name / label / regions,没有声明 type。而 spec 的 PageSchema.typePageTypeSchema.default('record')(page.zod.ts:413),所以「不写」并不等于「未指定」——它会落成 record;又因为 object 是可选的,这个 record 页没有任何对象绑定,校验也不会报错。

但同一个文件里的 app 样例,正是把这个页面当首页用的:

navigation[0] = { id: 'home', type: 'page', pageName: 'crm_welcome' }

即:样例演示的语义(首页)与它解析后的语义(无绑定的记录页)是矛盾的。

为什么之前没有任何测试变红

gallery 渲染的是未解析的 draft(draft.type 为 undefined);而 preview-samples-registry-resolvable.test.ts 只遍历 regions[].components,不读根节点的 type。这个缺陷正好落在两条既有防线之间。它值得修,是因为这些样例是作者(越来越多是生成元数据的模型)照抄的范例——错误语义会被复制、传播。

改动

一行 type: 'home',加一段说明「为什么必须显式声明」的注释。homePageTypeSchema 中(page.zod.ts:232),且已注册渲染器(packages/components/src/renderers/layout/page.tsx:700,与 page 共用 PageRenderer)。

这一行有实际作用,不只是「更规范」

运行时 PageView.tsx:129-131 会把 spec 的 type 桥接到渲染器真正读的 pageType:

type: (page as any).type || 'page',
pageType: (page as any).type,

该处注释写明:没有这个映射,"every page fell back to pageType: 'record', so non-record pages got the record max-width, a wrong data-page-type and a suppressed header"。也就是说,原样例演示的恰恰是这个映射要避免的坏状态;补上后,它发布到真实应用、从 home 导航打开时,会真正走 HomePageLayout

验证

反向验证(先预测方向,再执行):先加 pin、不改样例 → 应当变红,且 received 恰为 'record'。实际输出:

AssertionError: expected 'record' to be 'home'
Expected: "home"
Received: "record"

补上 type: 'home' 后:

  • preview-samples-spec-valid.test.ts + preview-samples-registry-resolvable.test.ts:35 passed
  • apps/console 全量:23 files / 212 tests passed
  • type-check --filter=@object-ui/console:35 tasks successful
  • check-control-bytes:OK

浏览器验证(scoped verify skill,gallery ?only=page):改动前后截图 md5 完全一致(8fde30b4...),DOM 采集逐项相同,无 "Unknown component type" 兜底框。零视觉差异的原因比「draft 路径忽略 type」更具体:design 模式下 PagePreview 走的是 PageBlockCanvas,根本不经过 PageRenderer(所以 DOM 里没有 data-page-type);即便走 SchemaRenderer,'home' 与原先注入的 'page' 也都解析到同一个 PageRenderer,而布局分支读的是 pageType(预览路径并不设置它)。

未改动 / 无新 finding

spec 的 type(页面种类)与 objectui 节点 pageType 的命名冲突,是 packages/types/src/zod/layout.zod.ts:296 已明确记录的既有取舍,且运行时已由 PageView 桥接,因此不另开 finding。

#3453 先例,dev-only 样例不加 changeset。


Generated by Claude Code

`PageSchema.type` is `PageTypeSchema.default('record')`, so the page sample
omitting `type` did not mean "unspecified" — it materialised the CRM welcome
screen as a RECORD page bound to no object (`object` is optional, so nothing
complained). The `app` sample in the same file routes that very page as the
CRM's landing entry, so `home` is the kind it is actually used as.

The mismatch was invisible: the gallery renders the UNPARSED draft, so no
test would ever have gone red over it. It matters because these samples are
the worked example authors — increasingly models generating metadata — copy.

Pinned on the PARSED value, since only the parse distinguishes "declared
`home`" from "omitted, therefore `record`".

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GTRjn8xBqp75dk7kFupVRt
@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectui Ignored Ignored Aug 6, 2026 9:08am

Request Review

@yinlianghui
yinlianghui marked this pull request as ready for review August 6, 2026 09:09
@yinlianghui
yinlianghui added this pull request to the merge queue Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

Metric Value Budget
Main entry (gzip) 28.1 KB 350 KB
Entry file index-D_L7OkcS.js
Status PASS

📦 Bundle Size Report

Package Size Gzipped
app-shell (index.js) 8.47KB 3.09KB
app-shell (runtime-config.js) 7.42KB 2.32KB
app-shell (types.js) 0.01KB 0.04KB
app-shell (urlParams.js) 7.57KB 2.97KB
auth (AuthContext.js) 0.31KB 0.24KB
auth (AuthGuard.js) 1.17KB 0.53KB
auth (AuthProvider.js) 22.10KB 4.37KB
auth (AuthShell.js) 3.49KB 1.40KB
auth (ForgotPasswordForm.js) 12.21KB 3.45KB
auth (LoginForm.js) 18.13KB 5.39KB
auth (PreviewBanner.js) 0.90KB 0.50KB
auth (RegisterForm.js) 6.64KB 2.21KB
auth (SocialSignInButtons.js) 9.60KB 3.89KB
auth (UserMenu.js) 3.40KB 1.22KB
auth (auth-gate-events.js) 1.29KB 0.66KB
auth (authStyles.js) 5.04KB 1.72KB
auth (createAuthClient.js) 35.76KB 9.11KB
auth (createAuthenticatedFetch.js) 4.37KB 1.69KB
auth (index.js) 2.35KB 1.07KB
auth (org-roles.js) 6.66KB 2.78KB
auth (phone-identifier.js) 1.11KB 0.66KB
auth (types.js) 0.59KB 0.35KB
auth (useAuth.js) 4.91KB 0.87KB
auth (useIsWorkspaceAdmin.js) 1.61KB 0.85KB
collaboration (CommentThread.js) 21.35KB 5.70KB
collaboration (LiveCursors.js) 3.17KB 1.27KB
collaboration (PresenceAvatars.js) 6.49KB 2.64KB
collaboration (PresenceProvider.js) 2.79KB 1.13KB
collaboration (index.js) 1.65KB 0.73KB
collaboration (useCollaborationTranslation.js) 5.30KB 2.24KB
collaboration (useCommentSearch.js) 1.98KB 0.88KB
collaboration (useConflictResolution.js) 7.75KB 1.86KB
collaboration (useMentionNotifications.js) 1.81KB 0.68KB
collaboration (usePresence.js) 6.33KB 1.84KB
collaboration (useRealtimeSubscription.js) 7.91KB 2.01KB
components (index.js) 479.63KB 105.43KB
core (index.js) 2.47KB 0.91KB
create-plugin (index.js) 9.28KB 2.98KB
data-objectstack (index.js) 136.30KB 34.76KB
fields (index.js) 229.92KB 56.48KB
i18n (LocalizationContext.js) 1.76KB 0.96KB
i18n (currency.js) 1.22KB 0.64KB
i18n (i18n.js) 4.32KB 1.77KB
i18n (index.js) 2.65KB 1.06KB
i18n (pickLocalized.js) 1.70KB 0.83KB
i18n (provider.js) 9.48KB 3.27KB
i18n (useObjectLabel.js) 26.14KB 6.07KB
i18n (useSafeTranslation.js) 3.26KB 1.44KB
layout (index.js) 38.53KB 10.71KB
mobile (MobileProvider.js) 0.92KB 0.49KB
mobile (ResponsiveContainer.js) 0.94KB 0.38KB
mobile (breakpoints.js) 1.51KB 0.70KB
mobile (createOfflineDataSource.js) 5.61KB 1.74KB
mobile (index.js) 1.50KB 0.62KB
mobile (offlineQueue.js) 3.91KB 1.35KB
mobile (pwa.js) 0.97KB 0.49KB
mobile (serviceWorker.js) 1.48KB 0.62KB
mobile (serviceWorkerSource.js) 3.41KB 1.48KB
mobile (useBreakpoint.js) 1.54KB 0.65KB
mobile (useGesture.js) 6.96KB 1.98KB
mobile (useOfflineSync.js) 1.99KB 0.72KB
mobile (usePullToRefresh.js) 2.53KB 0.85KB
mobile (useResponsive.js) 0.71KB 0.42KB
mobile (useResponsiveConfig.js) 1.36KB 0.63KB
mobile (useSpecGesture.js) 4.05KB 1.53KB
mobile (useTouchTarget.js) 1.01KB 0.54KB
permissions (MePermissionsProvider.js) 8.75KB 3.06KB
permissions (PermissionContext.js) 0.31KB 0.25KB
permissions (PermissionGuard.js) 0.89KB 0.45KB
permissions (PermissionProvider.js) 3.67KB 1.12KB
permissions (evaluator.js) 4.41KB 1.44KB
permissions (index.js) 0.91KB 0.41KB
permissions (store.js) 0.91KB 0.42KB
permissions (useFieldPermissions.js) 1.28KB 0.52KB
permissions (usePermissions.js) 1.55KB 0.71KB
plugin-ai (index.js) 15.71KB 3.79KB
plugin-calendar (index.js) 44.98KB 12.37KB
plugin-charts (index.js) 61.04KB 17.31KB
plugin-chatbot (index.js) 180.09KB 42.72KB
plugin-dashboard (index.js) 112.03KB 28.88KB
plugin-designer (index.js) 210.51KB 42.51KB
plugin-detail (index.js) 232.53KB 57.37KB
plugin-editor (index.js) 2.46KB 1.10KB
plugin-form (index.js) 111.54KB 26.97KB
plugin-gantt (index.js) 162.55KB 39.57KB
plugin-grid (index.js) 185.25KB 49.08KB
plugin-kanban (index.js) 48.03KB 13.22KB
plugin-list (index.js) 105.19KB 25.39KB
plugin-map (index.js) 16.81KB 5.24KB
plugin-markdown (index.js) 13.72KB 4.69KB
plugin-report (index.js) 40.58KB 10.58KB
plugin-timeline (index.js) 25.76KB 7.33KB
plugin-tree (index.js) 8.50KB 2.88KB
plugin-view (index.js) 84.03KB 20.55KB
providers (DataSourceProvider.js) 0.75KB 0.39KB
providers (MetadataProvider.js) 1.37KB 0.59KB
providers (ThemeProvider.js) 1.90KB 0.85KB
providers (UploadProvider.js) 11.71KB 3.53KB
providers (index.js) 0.44KB 0.22KB
providers (types.js) 0.01KB 0.04KB
react-runtime (index.js) 5.67KB 2.37KB
react (LazyPluginLoader.js) 3.77KB 1.33KB
react (SchemaRenderer.js) 19.28KB 6.38KB
react (data-invalidation.js) 5.05KB 2.08KB
react (index.js) 1.02KB 0.55KB
react (spec-input.js) 0.20KB 0.18KB
sdui-parser (codegen.js) 4.09KB 1.74KB
sdui-parser (index.js) 4.47KB 2.03KB
sdui-parser (parse.js) 10.04KB 2.82KB
sdui-parser (types.js) 0.29KB 0.24KB
sdui-parser (validate.js) 4.69KB 1.48KB
types (ai.js) 0.20KB 0.17KB
types (api-types.js) 0.20KB 0.18KB
types (app.js) 2.87KB 0.99KB
types (base.js) 0.20KB 0.18KB
types (blocks.js) 0.20KB 0.18KB
types (complex.js) 0.20KB 0.18KB
types (crud.js) 0.20KB 0.18KB
types (data-display.js) 0.20KB 0.18KB
types (data-protocol.js) 0.20KB 0.19KB
types (data.js) 0.20KB 0.18KB
types (designer.js) 1.87KB 0.85KB
types (disclosure.js) 0.20KB 0.18KB
types (error-code.js) 1.54KB 0.88KB
types (feedback.js) 0.20KB 0.18KB
types (field-types.js) 0.20KB 0.18KB
types (form.js) 0.20KB 0.18KB
types (http-retry.js) 4.32KB 2.02KB
types (index.js) 2.46KB 1.21KB
types (layout.js) 0.20KB 0.18KB
types (managed-by.js) 0.19KB 0.18KB
types (mobile.js) 0.20KB 0.18KB
types (navigation.js) 0.20KB 0.18KB
types (objectql.js) 0.20KB 0.18KB
types (overlay.js) 0.20KB 0.18KB
types (permissions.js) 0.20KB 0.18KB
types (plugin-scope.js) 0.20KB 0.18KB
types (record-components.js) 0.20KB 0.19KB
types (record-semantics.js) 1.28KB 0.67KB
types (registry.js) 0.20KB 0.18KB
types (reports.js) 0.20KB 0.18KB
types (spec-report.js) 5.05KB 1.93KB
types (system-fields.js) 3.33KB 1.54KB
types (theme.js) 0.20KB 0.18KB
types (ui-action.js) 3.40KB 1.71KB
types (views.js) 0.20KB 0.18KB
types (widget.js) 0.20KB 0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Merged via the queue into main with commit d003a88 Aug 6, 2026
18 checks passed
@yinlianghui
yinlianghui deleted the claude/issue-3454-preview-page-type branch August 6, 2026 09:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[finding] preview-samples 的 page 样例没声明 type,按 spec 默认落成 record 页——但 app 样例把它当 home 用

2 participants