Skip to content

fix: cut initial JS bundle 1 466 kB → 487 kB (−67%) — remove dead packages, lazy-load ExcelJS, split vendors#69

Merged
davidamunga merged 2 commits into
mainfrom
fix/bundle-bloat
Jul 14, 2026
Merged

fix: cut initial JS bundle 1 466 kB → 487 kB (−67%) — remove dead packages, lazy-load ExcelJS, split vendors#69
davidamunga merged 2 commits into
mainfrom
fix/bundle-bloat

Conversation

@davidamunga

Copy link
Copy Markdown
Owner

Problem

The entire app — including ExcelJS (~700 kB) — was bundled into a single 1 466 kB chunk loaded on every cold start, even when the user exports to CSV and never touches XLSX.

Changes

Dead-package removal

10 packages removed from package.json:

Package Reason
@radix-ui/react-checkbox replaced by @base-ui/react
@radix-ui/react-label replaced by @base-ui/react
@radix-ui/react-scroll-area replaced by @base-ui/react
@radix-ui/react-select replaced by @base-ui/react
@radix-ui/react-slot replaced by @base-ui/react
@radix-ui/react-tooltip replaced by @base-ui/react
zustand never imported anywhere
react-day-picker only in unused calendar.tsx scaffold
@krakz999/tabula-node Node.js package, never imported in frontend
tauri-plugin-pldownloader-api used as a raw IPC string, not a module import

rollup-plugin-visualizer (dev) also removed (was added temporarily for analysis).

ExcelJS code-split (src/services/exportService.ts)

  • Removed the static import { XlsxService } — this was the root cause dragging ExcelJS into every page load
  • createDownloadLink and getFileBuffer now use await import("./xlsxService") for the XLSX branch only
  • getFileName inlined so no import is needed at all for the common metadata path

Vendor chunk splitting (vite.config.ts)

  • react + react-domvendor-react (separately cacheable)
  • @base-ui/reactvendor-base-ui
  • lucide-reactvendor-lucide
  • chunkSizeWarningLimit: 1100 to acknowledge the intentionally large lazy ExcelJS chunk

Deleted files

  • src/components/ui/calendar.tsx — only consumer of react-day-picker

Before / After

Metric Before After Delta
Initial JS (raw) 1 466 kB 487 kB −67%
Initial JS (gzip) 438 kB 158 kB −64%
ExcelJS loaded always deferred — loaded only on first XLSX export
Vendor caching single monolithic chunk 4 independently cacheable chunks

The xlsxService chunk (975 kB / 279 kB gzip) is loaded on demand and then browser-cached.

Test plan

  • pnpm build completes with no errors or unexpected warnings
  • App loads and all non-XLSX export formats work (CSV, JSON, OFX, QFX, QIF)
  • XLSX export works (triggers lazy load of xlsxService chunk)
  • pnpm audit still shows no known vulnerabilities

- Remove 10 unused packages: @radix-ui/* (6 pkgs, fully replaced by @base-ui),
  zustand, react-day-picker, @krakz999/tabula-node,
  tauri-plugin-pldownloader-api, and rollup-plugin-visualizer
- Delete calendar.tsx (only consumer of the removed react-day-picker)
- Lazy-load XlsxService/ExcelJS via dynamic import() in exportService.ts —
  ExcelJS (~700 kB raw) is now deferred to a separate xlsxService chunk that
  is only fetched when the user first exports to XLSX
- Inline ExportService.getFileName() so the static XlsxService import is fully
  eliminated from the initial module graph
- Add vite manualChunks to split react, @base-ui, and lucide-react into
  separately cacheable vendor chunks; raise chunkSizeWarningLimit to 1 100 kB
  to acknowledge the intentionally lazy ExcelJS chunk
@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@davidamunga davidamunga self-assigned this Jul 14, 2026
@davidamunga
davidamunga merged commit f873b5a into main Jul 14, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant