Chunk List

A sorted list of bundle chunks rendered as a proportional-bar table. Pass a flat list of chunks tagged with a type (vendor / runtime / app / async) and an optional entry flag; the widget sorts initial chunks first, draws each row's bar proportional to the largest chunk, and surfaces the initial-load total and grand total at the top.

Preview

Dashboard build

Chunks after splitting heavy feature libs out of the initial payload.

7 chunks196 KBinitial·561 KBtotal
  • vendor.js92 KB16%
  • main.js78 KB14%
  • shared.js22 KB4%
  • runtime.js4 KB1%
  • rich-editor.js145 KB26%
  • pdf-renderer.js130 KB23%
  • chart-lib.js90 KB16%
Customize
Chunk sizes
92KB
78KB
90KB
145KB
130KB
Options

Installation

npx shadcn@latest add https://craftbits.dev/r/chunk-list.json

Usage

import { ChunkList } from "@craft-bits/core";
 
<ChunkList
  title="Dashboard build"
  chunks={[
    { id: "vendor", name: "vendor.js", size: 92, type: "vendor" },
    { id: "runtime", name: "runtime.js", size: 4, type: "runtime" },
    { id: "main", name: "main.js", size: 78, type: "app" },
    { id: "chart", name: "chart-lib.js", size: 90, type: "async" },
  ]}
/>

Render a monolithic "before" by passing a single chunk:

<ChunkList
  chunks={[{ id: "main", name: "main.js", size: 385, type: "app" }]}
/>

Anatomy

  • Header. Optional title (renders with the cb-label style) and a description sub-line. Omit both for a chromeless panel.
  • Totals row. Chunk count on the left, initial · total on the right. Hide with hideTotals.
  • Row. Swatch + name + size on the top line; proportional bar below; role badge on the right. Bar width is size / maxSize, so the largest chunk spans the full row.
  • Role tone. vendor paints --cb-accent, app paints --cb-accent / 70%, async paints --cb-accent / 40%, runtime paints --cb-fg-subtle. Non-entry chunks render at 80% opacity.

Understanding the component

  1. Sort order. Entry chunks (initial render-blocking) sort above non-entry chunks. Within each group, rows sort by size descending — the largest cost reads first. entry defaults to true for every type except async, which defaults to false.
  2. Proportional widths. Each row's bar is chunk.size / maxSize — the visualization compares chunks against each other, not against the total. The total and the percent share live next to the size so you can read both magnitudes at once.
  3. Type badge. The right column carries the role tag (vendor / runtime / app / async). When a chunk is non-entry but not async (e.g. an app chunk lifted behind a dynamic import), the badge appends a lazy suffix so the deferred state stays visible.
  4. Layout animation. Each bar uses Motion's layout prop with the SPRINGS.snap token. When sizes change, the bars resize smoothly. Under prefers-reduced-motion the layout animation short-circuits and the bars snap.

Props

PropTypeDefaultDescription
chunksChunkListChunk[]requiredOrdered list of chunks.
titleReactNodeOptional heading above the list.
descriptionReactNodeOptional sub-headline under the title.
unitstring'KB'Display unit suffix for sizes.
hideTotalsbooleanfalseHide the chunk-count and initial/total row.
hidePercentbooleanfalseHide the per-row percent share.
headingAs'h2' | 'h3' | 'h4''h3'Tag for the title element.
ariaLabelstring'Bundle chunks'Accessible label for the list.
classNamestringMerged onto the root via cn().

ChunkListChunk

FieldTypeDescription
idstringStable identifier.
nameReactNodeVisible chunk label (e.g. main.js).
sizenumberChunk size in the widget's unit.
type'vendor' | 'runtime' | 'app' | 'async'Role tag. Drives swatch and badge tone. Defaults to 'app'.
entrybooleanWhether the chunk is part of the initial payload. Defaults to true for every type except async.

Accessibility

  • The wrapper is a <section> with data-cb-edu="chunk-list". Rows expose data-cb-type and data-cb-entry so consumers can extend per-tone styling without monkey-patching CSS.
  • The list is a role="list" of role="listitem" entries with aria-live="polite" so size updates are announced without interrupting the user.
  • The totals row carries an aria-label like initial 196 KB of 561 KB total so the headline number is conveyed without depending on color.
  • The bar and the type badge are decorative (aria-hidden) — the chunk name and size are the source of truth for assistive tech.
  • Layout animations short-circuit under prefers-reduced-motion.

Credits

  • Extracted from: terminal-dreams (src/components/frontend-design/perf-bundle/ui/ChunkList.tsx). The original consumed a BundleState from the BundleOptLab scrollytelling engine and rendered a CSS-module table with vendor-cached / initial / on-demand tags. This rewrite drops the engine coupling and the diagram-layer palette, generalises the chunk shape to { id, name, size, type?, entry? }, and surfaces a single sorted bar list with initial + total summaries so the widget can describe any bundle.