Skip to content

perf: split client bundle to reduce large initial JS chunk #73

Description

@vishr

Summary

The production client build currently emits a large main JavaScript chunk:

dist/assets/index-DtXPVynI.js   1,449.28 kB | gzip: 454.26 kB

Vite warns that the main chunk exceeds the default size threshold. The app still builds and works, but the current bundle shape increases initial download, parse, and execution cost.

Current state

  • client/src/App.tsx eagerly imports every route
  • client/src/components/blocks/BlockRenderer.tsx eagerly imports every block type
  • heavy visualization dependencies are pulled into the main path:
    • echarts via client/src/lib/echarts.ts
    • d3 via FlameGraphBlock and TraceWaterfallBlock
    • markdown/rendering helpers through chat rendering
  • DemoPage is bundled into the main app even though it is only a showcase route

Goal

Reduce initial client JS without making the codebase harder to follow.

Proposed work

  1. Add route-level lazy loading in client/src/App.tsx
    • lazy load HomePage, ServicePage, AlertsPage, ChatPage, and DemoPage
    • keep a simple Suspense fallback
  2. Split heavy block rendering in client/src/components/blocks/BlockRenderer.tsx
    • lazy load the expensive visualization blocks:
      • TimeseriesBlock
      • BarBlock
      • HeatmapBlock
      • TopologyBlock
      • SankeyBlock
      • CorrelationBlock
      • FlameGraphBlock
      • TraceWaterfallBlock
    • keep lightweight blocks eager
  3. Isolate DemoPage completely from the main application chunk
  4. Rebuild and measure the new chunk layout
  5. Only if needed after real lazy loading, add manualChunks in client/vite.config.ts for large vendor groups such as echarts, d3, and markdown-related packages

Non-goal

Do not silence the warning by only increasing chunkSizeWarningLimit. The fix should be actual code-splitting.

Acceptance criteria

  • the main entry chunk is materially smaller than the current ~1.45 MB minified output
  • route transitions still work correctly
  • chart and trace blocks still render correctly when loaded lazily
  • bun run build passes
  • the remaining Vite warning is gone or clearly reduced to a justified vendor split

Activity

  1. vishr commented on Aug 21, 2026

    @vishr
    MemberAuthor

    Current baseline after the UI rewrite: bun run build in ui/host passes and emits route/dashboard/auth chunks, with the main entry at 930.84 kB minified / 265.98 kB gzip versus the original 1,449.28 kB / 454.26 kB gzip. Vite still reports a >500 kB chunk warning, so the performance goal is improved but not complete. The old client/ paths should now be read as ui/host/ and the current MCP App frame/shared dependency graph.

  2. vishr commented on Aug 22, 2026

    @vishr
    MemberAuthor

    Measured, from a clean just ui on main

    Recording real numbers so this can be prioritised against everything else rather than argued from impression:

    Artifact Raw gzip
    assets/index-*.js 930.84 kB 265.99 kB
    logs.html (single-file app) 1,504.74 kB 419.76 kB
    trace.html (single-file app) 937.04 kB 228.98 kB
    assets/mcp-app-frame-*.js 298.11 kB 83.60 kB
    assets/dashboard-*.js 133.96 kB 38.22 kB
    assets/auth-*.js 83.70 kB 25.40 kB
    assets/index-*.css 235.67 kB 34.85 kB

    The build already warns about this and suggests build.rolldownOptions.output.codeSplitting.

    Two observations that affect priority:

    • The route-level chunks are already small — dashboards.index and chat.index are well under 1 kB. The weight is concentrated in the shared index-*.js entry, so the win is in what that entry pulls in eagerly, not in adding more route splits.
    • The logs and trace apps are deliberately built as single-file bundles, so they will not benefit from splitting the host. They are separately the two largest artifacts, and worth measuring on their own terms.

    This is a first-impression cost: 266 kB gzip lands before anything renders, on the first dashboard a reviewer or evaluator sees. It is not a launch blocker, but it is the sort of thing that gets screenshotted.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions