squirrelscan
GitHub

JavaScript bundle too large: the 250 KB and 1 MB limits

Scripts over 250 KB warn and over 1 MB fail. squirrel measures every JavaScript file the crawl found and names the pages that load it.

What JavaScript size costs

A JavaScript file costs twice. It costs bandwidth to download, which scales with connection speed, and it costs main-thread time to parse and execute, which scales with device. The second cost is the one that hurts: a mid-range phone parses JavaScript several times slower than a laptop, and none of that time is visible in a transfer-size number.

Bundle size is usually a dependency question rather than an application-code question. A date library included whole for one format call, an icon set imported as a barrel file, and a polyfill bundle serving browsers nobody uses are the common three.

What squirrel checks

The rule runs once per crawl over the script resources the crawl collected, with their sizes and the pages that referenced them. It emits one or two checks:

  • js-file-size, passing with the message No JavaScript files detected when the crawl found none.
  • js-file-size, failing with the message N JS file(s) exceed 1.0 MB and one item per file, carrying its size, HTTP status, content type and the pages that load it.
  • js-file-size-warn, warning with the message N JS file(s) exceed 250.0 KB for files above the warning threshold but not above the error one, with the same items.
  • js-file-size, passing with the message All JavaScript files are within size limits when nothing crossed either threshold.

Sizes are the transferred sizes the crawl observed. A file whose size could not be determined is counted in neither bucket. The fail and warn checks can both appear on the same audit, since they cover different files.

How to fix it

Split the bundle so a route loads only its own code:

const Editor = lazy(() => import("./editor"));

Then look at what the shared chunk contains. A bundle analyser against the production build names the dependency responsible far faster than reading imports, and the answer is usually one package that has a smaller equivalent or a per-function import path.

The common false positive is a single bundle deliberately shipped for the whole application and cached across every route. The transfer is paid once, so the finding is true of the first visit, but a cached second navigation pays only the parse and execute cost.

Rule IDperf/js-file-size
CategoryPerformance
ScopeSite-wide
Severityerror
Weight7/10

Options

OptionTypeDefaultDescription
warn_bytesnumber256000 (250 KB)Byte size to trigger warning
error_bytesnumber1048576 (1 MB)Byte size to trigger error

Configuration example

[rules."perf/js-file-size"]
warn_bytes = 256000
error_bytes = 1048576

Enable / disable

Disable this rule

[rules]
disable = ["perf/js-file-size"]

Disable all Performance rules

[rules]
disable = ["perf/*"]

Enable only this rule

[rules]
enable = ["perf/js-file-size"]

enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.

Performance findings ship in every audit next to the SEO, security and agent experience rules. See Core Web Vitals for how an agent works through a report.

References

Check your site

Run squirrel audit https://example.com and open the Performance section of the report. Every oversized script is listed with its size and the pages that load it. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.

Type to search…

↑↓ navigate↵ openesc close