Skip to content

refactor: shrink the renderer's first-load chunk and remove three duplicated authorities - #4100

Closed
Astro-Han wants to merge 5 commits into
mainfrom
claude/eager-rosalind-e4b5f3
Closed

refactor: shrink the renderer's first-load chunk and remove three duplicated authorities#4100
Astro-Han wants to merge 5 commits into
mainfrom
claude/eager-rosalind-e4b5f3

Conversation

@Astro-Han

@Astro-Han Astro-Han commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Five simplification-audit findings in the desktop renderer and packages/ui. All internal; no user-visible behavior changes.

This is not a fix for the session-switch jank. The measured session-switch cost (9 long tasks, 717 ms, CLS 0.55) has a different, still-unidentified cause and is tracked separately. What is here is bundle size, one duplicated authority removed, and two boundary escape hatches closed.

Bundle size

The workbar feature barrel statically re-exported WorkbarSurface while workbar-host reaches it through lazy(() => import('./workbar-surface')). Because app-shell imports WorkbarHost from that barrel, the static edge dragged the 917-line surface and its five nested tool panels into the eager chunk — rolldown reported INEFFECTIVE_DYNAMIC_IMPORT.

Two Storybook files did import WorkbarSurface from the barrel. The export moves to the feature's testing entry — already recognized as public by workbar-boundary.test.ts, and imported by nothing that ships — and the stories follow it there.

before after
entry chunk 2,245.33 kB (gzip 451.12) 2,166.20 kB (gzip 426.86)
workbar-surface chunk 81.31 kB (gzip 25.41)
INEFFECTIVE_DYNAMIC_IMPORT yes no

One duplicated authority

assistant-stream and thinking-stream were two implementations of one concept — identical Options/Result shapes, the same redact-append-cap pipeline, the same non-string guard, structurally identical complete paths. They differed only in caps, marker strings, and which end of an over-cap buffer survives, and streaming-display-redaction already parameterizes that as recovery: 'head' | 'tail'.

stream-delta now owns the pipeline. Both modules keep their exported names, cap constants, and option types as thin wrappers. Head-keep's short-circuit on a frozen buffer is now expressed as a property of recovery: 'head', which is what it always was — tail-keep has no fixed point, so it is unaffected.

tool-output-stream is deliberately left alone: it accumulates a chunk array with dedup-by-seq, a different problem.

Two boundary escape hatches

Four workbar files imported ComposerProps through a seven- or eight-level relative path into packages/ui/dist/composer.d.ts, a build artifact. @maka/ui exports the type and all four already import from it.

Two local simplifications

  • chat-message-surface: the first two render-phase activation branches called setActivation with a byte-identical literal — now one condition. The snapshot handed to ChatView also dropped a session guard whose else branch was unreachable: every branch reseeds sessionId to activeSessionId, and a render-phase setState re-runs the body before anything commits.
  • use-roving-row-focus: the dependency-array-free layout effect (deliberate, and left that way) wrote tabIndex on every row on every render. An identical write still invalidates style and forces synchronous layout — DevTools charged it 224 ms of reflow. It now compares first. This helps the module pages that use the hook (skills, scheduled tasks, MCP); the chat transcript does not use it.

Verification

  • npm run format, npm run check:asf-headers, biome lint over the touched trees
  • @maka/ui build + full packages/ui test suite
  • desktop tsconfig.renderer.json and tsconfig.storybook.json typechecks
  • apps/desktop/src/main/__tests__/{assistant,thinking}-stream.test.ts — 12/12
  • vite build of the renderer, A/B against the same tree with the barrel export restored
  • workbar-boundary.test.ts — 6/6

@github-actions github-actions Bot added the effort/L Under 1000 readable lines label Aug 28, 2026
The feature barrel statically re-exported `WorkbarSurface`, and
`app-shell` imports `WorkbarHost` from that barrel, so the surface and
its five nested lazy tool panels landed in the eager chunk anyway.
rolldown named it: INEFFECTIVE_DYNAMIC_IMPORT.

Move the export to the `testing` entry, which the feature boundary test
already recognizes as public and nothing shipped imports, and point the
two Storybook consumers there.

Renderer entry chunk 2,245.33 kB -> 2,166.20 kB (gzip 451.12 -> 426.86),
with `workbar-surface` now emitted as its own 81.31 kB chunk, and the
build warning is gone.
Four workbar files reached `ComposerProps` through a seven- or
eight-level relative path into `packages/ui/dist/composer.d.ts`, a build
artifact. `@maka/ui` already exports the type, and all four files
already import from it.
`assistant-stream` and `thinking-stream` were two copies of one
authority: identical Options/Result shapes, the same five-step
redact-append-cap pipeline, the same non-string guard, structurally
identical complete paths. They differed only in caps, marker strings,
and which end of an over-cap buffer survives — a direction
`streaming-display-redaction` already parameterizes as `recovery`.

`stream-delta` now owns the pipeline; the two modules keep their
exported names, caps, and option types as thin wrappers that supply
their own spec. Head-keep's short-circuit on a frozen buffer is now
expressed as a property of `recovery: 'head'` rather than of the
assistant stream, which is what it always was.

`tool-output-stream` stays separate: it accumulates a chunk array with
dedup-by-seq, a different problem.
The first two render-phase branches reseeded `activation` with a
byte-identical object literal, so they are one condition. The third
branch clears `initialLiveContent` and stays as it is.

The snapshot passed to `ChatView` also dropped its session guard: every
branch reseeds `sessionId` to `activeSessionId`, and a render-phase
setState re-runs the component body before anything commits, so the
mismatched arm could never reach the DOM.
The layout effect deliberately runs on every render, and it wrote
`tabIndex` on every row each time. An identical assignment still
invalidates style and forces synchronous layout — DevTools charged the
loop 224ms of reflow across the module pages that use it.

Compare before assigning. A freshly mounted row still gets its tabindex,
because it arrives at the default 0.
@Astro-Han
Astro-Han force-pushed the claude/eager-rosalind-e4b5f3 branch from d653320 to 0309897 Compare August 28, 2026 15:54
@Astro-Han
Astro-Han marked this pull request as ready for review August 28, 2026 15:56
@Astro-Han

Copy link
Copy Markdown
Contributor Author

Reopened as a branch that follows the repo's <type>/<description> convention.

@Astro-Han Astro-Han closed this Aug 28, 2026
@Astro-Han
Astro-Han deleted the claude/eager-rosalind-e4b5f3 branch August 28, 2026 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/L Under 1000 readable lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant