-
-
Notifications
You must be signed in to change notification settings - Fork 626
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move route data to
Astro.locals
(#2390)
Co-authored-by: Chris Swithinbank <[email protected]> Co-authored-by: HiDeoo <[email protected]> Co-authored-by: trueberryless <[email protected]>
- Loading branch information
1 parent
f895f75
commit f493361
Showing
78 changed files
with
1,087 additions
and
540 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
--- | ||
'@astrojs/starlight': minor | ||
--- | ||
|
||
Moves route data to `Astro.locals` instead of passing it down via component props | ||
|
||
⚠️ **Breaking change:** | ||
Previously, all of Starlight’s templating components, including user or plugin overrides, had access to a data object for the current route via `Astro.props`. | ||
This data is now available as `Astro.locals.starlightRoute` instead. | ||
|
||
To update, refactor any component overrides you have: | ||
|
||
- Remove imports of `@astrojs/starlight/props`, which is now deprecated. | ||
- Update code that accesses `Astro.props` to use `Astro.locals.starlightRoute` instead. | ||
- Remove any spreading of `{...Astro.props}` into child components, which is no longer required. | ||
|
||
In the following example, a custom override for Starlight’s `LastUpdated` component is updated for the new style: | ||
|
||
```diff | ||
--- | ||
import Default from '@astrojs/starlight/components/LastUpdated.astro'; | ||
- import type { Props } from '@astrojs/starlight/props'; | ||
|
||
- const { lastUpdated } = Astro.props; | ||
+ const { lastUpdated } = Astro.locals.starlightRoute; | ||
|
||
const updatedThisYear = lastUpdated?.getFullYear() === new Date().getFullYear(); | ||
--- | ||
|
||
{updatedThisYear && ( | ||
- <Default {...Astro.props}><slot /></Default> | ||
+ <Default><slot /></Default> | ||
)} | ||
``` | ||
|
||
_Community Starlight plugins may also need to be manually updated to work with Starlight 0.32. If you encounter any issues, please reach out to the plugin author to see if it is a known issue or if an updated version is being worked on._ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -36,10 +36,11 @@ Overriding Starlight’s default components can be useful when: | |
```astro | ||
--- | ||
// src/components/EmailLink.astro | ||
import type { Props } from '@astrojs/starlight/props'; | ||
const email = '[email protected]'; | ||
--- | ||
<a href="mailto:[email protected]">E-mail Me</a> | ||
<a href=`mailto:${email}`>E-mail Me</a> | ||
``` | ||
|
||
3. Tell Starlight to use your custom component in the [`components`](/reference/configuration/#components) configuration option in `astro.config.mjs`: | ||
|
@@ -70,52 +71,46 @@ You can build with Starlight’s default UI components just as you would with yo | |
|
||
The example below shows a custom component that renders an e-mail link along with the default `SocialIcons` component: | ||
|
||
```astro {4,8} | ||
```astro {3,7} | ||
--- | ||
// src/components/EmailLink.astro | ||
import type { Props } from '@astrojs/starlight/props'; | ||
import Default from '@astrojs/starlight/components/SocialIcons.astro'; | ||
--- | ||
<a href="mailto:[email protected]">E-mail Me</a> | ||
<Default {...Astro.props}><slot /></Default> | ||
<Default><slot /></Default> | ||
``` | ||
|
||
When rendering a built-in component inside a custom component: | ||
|
||
- Spread `Astro.props` into it. This makes sure that it receives all the data it needs to render. | ||
- Add a [`<slot />`](https://docs.astro.build/en/basics/astro-components/#slots) inside the default component. This makes sure that if the component is passed any child elements, Astro knows where to render them. | ||
When rendering a built-in component inside a custom component add a [`<slot />`](https://docs.astro.build/en/basics/astro-components/#slots) inside the default component. This makes sure that if the component is passed any child elements, Astro knows where to render them. | ||
|
||
If you are reusing the [`PageFrame`](/reference/overrides/#pageframe) or [`TwoColumnContent`](/reference/overrides/#twocolumncontent) components which contain [named slots](https://docs.astro.build/en/basics/astro-components/#named-slots), you also need to [transfer](https://docs.astro.build/en/basics/astro-components/#transferring-slots) these slots as well. | ||
|
||
The example below shows a custom component that reuses the `TwoColumnContent` component which contains an additional `right-sidebar` named slot that needs to be transferred: | ||
|
||
```astro {9} | ||
```astro {8} | ||
--- | ||
// src/components/CustomContent.astro | ||
import type { Props } from '@astrojs/starlight/props'; | ||
import Default from '@astrojs/starlight/components/TwoColumnContent.astro'; | ||
--- | ||
<Default {...Astro.props}> | ||
<Default> | ||
<slot /> | ||
<slot name="right-sidebar" slot="right-sidebar" /> | ||
</Default> | ||
``` | ||
|
||
## Use page data | ||
|
||
When overriding a Starlight component, your custom implementation receives a standard `Astro.props` object containing all the data for the current page. | ||
When overriding a Starlight component, you can access the global [`starlightRoute` object](/guides/route-data/) containing all the data for the current page. | ||
This allows you to use these values to control how your component template renders. | ||
|
||
For example, you can read the page’s frontmatter values as `Astro.props.entry.data`. In the following example, a replacement [`PageTitle`](/reference/overrides/#pagetitle) component uses this to display the current page’s title: | ||
In the following example, a replacement [`PageTitle`](/reference/overrides/#pagetitle) component displays the current page’s title as set in the content’s frontmatter: | ||
|
||
```astro {5} "{title}" | ||
```astro {4} "{title}" | ||
--- | ||
// src/components/Title.astro | ||
import type { Props } from '@astrojs/starlight/props'; | ||
const { title } = Astro.props.entry.data; | ||
const { title } = Astro.locals.starlightRoute.entry.data; | ||
--- | ||
<h1 id="_top">{title}</h1> | ||
|
@@ -127,28 +122,27 @@ const { title } = Astro.props.entry.data; | |
</style> | ||
``` | ||
|
||
Learn more about all the available props in the [Overrides Reference](/reference/overrides/#component-props). | ||
Learn more about all the available properties in the [Route Data Reference](/reference/route-data/). | ||
|
||
### Only override on specific pages | ||
|
||
Component overrides apply to all pages. However, you can conditionally render using values from `Astro.props` to determine when to show your custom UI, when to show Starlight’s default UI, or even when to show something entirely different. | ||
Component overrides apply to all pages. However, you can conditionally render using values from `starlightRoute` to determine when to show your custom UI, when to show Starlight’s default UI, or even when to show something entirely different. | ||
|
||
In the following example, a component overriding Starlight's [`Footer`](/reference/overrides/#footer-1) displays "Built with Starlight 🌟" on the homepage only, and otherwise shows the default footer on all other pages: | ||
|
||
```astro | ||
--- | ||
// src/components/ConditionalFooter.astro | ||
import type { Props } from '@astrojs/starlight/props'; | ||
import Default from '@astrojs/starlight/components/Footer.astro'; | ||
const isHomepage = Astro.props.id === ''; | ||
const isHomepage = Astro.locals.starlightRoute.id === ''; | ||
--- | ||
{ | ||
isHomepage ? ( | ||
<footer>Built with Starlight 🌟</footer> | ||
) : ( | ||
<Default {...Astro.props}> | ||
<Default> | ||
<slot /> | ||
</Default> | ||
) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
--- | ||
title: Route Data | ||
description: Learn how Starlight’s page data model is used to render your pages and how you can customize it. | ||
--- | ||
|
||
import { Steps } from '@astrojs/starlight/components'; | ||
|
||
When Starlight renders a page in your documentation, it first creates a route data object to represent what is on that page. | ||
This guide explains how route data is generated, how to use it, and how you can customize it to modify Starlight’s default behavior. | ||
|
||
See the [“Route Data Reference”](/reference/route-data/) for a full list of the available properties. | ||
|
||
## What is route data? | ||
|
||
Starlight route data is an object containing all the information required to render a single page. | ||
It includes information for the current page as well as data generated from your Starlight configuration. | ||
|
||
## Using route data | ||
|
||
All of Starlight’s components use route data to decide what to render for each page. | ||
For example, the [`siteTitle`](/reference/route-data/#sitetitle) string is used to display the site title and the [`sidebar`](/reference/route-data/#sidebar) array is used to render the global sidebar navigation. | ||
|
||
You can access this data from the `Astro.locals.starlightRoute` global in Astro components: | ||
|
||
```astro title="example.astro" {2} | ||
--- | ||
const { siteTitle } = Astro.locals.starlightRoute; | ||
--- | ||
<p>The title of this site is “{siteTitle}”</p> | ||
``` | ||
|
||
This can be useful for example when building [component overrides](/guides/overriding-components/) to customize what you display. | ||
|
||
## Customizing route data | ||
|
||
Starlight’s route data works out of the box and does not require any configuration. | ||
However, for advanced use cases, you may want to customize route data for some or all pages to modify how your site displays. | ||
|
||
This is a similar concept to [component overrides](/guides/overriding-components/), but instead of modifying how Starlight renders your data, you modify the data Starlight renders. | ||
|
||
### When to customize route data | ||
|
||
Customizing route data can be useful when you want to modify how Starlight processes your data in a way not possible with existing configuration options. | ||
|
||
For example, you may want to filter sidebar items or customize titles for specific pages. | ||
Changes like this do not require modifying Starlight’s default components, only the data passed to those components. | ||
|
||
### How to customize route data | ||
|
||
You can customize route data using a special form of “middleware”. | ||
This is a function that is called every time Starlight renders a page and can modify values in the route data object. | ||
|
||
<Steps> | ||
|
||
1. Create a new file exporting an `onRequest` function using Starlight’s `defineRouteMiddleware()` utility: | ||
|
||
```ts | ||
// src/routeData.ts | ||
import { defineRouteMiddleware } from '@astrojs/starlight/route-data'; | ||
|
||
export const onRequest = defineRouteMiddleware(() => {}); | ||
``` | ||
|
||
2. Tell Starlight where your route data middleware file is located in `astro.config.mjs`: | ||
|
||
```js ins={9} | ||
// astro.config.mjs | ||
import { defineConfig } from 'astro/config'; | ||
import starlight from '@astrojs/starlight'; | ||
|
||
export default defineConfig({ | ||
integrations: [ | ||
starlight({ | ||
title: 'My delightful docs site', | ||
routeMiddleware: './src/routeData.ts', | ||
}), | ||
], | ||
}); | ||
``` | ||
|
||
3. Update your `onRequest` function to modify route data. | ||
|
||
The first argument your middleware will receive is [Astro’s `context` object](https://docs.astro.build/en/reference/api-reference/). | ||
This contains full information about the current page render, including the current URL and `locals`. | ||
|
||
In this example, we are going to make our docs more exciting by adding an exclamation mark to the end of every page’s title. | ||
|
||
```ts | ||
// src/routeData.ts | ||
import { defineRouteMiddleware } from '@astrojs/starlight/route-data'; | ||
|
||
export const onRequest = defineRouteMiddleware((context) => { | ||
// Get the content collection entry for this page. | ||
const { entry } = context.locals.starlightRoute; | ||
// Update the title to add an exclamation mark. | ||
entry.data.title = entry.data.title + '!'; | ||
}); | ||
``` | ||
|
||
</Steps> | ||
|
||
#### Multiple route middleware | ||
|
||
Starlight also supports providing multiple middleware. | ||
Set `routeMiddleware` to an array of paths to add more than one middleware handler: | ||
|
||
```js {9} | ||
// astro.config.mjs | ||
import { defineConfig } from 'astro/config'; | ||
import starlight from '@astrojs/starlight'; | ||
|
||
export default defineConfig({ | ||
integrations: [ | ||
starlight({ | ||
title: 'My site with multiple middleware', | ||
routeMiddleware: ['./src/middleware-one.ts', './src/middleware-two.ts'], | ||
}), | ||
], | ||
}); | ||
``` | ||
|
||
#### Waiting for later route middleware | ||
|
||
To wait for middleware later in the stack to run before executing your code, you can await the `next()` callback passed as the second argument to your middleware function. | ||
This can be useful to wait for a plugin’s middleware to run before making changes for example. | ||
|
||
```ts "next" "await next();" | ||
// src/routeData.ts | ||
import { defineRouteMiddleware } from '@astrojs/starlight/route-data'; | ||
|
||
export const onRequest = defineRouteMiddleware(async (context, next) => { | ||
// Wait for later middleware to run. | ||
await next(); | ||
// Modify route data. | ||
const { entry } = context.locals.starlightRoute; | ||
entry.data.title = entry.data.title + '!'; | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.