feat: purge CSS by default, safely (production purge + guarded default flip)#2052
Merged
Conversation
…t flip) Flip the theme default to style.purge = true and make purging safe in every environment: - Purge runs only in production, where css.PostCSS executes inside resources.PostProcess (after every page renders) so PurgeCSS reads a complete hugo_stats.json. This is Hugo's documented purge pattern. - Development (hugo server, where PostProcess does not run and the stats are incomplete) serves the unpurged CSS — every class is present, so no rule is ever dropped against partial stats. This structurally removes the dev-server purge-poisoning failure class. - Guard the flip: when style.purge is on but the site has no config/postcss.config.js, skip purging and emit an actionable warning instead of failing. (A config that fails at runtime still errors at post-process, as css.PostCSS is deferred and cannot be caught in the template.) - Stop committing the generated hugo_stats.json (root and exampleSite) and gitignore it; build.buildStats still regenerates it on every build. Migration: existing sites that relied on the previous purge=false default now ship purged CSS. If a site has a stale safelist or custom classes only added by JS, review the PostCSS safelist. Set style.purge = false to opt out. exampleSite gate: purge-ON byte-identical to the prior output (run-vs-run deterministic), purge-OFF equals the unpurged baseline, selector audit shows no over-purges, and the component smoke (modal/dropdown/carousel/offcanvas/ datatables/dark-mode/search) survives purge.
✅ Deploy Preview for gethinode-demo ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
markdumay
enabled auto-merge
July 17, 2026 17:08
Collaborator
Author
|
🎉 This PR is included in version 3.6.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Flips the theme default to
style.purge = trueand makes purging safe in every environment.css.PostCSSexecutes insideresources.PostProcess— afterevery page has rendered — so PurgeCSS reads a complete
hugo_stats.json. This is Hugo's owndocumented purge pattern; it already worked, this PR just makes it the default.
hugo server,resources.PostProcessdoes not runand the stats are incomplete, so purging there would drop rules against partial stats. Instead
dev ships the unpurged CSS (every class present). This structurally removes the dev-server
purge-poisoning failure class (the 2026-07-14 issue) — dev never purges, so there is nothing
to poison.
style.purgeis on but the site has noconfig/postcss.config.js,purge is skipped with an actionable
warn-purge-postcsswarning rather than a failure.hugo_stats.json(root + exampleSite) and gitignore it.build.buildStatsstill regenerates it each build.
Heads-up for review
try-wrap not included (and why). The program spec wanted atry-wrappedcss.PostCSStodowngrade missing-npm-deps failures to a warning. That is not achievable for the production
path:
css.PostCSSis lazy and runs insideresources.PostProcessafter all pages render, soits error surfaces at post-process — outside any
tryscope (verified: a broken config panics;the
trycatches nothing). Theos.FileExistspre-check covers the common "purge on, no config"case gracefully; a present-but-broken config fails loudly but actionably (Hugo prints the error).
ExecuteAsTemplatecleanup). This PR's diff includesthat one-line commit until perf: drop redundant whole-bundle ExecuteAsTemplate pass in stylesheet #2050 merges; merge perf: drop redundant whole-bundle ExecuteAsTemplate pass in stylesheet #2050 first.
0 over-purges.
Evidence (exampleSite,
hugo --gc --minify)unpurged baseline (575,913 B).
in main.css; all
datatable-*survive in the module bundle; dark-mode/search/cky-/fa- present.Migration (for release notes)
Sites that relied on the old
purge = falsedefault now ship purged CSS. If a site has a stalesafelist or classes only added by JS, review
config/postcss.config.js's safelist. Opt out withstyle.purge = false.Part of the styles-pipeline modernization program (slice S2). Held pending the maintainer merge gate.