From 0f65f9340762de6767514e2670a116d6cb113cb3 Mon Sep 17 00:00:00 2001 From: Danny Banks Date: Wed, 17 Jun 2026 11:50:21 -0700 Subject: [PATCH 1/5] Next: per-route critical CSS via manifest v2 (P2.15) Emit route-scoped stylesheets during buildTypestylesForNext and expose getRouteCss so SSR can load pre-extracted CSS per App Router route instead of the full getRegisteredCss buffer. Co-authored-by: Cursor --- .changeset/p2-15-per-route-critical-css.md | 6 + docs/content/docs/ssr.md | 36 +++++- docs/content/docs/zero-runtime.md | 7 +- examples/next-app/README.md | 4 +- .../next-app/scripts/verify-typestyles.mts | 2 + packages/build-runner/README.md | 5 + packages/build-runner/src/index.ts | 21 ++++ packages/build-runner/src/manifest.ts | 31 +++++ packages/build-runner/src/next-routes.test.ts | 55 ++++++++ packages/build-runner/src/next-routes.ts | 117 ++++++++++++++++++ packages/build-runner/src/route-css-read.ts | 66 ++++++++++ packages/build-runner/src/route-css.test.ts | 59 +++++++++ packages/build-runner/src/route-css.ts | 88 +++++++++++++ .../build-runner/src/trace-imports.test.ts | 68 ++++++++++ packages/build-runner/src/trace-imports.ts | 99 +++++++++++++++ packages/build-runner/src/verify.test.ts | 35 ++++++ packages/build-runner/src/verify.ts | 51 ++++++-- packages/next/README.md | 12 +- packages/next/src/build-route-css.test.ts | 48 +++++++ packages/next/src/build.d.ts | 29 +++++ packages/next/src/build.ts | 45 ++++++- packages/next/src/server.d.ts | 2 + packages/next/src/server.ts | 3 +- 23 files changed, 873 insertions(+), 16 deletions(-) create mode 100644 .changeset/p2-15-per-route-critical-css.md create mode 100644 packages/build-runner/src/manifest.ts create mode 100644 packages/build-runner/src/next-routes.test.ts create mode 100644 packages/build-runner/src/next-routes.ts create mode 100644 packages/build-runner/src/route-css-read.ts create mode 100644 packages/build-runner/src/route-css.test.ts create mode 100644 packages/build-runner/src/route-css.ts create mode 100644 packages/build-runner/src/trace-imports.test.ts create mode 100644 packages/build-runner/src/trace-imports.ts create mode 100644 packages/next/src/build-route-css.test.ts diff --git a/.changeset/p2-15-per-route-critical-css.md b/.changeset/p2-15-per-route-critical-css.md new file mode 100644 index 0000000..f52866b --- /dev/null +++ b/.changeset/p2-15-per-route-critical-css.md @@ -0,0 +1,6 @@ +--- +'@typestyles/build-runner': minor +'@typestyles/next': minor +--- + +Per-route critical CSS for Next.js App Router (P2.15): `buildTypestylesForNext` emits route-scoped stylesheets and manifest v2 with a `routes` map; `getRouteCss` reads them at request time instead of the full `getRegisteredCss()` buffer. diff --git a/docs/content/docs/ssr.md b/docs/content/docs/ssr.md index e394625..89a3d89 100644 --- a/docs/content/docs/ssr.md +++ b/docs/content/docs/ssr.md @@ -321,7 +321,41 @@ TypeStyles automatically deduplicates CSS during collection. If multiple compone ### Critical CSS -All CSS is included by default. For large applications, you might want to implement critical CSS extraction (only including styles for above-the-fold content). This isn't built into TypeStyles—you'd need to implement it at the framework level. +By default, `getRegisteredCss()` returns every rule registered in the process. For large apps, prefer **build-time per-route CSS** on Next.js: `buildTypestylesForNext` writes route-scoped stylesheets and a v2 manifest (see [zero-runtime — Next.js](/docs/zero-runtime#nextjs) and [per-route critical CSS](#per-route-critical-css-nextjs) below). + +### Per-route critical CSS (Next.js) + +`buildTypestylesForNext` traces each App Router `page` plus its layout chain, extracts CSS for modules that import `typestyles`, and writes self-contained files under `app/_typestyles/routes/` (default). The manifest maps route paths to those files: + +```json +{ + "version": 2, + "css": "app/typestyles.css", + "routes": { + "/": { "css": "app/_typestyles/routes/index.css" }, + "/about": { "css": "app/_typestyles/routes/about.css" } + } +} +``` + +At request time, read the pre-built CSS for the current route instead of the full global sheet: + +```tsx +// app/about/layout.tsx (Server Component) +import { getRouteCss } from '@typestyles/next/server'; + +export default function AboutLayout({ children }: { children: React.ReactNode }) { + const css = getRouteCss('/about', { root: process.cwd() }); + return ( + <> +