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
This commit is contained in:
Andreas Reinhold / reini
2026-09-15 03:12:54 +02:00
co-authored by Claude Opus 5
parent 3854f4321c
commit 5e7c8b2b58
3 changed files with 109 additions and 38 deletions
+14
View File
@@ -0,0 +1,14 @@
/*
* An application's own CSS entry, the way plan step 37's claim is about: outside the package, the
* foundation first, then the stylesheet of each component its views render. Split button, app bar,
* modal and pagination each import button.css (and icon.css, through it), and the application
* names button.css itself once more at the end. Built by tests/Fixtures/dedup.vite.config.mjs for
* StylesheetsBundleTest.php, which expects every shared rule once, at its first position.
*/
@import '../../resources/css/foundation.css';
@import '../../resources/css/components/split-button.css';
@import '../../resources/css/components/app-bar.css';
@import '../../resources/css/components/modal.css';
@import '../../resources/css/components/pagination.css';
@import '../../resources/css/components/button.css';
+19 -13
View File
@@ -1,25 +1,31 @@
import { defineConfig } from 'vite';
// Builds resources/css/all.css alone, with no other plugin in the graph: it isolates Vite's own
// bundled postcss-import, whose `skipDuplicates` option is the mechanism
// docs/plans/material-3-alignment.md's "Tailwind's footprint" paragraph measured and
// StylesheetsBundleTest.php pins against the real bundler — a stylesheet several files import
// lands once, at its first position.
// Builds two CSS entries with no plugin in the graph, isolating Vite's own bundled postcss-import,
// whose `skipDuplicates` option is the mechanism docs/plans/material-3-alignment.md's "Tailwind's
// footprint" paragraph measured and StylesheetsBundleTest.php pins: resources/css/all.css, and
// tests/Fixtures/dedup-app.css, an application-shaped entry importing per-component stylesheets
// that share button.css. A stylesheet several files import lands once per entry, at its first
// position.
//
// The Workbench's own entry (vite.config.js) still shares one file with `@tailwindcss/vite` until
// plan step 39 removes it, and that plugin bundles its whole reachable module graph itself,
// independently of Vite's CSS pipeline; it does not carry the same `skipDuplicates` option, so a
// shared component stylesheet currently lands once per import site there, not once overall. That
// is a pre-existing limitation of mixing the two in one entry, not something plan step 37
// introduces or can fix without moving Tailwind out of the Workbench's entry (step 39's job) — this
// fixture is what actually exercises the claim being pinned, decoupled from it.
// Not the Workbench's config: `@tailwindcss/vite` inlines the imports of any entry that uses
// Tailwind itself, without that deduplication, so a shared stylesheet repeats there. The Workbench
// keeps the package's CSS in an entry of its own (workbench/resources/css/package.css) for that
// reason, until plan step 39 removes Tailwind.
//
// DEDUP_OUT_DIR is required: the test builds into a temporary directory and deletes it, and nothing
// should land in the package's own tree, least of all workbench/public/build.
if (!process.env.DEDUP_OUT_DIR) {
throw new Error('Set DEDUP_OUT_DIR to the directory the dedup fixture should build into.');
}
export default defineConfig({
publicDir: false,
build: {
outDir: process.env.DEDUP_OUT_DIR,
emptyOutDir: true,
manifest: true,
rollupOptions: {
input: 'resources/css/all.css',
input: ['resources/css/all.css', 'tests/Fixtures/dedup-app.css'],
},
},
logLevel: 'silent',