2 Commits
Author SHA1 Message Date
Andreas Reinhold / reiniandClaude Opus 5 5e7c8b2b58 Pin Vite's deduplication for an application-shaped entry
Plan step 37 review. The Vite test counted each of four files' plain
root rule, which the minifier folds into one even when a build repeats
the whole stylesheet: it passed against the Workbench's Tailwind entry,
which repeated 231 rules. It now asserts that no innermost rule repeats
under the same at-rules, which that build fails and a deduplicating one
passes, and it builds a second entry shaped like an application's —
outside the package, the foundation, then four component stylesheets
that each import button.css, and button.css again — where button.css
must also keep its first position. The fixture config refuses to run
without DEDUP_OUT_DIR, so it never writes into the package tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-15 03:12:54 +02:00
Andreas Reinhold / reiniandClaude Sonnet 5 792ec44d5e Add Stylesheets::bundle(), a build-free CSS import resolver
Plan step 37: the showcase and the error page's fallback serve CSS
without the application's Vite build, so nothing deduplicates their
@imports for them the way Vite's bundled postcss-import does — a
browser's native @import fetches every occurrence, it does not skip a
file it already loaded. Stylesheets::bundle(array $files, ?string
$base = null): string does in PHP what that build step does: it
inlines every @import depth-first, each file once, first occurrence
kept; leaves a bare specifier or an absolute URL untouched; rewrites a
relative url() against $base (or, without one, against the directory
of $files[0]); breaks a cycle instead of looping; throws naming the
importer when an import is missing; and caches per resolved file list
and mtime, with resetCache() for tests.

tests/Feature/StylesheetsBundleTest.php covers bundle()'s own
behaviour (dedup, url() rewriting, cycles, the missing-import
exception, the cache) and, at the end, pins the Vite deduplication
bundle() is modelled on against a real build — of all.css alone
(tests/Fixtures/dedup.vite.config.mjs), whose docblock explains why:
the Workbench's own entry still shares one file with @tailwindcss/vite
until plan step 39 removes it, and that plugin bundles its whole
reachable module graph itself, without the same dedup guarantee.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
2026-09-15 02:49:59 +02:00