Skip to content

perf(blocks): lazy block registry + display manifest [draft: investigation, not for merge]#5238

Draft
TheodoreSpeaks wants to merge 4 commits into
stagingfrom
perf/block-display-manifest
Draft

perf(blocks): lazy block registry + display manifest [draft: investigation, not for merge]#5238
TheodoreSpeaks wants to merge 4 commits into
stagingfrom
perf/block-display-manifest

Conversation

@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator

Summary

  • Splits every block into a light blocks/blocks/<name>.display.ts (display fields only) + adds blocks/manifest.ts / blocks/manifest-data.ts (BLOCK_DISPLAY for 300 blocks + BLOCK_CATALOG); migrates display/catalog callsites off the heavy registry.
  • Makes blocks/registry.ts lazy: the 300 block configs become BLOCK_LOADERS import() thunks resolved into a sync cache via loadBlockConfigs; getBlock stays sync and fail-loud on a cache miss. Preloads the open workflow's configs at loadWorkflowState.
  • Goal: cut Turbopack next dev compile RAM by decoupling the block/tool registries from routes.

⚠️ Draft — investigation, NOT for merge

  • Runtime-incomplete: ~74 backend getBlock callers + the add-block path aren't preloaded yet, so running/validating workflows, copilot, and adding blocks break at runtime. type-check is green; the rest isn't wired.
  • Base is 1 commit behind staging (downdetector feat(downdetector): add Downdetector outage-monitoring integration #5228) → the diff shows a spurious downdetector removal; needs a rebase + codemod re-run before any real merge.
  • Phases 3 (tools lazy) + 4 (boundary guard, retire dev:minimal) not started.

Measurement finding (why this is a draft, not a ship)

Cold editor-route compile, apples-to-apples (direct nav):

State editor compile (next.js) physical footprint
staging (eager) 32.1s 13.7 GB
this branch (blocks lazy, tools eager) 26.2s ~13.5–16.9 GB
both registries + manifest fully removed (dev:minimal-equiv) 23.0s 11.8 GB

The registry-internals decouple recovers ~0.2 GB on the editor. The real dev:minimal win (~1.7 GB editor / ~4 GB /home) lives in the display/icon/catalog layer a working editor genuinely needs — not safely removable. Dev pain is dominated by the systematic ~11.8 GB floor (Turbopack/Next + ReactFlow/Monaco) and the per-route API compile cascade (routes at 40–50s each), not the registries.

Where it still has value

  • Smaller prod bundles: routes that don't render blocks stop shipping the 300 configs. Phase 1 + 1b (manifest/catalog) are the keepable part; the lazy core (Phase 2) buys ~nothing for dev compile and adds runtime risk.

Recommendation

Keep as a record + (optionally) ship only Phase 1 + 1b for the prod-bundle benefit; drop the lazy core unless a prod-bundle measurement justifies it. Don't pursue Phases 2–4 for dev performance.

Type of Change

  • Draft / investigation (perf)

Testing

  • bun run type-check green across all 4 commits.
  • Editor compile/RAM measured cold via vmmap peak + Turbopack route timings (table above).
  • Full lint:check / check:api-validation:strict / runtime test suites NOT run — branch is a non-mergeable draft.

🤖 Generated with Claude Code

TheodoreSpeaks and others added 4 commits June 26, 2026 19:04
…migrate display sites

Foundation for the registry decouple (plan: snug-brewing-mist.md). Splits each block's
display fields into blocks/blocks/<name>.display.ts (<Name>BlockDisplay satisfies BlockDisplay),
the full config spreads it; adds blocks/manifest.ts (accessors) + blocks/manifest-data.ts
(BLOCK_DISPLAY 300 + TOOL_TO_BLOCK; BLOCK_CATALOG deferred to 1b). Migrates 15 pure-display
callsites off @/blocks/registry → @/blocks/manifest. registry.ts/registry-maps.ts untouched
(full configs intact; manifest is a parallel light source). Generated by
scripts/codemod-block-display.ts + scripts/generate-block-manifest-data.ts.

type-check 0 errors; manifest(300) == registry(300), zero drift.

WIP — before PR: rebase onto origin/staging (1 behind, downdetector) + re-run codemod; then
Phase 1b (BLOCK_CATALOG + catalog consumers) and Phase 2 (lazy configs + preload, the dev-RAM win).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…CK_CATALOG (Phase 1b)

Moves all 221 `{Service}BlockMeta` consts from blocks/blocks/<name>.ts into the
sibling <name>.display.ts (carrying the template-icon imports they reference), so
the light manifest can aggregate catalog data without importing heavy block configs.

- scripts/codemod-block-meta.ts: ts-morph codemod for the move (idempotent; skips
  files whose meta is already gone)
- generate-block-manifest-data.ts: aggregates the metas into BLOCK_CATALOG (231
  entries), keyed by each meta's sibling display `type` — exact parity with the old
  BLOCK_META_REGISTRY (231 keys, zero diff); generator is idempotent
- registry.ts: drop the `{XBlock, XBlockMeta}` meta imports and the inline
  BLOCK_META_REGISTRY; the catalog accessors now read BLOCK_CATALOG
- manifest.ts: add getAllBlockMeta + getBlockMeta
- migrate catalog consumers (integration detail page, landing slug page,
  lib/integrations re-export, suggested-actions via that re-export) to @/blocks/manifest

type-check 0 errors; check-block-registry passes; BLOCK_CATALOG parity 231=231.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ache + loadBlockConfigs

registry.ts no longer statically imports the 300 block configs. Each is now a lazy
import() thunk in BLOCK_LOADERS; configs resolve into a sync cache via loadBlockConfig/
loadBlockConfigs/loadAllBlockConfigs. getBlock & co. read the cache synchronously and
fail loud (dev warn) on a miss for a known type. Catalog accessors unchanged (read
BLOCK_CATALOG). Dropped the `registry` raw-map alias; its 3 callers were display/existence
checks → moved to getBlockDisplay (manifest) / isValidBlockType.

type-check 0 errors. RUNTIME-BROKEN until preload wiring (next commit): every getBlock
caller now needs its types preloaded. registry.ts compiles WITHOUT the 300 configs.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…kflowState (canvas)

await loadBlockConfigs(workflow block types) before the hydration ready-gate so the
canvas renders synchronously from a warm cache. Covers the editor's initial open.
Add-path + ~74 backend getBlock callers still need preload (next).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 27, 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)
docs Skipped Skipped Jun 27, 2026 6:56pm

Request Review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant