Files

7.3 KiB

Bundle Size Development Workflow

This package contains the internal bundle-size tooling used to measure Effect entrypoints with Rollup, minification, and gzip.

AI Agent Instructions

Use this workflow when a user wants to quickly understand how a local source change affects bundle size for one or more explicitly selected fixture files.

Do not scan scratchpad/ or packages/tools/bundle/fixtures/ for this workflow. Only measure files that the user explicitly names, or files you create specifically for the current investigation.

Before running a comparison, ask the user which mode they want:

  • default cleanup mode for a single check or one-off investigation;
  • keep-base mode for many repeated measurements, followed by explicit cleanup at the end.

Use cleanup mode unless the user says they expect to run multiple trials.

If the user asks what a generated bundle is made of, use the bundle composition workflow instead of the size comparison workflow.

Analyze Bundle Composition

Use this workflow when the user gives an explicit fixture and wants to understand which modules make up the produced bundle.

Agent procedure:

  1. Confirm the exact fixture path or paths to analyze. Do not scan directories.
  2. Run pnpm bundle-analyze with only those explicit paths.
  3. Read the printed Markdown table and identify the generated *.raw-data.json path for each fixture.
  4. Analyze *.raw-data.json first. Use *.treemap.html only when the user wants a visual artifact to open.
  5. Report the largest modules, notable dependency groups, and any surprising inclusions. Mention the generated artifact paths in the answer.

Prefer the repository-level wrapper:

pnpm bundle-analyze scratchpad/my-fixture.ts

You can pass multiple explicit files:

pnpm bundle-analyze \
  scratchpad/schema-codec.ts \
  scratchpad/schema-arbitrary.ts

The wrapper builds the current checkout with pnpm build before generating analysis artifacts, so the bundle is not produced from stale dist files.

By default, artifacts are written to tmp/bundle-analysis. Use --output-dir to choose another directory:

pnpm bundle-analyze --output-dir tmp/schema-analysis scratchpad/my-fixture.ts

For each selected fixture, the tool writes:

  • <name>.min.js: the generated Rollup output for inspection;
  • <name>.treemap.html: an interactive treemap for human inspection;
  • <name>.raw-data.json: raw visualizer data suitable for AI analysis.

The analysis build disables identifier mangling so module and export names stay readable in the visualizer output. Use bundle-compare-selected or report when exact size measurement is the goal.

After running the command, inspect the Markdown table it prints to find the exact paths. For an AI analysis, read the *.raw-data.json file first and summarize the largest modules and dependency groups. Use the *.treemap.html file when the user wants to inspect the bundle visually.

The raw data contains a tree plus module metadata. For a quick size-oriented summary, rank module parts by renderedLength or gzipLength, then map each part through metaUid to nodeMetas[metaUid].id.

Example inspection command:

node -e 'const data = JSON.parse(require("node:fs").readFileSync(process.argv[1], "utf8")); console.log(Object.entries(data.nodeParts).map(([uid, part]) => ({ uid, id: data.nodeMetas[part.metaUid]?.id, rendered: part.renderedLength, gzip: part.gzipLength })).sort((a, b) => b.rendered - a.rendered).slice(0, 20))' tmp/bundle-analysis/my-fixture.raw-data.json

Do not treat the generated .min.js size from this workflow as the exact bundle size comparison number. The analysis build keeps names readable for the visualizer. Use bundle-compare-selected or report for exact size reporting.

Do not use this workflow to compare against a base ref. Use bundle-compare-selected for size impact and bundle-analyze for current bundle composition.

Compare Explicit Scratchpad Fixtures

Prefer the repository-level wrapper:

pnpm bundle-compare-selected --base main scratchpad/my-fixture.ts

You can pass multiple explicit files:

pnpm bundle-compare-selected --base main \
  scratchpad/schema-codec.ts \
  scratchpad/schema-arbitrary.ts

If --base is omitted, the script compares against main.

By default, the wrapper removes tmp/bundle-base before exiting, including on failure. This avoids leaving extra git worktree state after a one-off measurement.

For repeated measurements where the user explicitly wants a faster feedback loop, pass --keep-base:

pnpm bundle-compare-selected --base main --keep-base scratchpad/my-fixture.ts

When using --keep-base, clean up tmp/bundle-base after the last measurement. The explicit final cleanup command is:

git worktree remove --force tmp/bundle-base

The wrapper:

  • builds the current checkout with pnpm build;
  • creates or reuses tmp/bundle-base at the requested base ref;
  • builds the base checkout when needed and writes tmp/bundle-base/.bundle-build-stamp only after a successful build;
  • reuses a kept base checkout only when its HEAD and .bundle-build-stamp both match the requested base ref;
  • copies only the selected files into the base checkout at the same relative paths;
  • invokes the internal bundle CLI to compare current vs base sizes.

The selected files are copied into the base checkout so the report isolates source changes instead of changes to the fixture text.

Expected output is a Markdown table:

| File Name                  | Current Size | Previous Size |    Difference     |
| :------------------------- | :----------: | :-----------: | :---------------: |
| `scratchpad/my-fixture.ts` |   42.10 KB   |   40.80 KB    | +1.30 KB (+3.19%) |

Internal CLI

Use the internal CLI directly only when the base checkout is already prepared and built:

node packages/tools/bundle/src/bin.ts compare-selected \
  --base-dir tmp/bundle-base \
  scratchpad/my-fixture.ts

The --base-dir value must be the root of the base checkout, not the base fixture directory.

Current Size Only

If the user only asks for the current bundled size, use:

pnpm --dir packages/tools/bundle report ../../../scratchpad/my-fixture.ts

This does not compare against a base ref.

Fixture Guidance

Keep temporary fixtures in scratchpad/.

Good temporary fixtures are small, focused entrypoints that import public package APIs:

import * as Effect from "effect/Effect"
import * as Schema from "effect/Schema"

const schema = Schema.Struct({
  name: Schema.String
})

Schema.decodeUnknownEffect(schema)({ name: "effect" }).pipe(Effect.runFork)

Prefer self-contained fixtures. The compare-selected workflow copies only the explicit entry files into the base checkout. If a fixture imports local relative helpers, either avoid that shape or make the entry fixture self-contained before measuring.

Do not add temporary fixtures to packages/tools/bundle/fixtures/. That directory is for stable comparison fixtures used by the regular bundle-size workflow.

Cleanup

The wrapper cleans up tmp/bundle-base by default. If --keep-base was used for a multi-run investigation, remove the worktree when the user is done.

To remove it:

git worktree remove --force tmp/bundle-base

To verify that cleanup succeeded:

git worktree list

Only the main repository worktree should remain.