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

@waleedlatif1 waleedlatif1 deleted the branch staging July 1, 2026 05:43
@waleedlatif1 waleedlatif1 reopened this Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants