Problem
The production JavaScript bundle is a single 6.8 MB main.js with no code splitting. Enabling gzip in #261 brought the transfer down to 2.0 MB, which made the site usable again — but 2 MB before first paint is still a lot, and compression is a mitigation rather than a fix.
Before #261 this made demo.actyze.ai effectively unusable: a headless browser could not finish domcontentloaded within 60 seconds on a normal connection.
What is in the bundle
From frontend/package.json, all of these are pulled into the single entry chunk:
| Package |
Why it is heavy |
plotly.js-dist-min |
~3 MB on its own; the largest single contributor |
xlsx |
spreadsheet export |
jspdf |
PDF export |
html2canvas |
screenshot/export path |
@uiw/react-codemirror + @codemirror/lang-sql |
SQL editor |
@mui/material + @mui/icons-material |
UI framework |
Most of these are only needed on specific screens or user actions. A user who opens the dashboard and never exports anything still downloads xlsx, jspdf and html2canvas.
Suggested approach
- Measure first. Add
source-map-explorer or webpack-bundle-analyzer and record what the actual split looks like — the table above is inferred from dependencies, not measured.
- Lazy-load the obvious candidates with
React.lazy() + Suspense:
- the export paths (
xlsx, jspdf, html2canvas) behind the export buttons
- the SQL editor (
codemirror) behind the query view
- Plotly behind the chart components
- Consider
plotly.js-basic-dist-min instead of the full distribution if only standard chart types are used. This alone could remove a large fraction.
- Route-level splitting via
React.lazy on the router.
Note on tooling
The app is on react-scripts@5.0.1 (Create React App), which is unmaintained and gives limited control over chunking. Migrating to Vite would make this substantially easier and is worth evaluating as part of the work — though it should be a deliberate decision, not a side effect.
Definition of done
- Initial JS transfer meaningfully below the current 2.0 MB gzipped
- Export, SQL editor and chart functionality all still work
- A bundle size budget enforced in CI so this cannot silently regress again
Context
Compression is already in place (#261), so this is no longer urgent — but it is the actual fix. Related: #261.
Problem
The production JavaScript bundle is a single 6.8 MB
main.jswith no code splitting. Enabling gzip in #261 brought the transfer down to 2.0 MB, which made the site usable again — but 2 MB before first paint is still a lot, and compression is a mitigation rather than a fix.Before #261 this made
demo.actyze.aieffectively unusable: a headless browser could not finishdomcontentloadedwithin 60 seconds on a normal connection.What is in the bundle
From
frontend/package.json, all of these are pulled into the single entry chunk:plotly.js-dist-minxlsxjspdfhtml2canvas@uiw/react-codemirror+@codemirror/lang-sql@mui/material+@mui/icons-materialMost of these are only needed on specific screens or user actions. A user who opens the dashboard and never exports anything still downloads
xlsx,jspdfandhtml2canvas.Suggested approach
source-map-explorerorwebpack-bundle-analyzerand record what the actual split looks like — the table above is inferred from dependencies, not measured.React.lazy()+Suspense:xlsx,jspdf,html2canvas) behind the export buttonscodemirror) behind the query viewplotly.js-basic-dist-mininstead of the full distribution if only standard chart types are used. This alone could remove a large fraction.React.lazyon the router.Note on tooling
The app is on
react-scripts@5.0.1(Create React App), which is unmaintained and gives limited control over chunking. Migrating to Vite would make this substantially easier and is worth evaluating as part of the work — though it should be a deliberate decision, not a side effect.Definition of done
Context
Compression is already in place (#261), so this is no longer urgent — but it is the actual fix. Related: #261.