Skip to content

chore(deps): narrow tailwind source scope in docs and playgrounds - #417

Merged
IgorShevchik merged 1 commit into
mainfrom
sync/nuxt-689c671
Aug 17, 2026
Merged

chore(deps): narrow tailwind source scope in docs and playgrounds#417
IgorShevchik merged 1 commit into
mainfrom
sync/nuxt-689c671

Conversation

@IgorShevchik

Copy link
Copy Markdown
Collaborator

Port of nuxt/ui@689c671a (nuxt/ui#6843). First of three in the current sync queue.

Upstream change

Every Tailwind entry point pointed source() at the repository root, so the CSS watcher scanned the whole tree — including directories the built site never renders.

-@import "tailwindcss" theme(static) source("../../../..");
+@import "tailwindcss" theme(static) source(none);
+@source "../../..";
+@source "../../../../src";

Naming what is in scope rather than what is out of it.

Deviations

Relative depths match upstream's, so the paths are verbatim. Two fork differences:

  • Four entry points, not three. We also carry playgrounds/demo. Checked its nuxt.config.ts for cross-directory dirs/aliases — none, it is self-contained — so it gets the same pair as playgrounds/nuxt.
  • playgrounds/vue borrows the same way upstream's does. Verified in our vite.config.ts rather than assumed: it lists ../nuxt/app/composables and ../nuxt/app/components, so @source "../../../../nuxt/app" applies here for the same reason it does upstream.

It deletes a fork-local patch

docs/app/assets/css/main.css carried:

@source not "../../../../.sync";

added because .sync/log/*.md quotes illustrative class strings with placeholders (--reka-*-content-available-height) that produce invalid CSS during build. That exclusion existed only to claw back part of a root source that was too broad. With source(none) the sync notes were never in scope, so the patch goes — the upstream approach subsumes it.

skills/ leaves the scan too, and does not need it: Nitro serves it raw as a publicAssets entry at /.well-known/skills, so its class strings are file bytes and never reach the DOM.

Verification

docs:generate does not test this — it succeeds either way. The question is whether a narrower scan drops a rule the site needs, so the check is a before/after diff of the emitted stylesheet.

237 class selectors disappear, 0 appear. 593,334 → 574,778 bytes. Every one accounted for:

bucket n verdict
occur only in playgrounds/, test/, skills/ 227 correct to drop
CHANGELOG.md prose — focus:outline-hidden, aria-busy:cursor-progress 2 correct; both quoted in entries saying the class was removed — the same noise the .sync exclusion existed for
upstream spellings of classes we write differently 8 correct; e.g. animate-[accordion-down_200ms_ease-out] vs our …_200ms_var(--ease-out), which is present in both builds

The decisive check is direct rather than inferential. Across the 201 prerendered pages, 2,046 distinct class tokens appear in class="…" attributes:

classes the HTML actually uses that the new CSS no longer defines: 0

A wrong answer on the way there

The first pass at the bucket analysis reported 30 regressions. It was wrong: it matched substrings, so py-3.5 was "found" in src/theme/table-wrapper.ts inside [&>table>thead>tr>td]:py-3.5 — a different generated class, since a variant prefix produces a different selector. Matching whole unprefixed tokens takes it to zero. Recorded because the same mistake is easy to repeat the next time someone audits a @source change.

Verify (CI=true)

lint · typecheck · test · build · docs:generate — all green. Tests 6540 passed | 6 skipped across 286 files. docs:generate run with deploy.yml's env, 1240 routes prerendered.

Ledger

cursor advances to 689c671a, entry added, log at .sync/log/689c671a….md. pr/b24ui_sha are pending-merge and get reconciled by the next commit in the queue, per PORTING.md §6 step 4.

Remaining in the queue: a4fe7d86 (docs(page-hero), expected n/a — no page-hero.md here) and 08e75317 (docs: resolve icon load failures during prerender, expected largely n/a — no @nuxt/icon/clientBundle in our docs; its code-icon.ts half is a pure alphabetical reorder, 65 key→value pairs identical before and after).


Generated by Claude Code

Port of nuxt/ui@689c671a (#6843).

Every Tailwind entry point pointed `source()` at the repository root, so
the CSS watcher scanned the whole tree — including directories the built
site never renders. Replaced with `source(none)` plus an explicit `@source`
per directory that is genuinely in scope: naming what is in rather than
what is out.

The relative depths match upstream's, so the paths are verbatim. Two fork
differences. We carry a fourth entry point, `playgrounds/demo`, which is
self-contained — no cross-directory `dirs` or aliases in its config — so it
gets the same pair as `playgrounds/nuxt`. And `playgrounds/vue` borrows
`../nuxt/app/{components,composables}` through `vite.config.ts` exactly as
upstream's does, checked rather than assumed, so it keeps that `@source`
too.

This deletes a fork-local patch. `docs/app/assets/css/main.css` carried
`@source not "../../../../.sync"`, added because `.sync/log/*.md` quotes
illustrative class strings with placeholders that produce invalid CSS. That
exclusion existed only to claw back part of a root source that was too
broad; with nothing in scope by default it is unnecessary. `skills/` leaves
the scan too and does not need it — Nitro serves it raw at
`/.well-known/skills`, so its class strings are file bytes, never DOM.

`docs:generate` does not test this: it succeeds either way. The question is
whether the narrower scan drops a rule the site needs, so the check was a
before/after diff of the emitted stylesheet. 237 selectors disappear and 0
appear, 593,334 -> 574,778 bytes. 227 occur only in `playgrounds/`, `test/`
or `skills/`; 2 came from `CHANGELOG.md` prose, quoting classes the entries
say were removed — the same noise the `.sync` exclusion was for; the rest
are upstream spellings of classes we write differently, such as
`animate-[accordion-down_200ms_ease-out]` against our `var(--ease-out)`
form, which is present in both builds.

The decisive check is direct rather than inferential: across the 201
prerendered pages, 2,046 distinct class tokens appear in `class="…"`
attributes and none of them lost its rule.

An earlier pass here reported 30 regressions and was wrong — it matched
substrings, so `py-3.5` was "found" inside `[&>table>thead>tr>td]:py-3.5`,
which is a different generated class. Whole unprefixed tokens bring it to
zero.

Verify (CI=true): lint · typecheck · test (6540 passed, 6 skipped, 286
files) · build · docs:generate (1240 routes) — all green.
@IgorShevchik
IgorShevchik merged commit 72a5957 into main Aug 17, 2026
1 check passed
@IgorShevchik
IgorShevchik deleted the sync/nuxt-689c671 branch August 17, 2026 05:18
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.

2 participants