Repository navigation
Description
Parent track: #21 (bundle-size ratchet-down). Split out per the 2026-07-10 investigation there — this is the one real bundle-reduction lever found, but it's a multi-day architectural project, not a gate chore, so it lives on its own.
Summary
The spreadsheet engine + its UI compile into the same single *_bg.wasm as the document editor and load on every page, even pure-document sessions that never open a sheet. Deferring it behind a dynamic load is the largest available WASM reduction.
Size (rough, from the #21 twiggy investigation)
- Engine (
src/spreadsheet/{eval,functions,parser,pivot,stats,translate}.rs) + UI (src/components/spreadsheet_view.rs) = 294,746 B raw pre-opt = 5.3% of real code / ~25% of our own app code. - Proportional estimate on the shipped baseline (~1,712,714 B gzip): ~85–90 KB gzipped saved on non-spreadsheet page loads.
- Heavily caveated: linear pre-opt→post-opt-gzip scaling is not exact; treat as order-of-magnitude, not a promise. A precise number needs
wasm-optwith names preserved through the pipeline (not currently installed). - Single biggest function in the engine:
spreadsheet::functions::call_function= 124,301 B (a large match over every sheet function) — a secondary, self-contained target if the split proves too heavy.
Why it's not a quick change (separability blocker)
src/pages/document.rsimportsSpreadsheetViewunconditionally (use crate::components::spreadsheet_view::SpreadsheetView;) and branches ondoc_typeat runtime inside one page component — there is no module boundary isolating spreadsheet code from the document page today.- Genuine lazy-loading requires either:
- A second
wasm-bindgentarget compiled to its own.wasm+ JS-sideimport()glue, plus a way to bridge Leptos reactive state across two wasm instances; or - Restructuring
pages::document.rsto defer theSpreadsheetViewimport behind a dynamic-loading shim.
- A second
- Neither exists in the current Trunk / Leptos-CSR setup. This is the bulk of the work.
Don't forget the CSS
spreadsheet.css (~37 KB, frontend/dist/spreadsheet-*.css) is loaded unconditionally via a static <link> in index.html — outside the WASM gate. Splitting the WASM without also deferring this CSS only captures part of the win.
Severity
S4 — no user-facing issue; a bundle-weight optimization. Deferred: high effort, medium-uncertain payoff, and even a perfect split leaves the bundle at ~1.61 MB (Leptos framework internals are ~34.5% of the bundle and structurally dominate — see #21). Pick up when someone has multi-day appetite for the CSR code-splitting infra, not under gate pressure.
Suspected area
frontend/src/pages/document.rs— the unconditional import + runtimedoc_typebranchfrontend/src/components/spreadsheet_view.rs,frontend/src/spreadsheet/— the code to splitfrontend/index.html— static spreadsheet CSS<link>frontend/Trunk.toml/ build config — where a second wasm target / dynamic import would be wired
Activity
perf(frontend): load spreadsheet CSS on demand (#30, partial) (#109)