From 0b05416145168f3f4822c745e4859d0aa05e1fd6 Mon Sep 17 00:00:00 2001 From: Giovambattista Fazioli Date: Tue, 6 Oct 2026 08:00:01 +0200 Subject: [PATCH] fix: drop graph CSS chunking, which put Mantine's styles after ours cssChunking 'graph' (added in #75 to keep the home's CSS off the docs) orders the chunks by its own cost model, and Mantine's core stylesheet landed after the component modules: every module rule overriding a Mantine component at the same specificity lost. On wpbones.com the chat launcher was position: relative at the foot of the page, 20 px off its left edge, instead of fixed bottom right, and the docs' GitHub buttons had Mantine's border. Measured with getComputedStyle on production and on a local production build without graph (launcher fixed at 1420,880; border back to ours). The price is the home's CSS on the docs again, about 9 KB gzip. --- CLAUDE.md | 16 ++++++++++++---- next.config.mjs | 7 ------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2e0817b..345fe32 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -99,12 +99,20 @@ not the author's personal one). layout's CSS and every docs page blocked its first paint on them (measured: docs LCP 2.0 s on `main`, 2.2 s with the home's CSS, 2.0 s again without). A dynamic `import()` did not help. Hence also no `index` key in `app/_meta.tsx`: it refers to a page the map no longer sees, and fails the build. - `next.config.mjs` adds `cssChunking: 'graph'` where `TURBOPACK` is set: the default chunking merged - the home's CSS back into the shared chunks. To check: the `` tags of `/docs` - must not name any `Home/` module. + The default CSS chunking still merges the home's CSS into the shared chunks, so the docs load it. +- **Never `cssChunking: 'graph'` while Mantine's CSS is unlayered.** It kept the home's CSS off the docs, + and it shipped (#75), but it ORDERS the chunks by its own cost model: Mantine's core stylesheet came + after the component modules, and every module rule that overrides a Mantine component at the same + specificity lost. In production the chat launcher was `position: relative` at the foot of the page, + 20 px off its left edge, instead of fixed bottom right, and the docs' GitHub buttons had Mantine's + border, not ours (measured with `getComputedStyle` on wpbones.com, then reverted). Moving Mantine to + `styles.layer.css` would make the order irrelevant, but the layer order would then put Nextra's + preflight above Mantine: settle that first, and check `getComputedStyle` of the launcher, a tab pill + and a GitHub button on a production build, not in `next dev`, which does not chunk. - **Measured before/after (2026-10-05, local `next start`, Lighthouse mobile, 4 passes home, 2 docs)**: home perf 95–96 → 92–93, LCP 1.73–2.04 → 2.11–2.15 s, TBT ~160 → ~225 ms, CLS 0.041 → 0.002, 1271 → - 965 KiB; docs LCP 2.0 → 2.0 s; at rest 716 → 80 ms of main-thread work and 601 → 54 style recalcs. + 965 KiB; docs LCP 2.0 → 2.0 s with `graph` (2.2 s without it, the home's CSS on the docs again, ~9 KB + gzip: the price of the revert above); at rest 716 → 80 ms of main-thread work and 601 → 54 style recalcs. The home's code is compacted to one-letter classes (`highlight.ts`) and the sprite is one path per colour (`sprite.ts`, `paths`), because both are served twice, in the HTML and the RSC payload. - **Not ours, measured on `main` too**: two React "unique key" warnings from Nextra's `ConfigProvider` diff --git a/next.config.mjs b/next.config.mjs index d1626f3..63268d8 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -19,13 +19,6 @@ export default withNextra( cleanDistDir: true, experimental: { optimizePackageImports: ['@mantine/core', '@mantine/hooks'], - // Turbopack's default chunking merged the home page's CSS into the - // chunks every docs page loads; the graph strategy keeps it on the home - // page (measured 2026-10-05: the docs went from 3 files with the home's - // styles to 4 without). Graph is Turbopack-only and Next rejects it - // where TURBOPACK is unset -- Jest's next/jest, `next typegen` -- so it - // is set only where Turbopack is the bundler. - ...(process.env.TURBOPACK ? { cssChunking: 'graph' } : {}), }, turbopack: { rules: {