Skip to content

Commit b5232bc

Browse files
HiDeoodelucis
andauthored
Fix missing styles for dynamic routes rendering <StarlightPage> (#2905)
Co-authored-by: Chris Swithinbank <[email protected]> Co-authored-by: Chris Swithinbank <[email protected]>
1 parent d1f3c8b commit b5232bc

File tree

7 files changed

+83
-7
lines changed

7 files changed

+83
-7
lines changed

.changeset/long-waves-rush.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@astrojs/starlight': patch
3+
---
4+
5+
Fixes a potential issue for projects with dynamic routes added by an user, an Astro integration, or a Starlight plugin where some styles could end up being missing.

packages/starlight/__e2e__/components.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,26 @@ test.describe('anchor headings', () => {
393393
});
394394
});
395395

396+
test.describe('head propagation', () => {
397+
/**
398+
* Due to a head propagation issue in development mode, dynamic routes alphabetically sorted
399+
* before Starlight route (`[...slug]`) rendering the `<StarlightPage>` component can result in
400+
* missing styles. The issue is workaround by having our call to `render` from `astro:content` to
401+
* be in a specific file.
402+
*
403+
* @see https://github.com/withastro/astro/issues/13724
404+
*/
405+
test('does not prevent head propagation in dev mode when rendering a dynamic route using the `<StarlightPage>` component', async ({
406+
page,
407+
makeServer,
408+
}) => {
409+
const starlight = await makeServer('dev', { mode: 'dev' });
410+
await starlight.goto('/head-propagation');
411+
412+
await expect(page.getByTestId('purple-card')).toHaveCSS('background-color', 'rgb(128, 0, 128)');
413+
});
414+
});
415+
396416
async function expectSelectedTab(tabs: Locator, label: string, panel?: string) {
397417
expect(
398418
(
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<div data-testid="purple-card">I am a purple card with white text.</div>
2+
3+
<style>
4+
div {
5+
background-color: rgb(128, 0, 128);
6+
color: rgb(255, 255, 255);
7+
}
8+
</style>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
title: Head Propagation
3+
---
4+
5+
import PurpleCard from '../../components/PurpleCard.astro';
6+
7+
<PurpleCard />
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro';
3+
4+
/**
5+
* The name of this dynamic route is intentionally set to `[...param]` to test a head propagation
6+
* issue that occurs for dynamic routes alphabetically sorted before the Starlight default route
7+
* (`[...slug]`) rendering the `<StarlightPage>` component.
8+
*/
9+
10+
export function getStaticPaths() {
11+
return [{ params: { param: 'custom-page' } }];
12+
}
13+
---
14+
15+
<StarlightPage frontmatter={{ title: 'A custom page' }}>
16+
<p>This is a custom page</p>
17+
</StarlightPage>

packages/starlight/routes/common.astro

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
---
2+
import { render } from 'astro:content';
23
import Page from '../components/Page.astro';
3-
import { useRouteData } from '../utils/routing/data';
4+
import { getRoute, useRouteData } from '../utils/routing/data';
45
import { attachRouteDataAndRunMiddleware } from '../utils/routing/middleware';
56
6-
await attachRouteDataAndRunMiddleware(Astro, await useRouteData(Astro));
7+
const route = await getRoute(Astro);
8+
/**
9+
* The call to `render` from `astro:content` is purposely made in this file to work around a
10+
* development mode head propagation issue which is heavily tied to `astro:content` imports. Even
11+
* though we have a test for this, refactoring and moving this code to a different file should be
12+
* avoided for now until the linked issue which also contains more details is resolved.
13+
*
14+
* @see https://github.com/withastro/astro/issues/13724
15+
*/
16+
const renderResult = await render(route.entry);
17+
18+
await attachRouteDataAndRunMiddleware(Astro, await useRouteData(Astro, route, renderResult));
719
820
const { Content, entry } = Astro.locals.starlightRoute;
921
---

packages/starlight/utils/routing/data.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type {
1515
import { formatPath } from '../format-path';
1616
import { useTranslations } from '../translations';
1717
import { BuiltInDefaultLocale } from '../i18n';
18-
import { getEntry, render } from 'astro:content';
18+
import { getEntry, type RenderResult } from 'astro:content';
1919
import { getCollectionPathFromRoot } from '../collection';
2020
import { getHead } from '../head';
2121

@@ -25,11 +25,18 @@ export interface PageProps extends Route {
2525

2626
export type RouteDataContext = Pick<APIContext, 'generator' | 'site' | 'url'>;
2727

28-
export async function useRouteData(context: APIContext): Promise<StarlightRouteData> {
29-
const route =
28+
export async function getRoute(context: APIContext): Promise<Route> {
29+
return (
3030
('slug' in context.params && getRouteBySlugParam(context.params.slug)) ||
31-
(await get404Route(context.locals));
32-
const { Content, headings } = await render(route.entry);
31+
(await get404Route(context.locals))
32+
);
33+
}
34+
35+
export async function useRouteData(
36+
context: APIContext,
37+
route: Route,
38+
{ Content, headings }: RenderResult
39+
): Promise<StarlightRouteData> {
3340
const routeData = generateRouteData({ props: { ...route, headings }, context });
3441
return { ...routeData, Content };
3542
}

0 commit comments

Comments
 (0)