diff options
author | HiDeoo | 2025-05-01 12:23:54 +0200 |
---|---|---|
committer | GitHub | 2025-05-01 12:23:54 +0200 |
commit | b5232bcd201c2e3904bde2d7717fe6cfa06d6c82 (patch) | |
tree | e754799fe112fd8efa70e71484ba3bd14168a35a | |
parent | d1f3c8b6583b93968af3c568f7af44b1b10326ec (diff) | |
download | IT.starlight-b5232bcd201c2e3904bde2d7717fe6cfa06d6c82.tar.gz IT.starlight-b5232bcd201c2e3904bde2d7717fe6cfa06d6c82.tar.bz2 IT.starlight-b5232bcd201c2e3904bde2d7717fe6cfa06d6c82.zip |
Fix missing styles for dynamic routes rendering `<StarlightPage>` (#2905)
Co-authored-by: Chris Swithinbank <swithinbank@gmail.com>
Co-authored-by: Chris Swithinbank <357379+delucis@users.noreply.github.com>
7 files changed, 83 insertions, 7 deletions
diff --git a/.changeset/long-waves-rush.md b/.changeset/long-waves-rush.md new file mode 100644 index 00000000..d279e10c --- /dev/null +++ b/.changeset/long-waves-rush.md @@ -0,0 +1,5 @@ +--- +'@astrojs/starlight': patch +--- + +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. diff --git a/packages/starlight/__e2e__/components.test.ts b/packages/starlight/__e2e__/components.test.ts index 6a1b7e5b..7b536c78 100644 --- a/packages/starlight/__e2e__/components.test.ts +++ b/packages/starlight/__e2e__/components.test.ts @@ -393,6 +393,26 @@ test.describe('anchor headings', () => { }); }); +test.describe('head propagation', () => { + /** + * Due to a head propagation issue in development mode, dynamic routes alphabetically sorted + * before Starlight route (`[...slug]`) rendering the `<StarlightPage>` component can result in + * missing styles. The issue is workaround by having our call to `render` from `astro:content` to + * be in a specific file. + * + * @see https://github.com/withastro/astro/issues/13724 + */ + test('does not prevent head propagation in dev mode when rendering a dynamic route using the `<StarlightPage>` component', async ({ + page, + makeServer, + }) => { + const starlight = await makeServer('dev', { mode: 'dev' }); + await starlight.goto('/head-propagation'); + + await expect(page.getByTestId('purple-card')).toHaveCSS('background-color', 'rgb(128, 0, 128)'); + }); +}); + async function expectSelectedTab(tabs: Locator, label: string, panel?: string) { expect( ( diff --git a/packages/starlight/__e2e__/fixtures/basics/src/components/PurpleCard.astro b/packages/starlight/__e2e__/fixtures/basics/src/components/PurpleCard.astro new file mode 100644 index 00000000..932cb3f3 --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/basics/src/components/PurpleCard.astro @@ -0,0 +1,8 @@ +<div data-testid="purple-card">I am a purple card with white text.</div> + +<style> + div { + background-color: rgb(128, 0, 128); + color: rgb(255, 255, 255); + } +</style> diff --git a/packages/starlight/__e2e__/fixtures/basics/src/content/docs/head-propagation.mdx b/packages/starlight/__e2e__/fixtures/basics/src/content/docs/head-propagation.mdx new file mode 100644 index 00000000..dd16e472 --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/basics/src/content/docs/head-propagation.mdx @@ -0,0 +1,7 @@ +--- +title: Head Propagation +--- + +import PurpleCard from '../../components/PurpleCard.astro'; + +<PurpleCard /> diff --git a/packages/starlight/__e2e__/fixtures/basics/src/pages/[...param].astro b/packages/starlight/__e2e__/fixtures/basics/src/pages/[...param].astro new file mode 100644 index 00000000..db5d8675 --- /dev/null +++ b/packages/starlight/__e2e__/fixtures/basics/src/pages/[...param].astro @@ -0,0 +1,17 @@ +--- +import StarlightPage from '@astrojs/starlight/components/StarlightPage.astro'; + +/** + * The name of this dynamic route is intentionally set to `[...param]` to test a head propagation + * issue that occurs for dynamic routes alphabetically sorted before the Starlight default route + * (`[...slug]`) rendering the `<StarlightPage>` component. + */ + +export function getStaticPaths() { + return [{ params: { param: 'custom-page' } }]; +} +--- + +<StarlightPage frontmatter={{ title: 'A custom page' }}> + <p>This is a custom page</p> +</StarlightPage> diff --git a/packages/starlight/routes/common.astro b/packages/starlight/routes/common.astro index b96ef3fb..a113dbb8 100644 --- a/packages/starlight/routes/common.astro +++ b/packages/starlight/routes/common.astro @@ -1,9 +1,21 @@ --- +import { render } from 'astro:content'; import Page from '../components/Page.astro'; -import { useRouteData } from '../utils/routing/data'; +import { getRoute, useRouteData } from '../utils/routing/data'; import { attachRouteDataAndRunMiddleware } from '../utils/routing/middleware'; -await attachRouteDataAndRunMiddleware(Astro, await useRouteData(Astro)); +const route = await getRoute(Astro); +/** + * The call to `render` from `astro:content` is purposely made in this file to work around a + * development mode head propagation issue which is heavily tied to `astro:content` imports. Even + * though we have a test for this, refactoring and moving this code to a different file should be + * avoided for now until the linked issue which also contains more details is resolved. + * + * @see https://github.com/withastro/astro/issues/13724 + */ +const renderResult = await render(route.entry); + +await attachRouteDataAndRunMiddleware(Astro, await useRouteData(Astro, route, renderResult)); const { Content, entry } = Astro.locals.starlightRoute; --- diff --git a/packages/starlight/utils/routing/data.ts b/packages/starlight/utils/routing/data.ts index 343f8dbb..8e1dcb25 100644 --- a/packages/starlight/utils/routing/data.ts +++ b/packages/starlight/utils/routing/data.ts @@ -15,7 +15,7 @@ import type { import { formatPath } from '../format-path'; import { useTranslations } from '../translations'; import { BuiltInDefaultLocale } from '../i18n'; -import { getEntry, render } from 'astro:content'; +import { getEntry, type RenderResult } from 'astro:content'; import { getCollectionPathFromRoot } from '../collection'; import { getHead } from '../head'; @@ -25,11 +25,18 @@ export interface PageProps extends Route { export type RouteDataContext = Pick<APIContext, 'generator' | 'site' | 'url'>; -export async function useRouteData(context: APIContext): Promise<StarlightRouteData> { - const route = +export async function getRoute(context: APIContext): Promise<Route> { + return ( ('slug' in context.params && getRouteBySlugParam(context.params.slug)) || - (await get404Route(context.locals)); - const { Content, headings } = await render(route.entry); + (await get404Route(context.locals)) + ); +} + +export async function useRouteData( + context: APIContext, + route: Route, + { Content, headings }: RenderResult +): Promise<StarlightRouteData> { const routeData = generateRouteData({ props: { ...route, headings }, context }); return { ...routeData, Content }; } |