From 4a932b43e527af1dc0040da8e5783aec102aa0fe Mon Sep 17 00:00:00 2001 From: Michael Assraf Date: Sun, 1 Nov 2026 14:44:44 -0500 Subject: [PATCH] fix(next-styles): the home page gets its own sheet after Vercel regenerates it CU-17tkuw61z4z Vercel serves the home page as its index function, so a home page it regenerates renders with /index as its path, matches no route and got the complete sheet. /index is the home route, as in Next. Co-Authored-By: Claude Opus 5.5 --- openframe-frontend-core/scripts/route-styles-server.mjs | 7 ++++++- openframe-frontend-core/src/__tests__/route-styles.test.ts | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/openframe-frontend-core/scripts/route-styles-server.mjs b/openframe-frontend-core/scripts/route-styles-server.mjs index c5ab8f1666..1fdff5cdff 100644 --- a/openframe-frontend-core/scripts/route-styles-server.mjs +++ b/openframe-frontend-core/scripts/route-styles-server.mjs @@ -47,9 +47,14 @@ function routePattern(route) { return { route, dynamic, regex: new RegExp(`^${source || '/'}$`) }; } +/** + * The page's path as a route is written. `/index` is the home page: Next calls it that on the server (Vercel serves it + * as the `index` function, and a page regenerated there renders with `/index` as its path), and no app route is + * named `index` because Next answers `/index` itself. + */ function normalize(pathname) { const path = `/${String(pathname || '').replace(/^\/+/, '')}`.replace(/\/+$/, ''); - return path === '' ? '/' : path; + return path === '' || path === '/index' ? '/' : path; } /** diff --git a/openframe-frontend-core/src/__tests__/route-styles.test.ts b/openframe-frontend-core/src/__tests__/route-styles.test.ts index 655f124e54..6e101e0380 100644 --- a/openframe-frontend-core/src/__tests__/route-styles.test.ts +++ b/openframe-frontend-core/src/__tests__/route-styles.test.ts @@ -333,7 +333,7 @@ describe('RouteStyles: the rules a page gets on the server', () => { rmSync(root, { recursive: true, force: true }); }); - it('matches the page path to its route, a static route before a dynamic one, and the complete sheet otherwise', async () => { + it('matches the page path to its route, a static route before a dynamic one, the home page by either name, and the complete sheet otherwise', async () => { const { RouteStyles } = await import('../../scripts/route-styles-server.mjs'); const element = RouteStyles({}) as { props: { build: string } }; expect(element.props.build).toBe('b2'); @@ -345,6 +345,8 @@ describe('RouteStyles: the rules a page gets on the server', () => { )[Symbol.for('flamingo.next-styles')].get('b2'); if (!resolve) throw new Error('RouteStyles registered no resolver'); expect(resolve('/', false).css).toBe('.home{}'); + // A home page Vercel regenerates renders as its `index` function: the path it sees is `/index`. + expect(resolve('/index', false).css).toBe('.home{}'); expect(resolve('/blog/', false).css).toBe('.blog{}'); expect(resolve('/blog/a-post', false)).toEqual({ css: '.post{}', fullUrl: '/_next/static/next-styles/full.css' }); expect(resolve('/docs/a/b', false).css).toBe('.docs{}');