Unminified CSS or JavaScript
What is this issue?
Minification strips whitespace, comments and long names out of CSS and JavaScript without changing what the code does. An unminified file is larger than it needs to be, and every visitor downloads the difference.
This check reports pages where minifying the CSS and JavaScript they load would save 2 KiB or more.
Why it matters
- Every byte is downloaded on every uncached visit, and on a mobile connection download time is load time.
- Render-blocking files delay the first paint byte for byte: an unminified
stylesheet in the
<head>holds the whole page back. - It is one of the cheapest fixes in performance work -- usually a build setting.
Fixing it removes a standard-severity finding from the site's health score.
How to fix it
Turn on minification in your build. Vite, webpack, esbuild, Next.js and most frameworks minify production builds by default; check you are deploying the production build, not the development one.
Minify files outside the build -- hand-written scripts, theme files, plugin assets -- with a tool such as
terser(JavaScript) orcssnano/lightningcss(CSS).Let your CDN do it where it offers automatic minification for CSS and JS.
Serve the
.minbuilds of third-party libraries rather than their readable copies.
Examples
1. A development build in production
Fails -- 48 KiB of savings: the site was deployed with NODE_ENV=development.
// Initialise the carousel on every element with the data attribute
function initialiseCarousel(element) {
const configuration = readConfiguration(element);Passes -- the production build:
function n(e){const t=r(e);2. A theme stylesheet edited by hand
Fails -- 6 KiB of savings from comments and indentation in theme.css.
Passes -- the same file run through lightningcss --minify.
How PixyScan detects this
Chooses which pages to measure. After the crawl, PixyScan measures the homepage plus the pages your own site links to most, up to a per-scan budget (ten pages by default, at most fifty). Measuring every page would take hours and exhaust the PageSpeed Insights quota of the API key it runs under.
Asks the PageSpeed Insights API about each of them, on mobile. This needs the Hobby plan or above and a PageSpeed Insights API key on the site or its workspace.
Reads the Lighthouse audit
unminified-cssandunminified-javascript, which list each file whose minified copy would be at least 2 KiB (and 5%) smaller. The two are combined: CSS and JavaScript are one check.Raises the issue when the combined savings reach 2 KiB -- the same per-file floor Lighthouse uses, so in practice when Lighthouse lists any file.
Raises nothing on a page it did not measure. A page outside the sample, and a page whose measurement failed, are both reported as
Not measured. Neither is treated as passing, and neither can fail this check.
What we store
Storage Level
Page Level
Database Table / Prisma Model
PagePerformance (page_performance), with the finding itself on
audit_issues.details.
Fields Used
| Field | Type | Description |
|---|---|---|
| strategy | String | mobile or desktop. Every number in the row belongs to one form factor. |
| fetchedAt | DateTime | When PageSpeed answered. "Measured three weeks ago" is not "not measured". |
| errorReason | String? | Why a sampled page still has no numbers. Null when the call succeeded. |
| audits | Json? | A compact summary of the Lighthouse audits the opportunity checks read: per audit its source (the Lighthouse audit id it was read from), score, numericValue, displayValue, itemCount, totals over every row (wastedBytes, wastedMs, blockingTime, mainThreadTime) and the five worst rows. Keyed by the classic Lighthouse audit id. Null when the response carried no audits. |
On the finding (audit_issues.details): message, plus audits (the Lighthouse audit ids read), wastedBytes (combined savings over every file), thresholdBytes (2048), fileCount and items (the five largest savings, each url, totalBytes, wastedBytes).
Detection Dependencies
- PageSpeed Insights API v5 (
lighthouseResult.audits), mobile strategy - The PageSpeed plan feature (Hobby and above) and a PageSpeed Insights API key
- The crawl's internal link graph, which decides which pages are sampled
Note
A page with no row was never measured. The pass samples the homepage plus the
most-linked pages within a per-scan budget (default 10, at most 50), so most pages of a
site have no page_performance row at all. That is the normal state, it is drawn as
Not measured, and this check cannot be raised against it.
A row whose metric columns are all null with an errorReason set is a different state
again: the page WAS sampled and the measurement failed. It is still never reported as
passing.