Skip to content

Add experimental unused CSS checker - #34

Closed
gregjotau wants to merge 2 commits into
mainfrom
css-dead-check
Closed

Add experimental unused CSS checker#34
gregjotau wants to merge 2 commits into
mainfrom
css-dead-check

Conversation

@gregjotau

Copy link
Copy Markdown
Contributor

Why

We want unused first-party CSS to fail the build, the same way unused messages already can. Before flipping that switch, the compiler needs a conservative checker we can run against ReAI and inspect for false positives.

What

  • Parses first-party .css under src/main/resources/static (skips vendor/)
  • Collects class tokens from HTML class / th:class, Kotlin/Java/JS string literals
  • Prefix-matches interpolations such as r-analytics-sparkline-bar-$index
  • Treats htmx-request / htmx-indicator as runtime-applied
  • Writes build/reports/thim/css.json and warns; failOnUnusedCss.set(true) fails the build
  • cssUsage.from(...) lists extra modules that share the stylesheet
  • Standalone: ./gradlew :compiler:cssCheck --args='--css=... --usage=...'

ReAI result

Against web-app CSS plus usage from web-app, enak, and timesheet:

  • 442 defined classes
  • 434 exact uses, 7 prefix-used sparkline bars
  • 1 unused class: r-max-md:r-font-size-l (only exists in base.css, never referenced)

Scanning only web-app looked like 25 unused classes; 22 of those were live in Enak templates. Two more lived in timesheet. The remaining one is real dead CSS.

failOnUnusedCss stays off until consuming apps list every shared usage root.

Scan first-party stylesheets during Thim compilation and report classes
that never appear in templates, Kotlin/Java, or first-party JS. Prefix
matches cover interpolated names. Vendor CSS is ignored. The default is
warn-and-report; failOnUnusedCss turns unused classes into a build error.
Read backtick strings, nested quotes inside interpolations, and the last
class token before $ so short prefixes like r-is- and r-mchart- count as
used.
@gregjotau

Copy link
Copy Markdown
Contributor Author

Follow-up scan after teaching the checker JS backticks, nested quotes in `${}`, and last-token prefixes such as `r-is-` / `r-mchart-`.

Utin (web-app CSS, usage across the repo): 1000 defined, 988 exact, 12 prefix-used, 0 unused.

Eteo admin: 27 defined, 27 used, 0 unused.

Eteo web-app: 223 defined, 189 used, 34 unused leftover landing/signup rules. Cleanup PR opened separately.

ReAI still has the one unused class (`r-max-md:r-font-size-l`); cleanup PR opened separately.

`failOnUnusedCss` stays off until apps list every shared usage root.

@gregjotau

Copy link
Copy Markdown
Contributor Author

Superseded by #46. The released implementation uses one cacheable application-wide root task, discovers production usage across all Gradle modules automatically, participates in check and thimCheck, and fails by default. This removes the manual usage-root/configuration burden from this prototype.

@gregjotau gregjotau closed this Aug 22, 2026
@gregjotau
gregjotau deleted the css-dead-check branch August 22, 2026 07:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant