Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for SSR #1255

Open
wants to merge 61 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
1a288b9
Add suport for SSR
Fryuni Dec 8, 2023
b55f0e7
Handle route not found
Fryuni Dec 8, 2023
45d9e41
Fix SSR page typos
Fryuni Dec 8, 2023
6762da6
Specify prerendering option for injected routes
Fryuni Dec 8, 2023
867ba4f
Add an SSR example
Fryuni Dec 8, 2023
9edf662
Make pagefind work with SSR
Fryuni Dec 8, 2023
b66c763
Pre-render for pagefind
Fryuni Dec 10, 2023
c2df2fe
Add changeset
Fryuni Dec 10, 2023
62ceb4a
Merge branch 'main' into ssr-support
Fryuni Dec 10, 2023
fda9681
Merge branch 'main' into ssr-support
Fryuni Dec 14, 2023
29694b3
Merge branch 'main' into ssr-support
Fryuni Jan 30, 2024
670f4e8
Add SSR demonstration to example
Fryuni Jan 30, 2024
ab02b01
Make Pagefind + SSR warning more informative
Fryuni Jan 30, 2024
1177212
Clear imports
Fryuni Jan 30, 2024
836d757
Fix lockfile
Fryuni Jan 30, 2024
9bdffc1
Enable feature to work with project routes
Fryuni Jan 30, 2024
e47641f
Add docs for SSR
Fryuni Jan 31, 2024
9017bc8
Merge branch 'main' into ssr-support
Fryuni Feb 17, 2024
5adfef4
Disable Pagefind when using SSR
Fryuni Feb 17, 2024
700d828
Enable SSR for 404 route
Fryuni Feb 17, 2024
b8a03e0
Add nice errors and hints when mixing SSR with incompatible configura…
Fryuni Feb 17, 2024
741c5dc
Fix erorr message
Fryuni Feb 17, 2024
2e93820
Fix SSR example
Fryuni Feb 17, 2024
5feeda2
Move git executions to build time
Fryuni Feb 18, 2024
7a371fb
Add e2e tests
Fryuni Feb 19, 2024
beca130
Add tests for SSR rendering the same content as static
Fryuni Feb 20, 2024
b9a15ff
Prevent race during test cleanup
Fryuni Feb 20, 2024
f63fc28
Increase timeout for e2e SSR tests
Fryuni Feb 20, 2024
7a72c4b
Merge branch 'main' into ssr-support
Fryuni Feb 23, 2024
1ef15b1
Exclude tmp e2e files from watch
Fryuni Feb 23, 2024
7481409
Use system tempdir
Fryuni Feb 28, 2024
d9677b0
Merge branch 'main' into ssr-support
Fryuni Feb 28, 2024
624f620
Fix pagefind default
Fryuni Feb 28, 2024
24c33a4
Use long test for e2e tests
Fryuni Feb 28, 2024
d86b893
Ignore Astro generated files during e2e for coverage
Fryuni Feb 28, 2024
56955d5
Merge branch 'main' into ssr-support
Fryuni Mar 2, 2024
3bab442
Reorganize E2E tests to be run using specific commands
Fryuni Mar 2, 2024
fa2b89b
Update thresholds
Fryuni Mar 2, 2024
f39df22
Update threadhold due to rounding error
Fryuni Mar 2, 2024
dc2e31d
Merge branch 'main' into ssr-support
Fryuni Mar 20, 2024
07adf98
Use cloudflare in SSR example
Fryuni Mar 20, 2024
4290520
Fix node imports
Fryuni Mar 20, 2024
3302330
Remove workaround
Fryuni Mar 20, 2024
ca0fcfa
Make Vite aware that Node imports are side-effect free
Fryuni Mar 20, 2024
bcdc917
Fix comment typo
Fryuni Mar 21, 2024
47161db
Replace SSR demo with a more portable example
Fryuni Mar 21, 2024
3135fe1
Remove workaround for non-node runtimes
Fryuni Mar 21, 2024
3dd4734
Remove leftovers from old implementation details
Fryuni Mar 21, 2024
8ef67a4
Improve error messages to mention what is a Starlight config vs Astro…
Fryuni Mar 21, 2024
ac052f4
Merge branch 'main' into ssr-support
Fryuni Apr 12, 2024
49939f2
Use Node adapter for example
Fryuni Apr 12, 2024
9ac794a
Fix 404 in example
Fryuni Apr 12, 2024
9412a9d
Merge branch 'main' into ssr-support
Fryuni May 10, 2024
b2d77ef
Formatting
Fryuni May 10, 2024
1b3e06d
Update tests
Fryuni May 10, 2024
9eb44b1
Re-organize new functional tests
Fryuni May 10, 2024
cc446a7
Update test timing
Fryuni May 10, 2024
944a1dd
Fix typechecking
Fryuni May 10, 2024
72d9bc8
Add .astro folders
Fryuni May 10, 2024
e6b6608
Undo attempt to fix type
Fryuni May 12, 2024
0487488
Revert unneeded dependencies update
Fryuni May 12, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/six-phones-boil.md
@@ -0,0 +1,5 @@
---
'@astrojs/starlight': minor
---

Add support for server side components inside of Starlight pages.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Expand Up @@ -28,7 +28,7 @@ jobs:
cache: 'pnpm'
- run: pnpm i
- name: Test packages
run: pnpm -r test:coverage
run: pnpm -r test:coverage:all

e2e-test:
name: Run E2E tests
Expand Down
2 changes: 1 addition & 1 deletion docs/astro.config.mjs
Expand Up @@ -208,7 +208,7 @@ export default defineConfig({
errorOnFallbackPages: false,
errorOnInconsistentLocale: true,
}),
]
]
: [],
}),
],
Expand Down
4 changes: 2 additions & 2 deletions docs/src/content/docs/manual-setup.mdx
Expand Up @@ -125,6 +125,6 @@ In the future, we plan to support this use case better to avoid the need for the

### Use Starlight with SSR

You can use Starlight alongside custom on-demand rendered pages in your project by following the [“On-demand Rendering Adapters”](https://docs.astro.build/en/guides/server-side-rendering/) guide in Astro’s docs.
Starlight supports [SSR](https://docs.astro.build/en/guides/server-side-rendering/) out of the box using Astro's server adapters.

Currently, documentation pages generated by Starlight are always prerendered regardless of your project's output mode. We hope to be able to support on-demand rendering for Starlight pages soon.
Contrary to your own pages, documentation pages generated by Starlight are always prerendered by default regardless of your project's output mode. To opt-out of prerendering your Starlight pages, set the [`prerender` config option](/reference/configuration/#prerender) to `false`.
12 changes: 12 additions & 0 deletions docs/src/content/docs/reference/configuration.mdx
Expand Up @@ -433,6 +433,18 @@ Define whether Starlight’s default site search provider [Pagefind](https://pag
Set to `false` to disable indexing your site with Pagefind.
This will also hide the default search UI if in use.

Pagefind cannot be enabled when the [`prerender`](#prerender) option is set to `false`.

### `prerender`

**type:** `boolean`
**default:**: `true`

Define whether Starlight pages should be prerendered or handled using SSR.
This option behave just like the [`export const prerender`](https://docs.astro.build/en/guides/server-side-rendering/#enable-on-demand-server-rendering) from Astro pages and allow overriding the default prerendering behavior of the selected output mode.

Starlight pages are prerendeered by default regardless of the output mode of the Astro project. This differs from the default behavior of Astro pages, which are prerendered by default on `output: 'hybrid'` but not `output: 'server'`.

### `head`

**type:** [`HeadConfig[]`](#headconfig)
Expand Down
21 changes: 21 additions & 0 deletions examples/ssr/.gitignore
@@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/

# dependencies
node_modules/

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*


# environment variables
.env
.env.production

# macOS-specific files
.DS_Store
4 changes: 4 additions & 0 deletions examples/ssr/.vscode/extensions.json
@@ -0,0 +1,4 @@
{
"recommendations": ["astro-build.astro-vscode"],
"unwantedRecommendations": []
}
11 changes: 11 additions & 0 deletions examples/ssr/.vscode/launch.json
@@ -0,0 +1,11 @@
{
"version": "0.2.0",
"configurations": [
{
"command": "./node_modules/.bin/astro dev",
"name": "Development server",
"request": "launch",
"type": "node-terminal"
}
]
}
54 changes: 54 additions & 0 deletions examples/ssr/README.md
@@ -0,0 +1,54 @@
# Starlight Starter Kit: Basics

[![Built with Starlight](https://astro.badg.es/v2/built-with-starlight/tiny.svg)](https://starlight.astro.build)

```
npm create astro@latest -- --template starlight
```

[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/starlight/tree/main/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/starlight/tree/main/examples/basics)
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Fwithastro%2Fstarlight%2Ftree%2Fmain%2Fexamples%2Fbasics&project-name=my-starlight-docs&repository-name=my-starlight-docs)

> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!

## 🚀 Project Structure

Inside of your Astro + Starlight project, you'll see the following folders and files:

```
.
├── public/
├── src/
│ ├── assets/
│ ├── content/
│ │ ├── docs/
│ │ └── config.ts
│ └── env.d.ts
├── astro.config.mjs
├── package.json
└── tsconfig.json
```

Starlight looks for `.md` or `.mdx` files in the `src/content/docs/` directory. Each file is exposed as a route based on its file name.

Images can be added to `src/assets/` and embedded in Markdown with a relative link.

Static assets, like favicons, can be placed in the `public/` directory.

## 🧞 Commands

All commands are run from the root of the project, from a terminal:

| Command | Action |
| :------------------------ | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:4321` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro -- --help` | Get help using the Astro CLI |

## 👀 Want to learn more?

Check out [Starlight’s docs](https://starlight.astro.build/), read [the Astro documentation](https://docs.astro.build), or jump into the [Astro Discord server](https://astro.build/chat).
40 changes: 40 additions & 0 deletions examples/ssr/astro.config.mjs
@@ -0,0 +1,40 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import node from '@astrojs/node';

// https://astro.build/config
export default defineConfig({
output: 'server',
integrations: [
starlight({
title: 'My Docs',
prerender: false,
lastUpdated: true,
social: {
github: 'https://github.com/withastro/starlight',
},
sidebar: [
{
label: 'SSR Demo',
link: '/demo',
},
{
label: 'Guides',
items: [
{
label: 'Example Guide',
link: '/guides/example/',
},
],
},
{
label: 'Reference',
autogenerate: {
directory: 'reference',
},
},
],
}),
],
adapter: node({ mode: 'standalone' }),
});
19 changes: 19 additions & 0 deletions examples/ssr/package.json
@@ -0,0 +1,19 @@
{
"name": "@example/starlight-ssr",
"type": "module",
"version": "0.0.1",
"private": true,
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/node": "^7.0.0",
"@astrojs/starlight": "workspace:*",
"astro": "^4.0.1",
"sharp": "^0.32.5"
}
}
1 change: 1 addition & 0 deletions examples/ssr/public/favicon.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/ssr/src/assets/houston.webp
Binary file not shown.
7 changes: 7 additions & 0 deletions examples/ssr/src/components/RenderTime.astro
@@ -0,0 +1,7 @@
---
const now = Date();
---

<p>
Page was rendered on {now}
</p>
7 changes: 7 additions & 0 deletions examples/ssr/src/content/config.ts
@@ -0,0 +1,7 @@
import { defineCollection } from 'astro:content';
import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';

export const collections = {
docs: defineCollection({ schema: docsSchema() }),
i18n: defineCollection({ type: 'data', schema: i18nSchema() }),
};
13 changes: 13 additions & 0 deletions examples/ssr/src/content/docs/404.mdx
@@ -0,0 +1,13 @@
---
title: '404'
template: 'splash'
editUrl: false
head: []
hero: { tagline: 'Not found', actions: [] }
pagefind: false
sidebar: { hidden: false, attrs: {} }
---

import RenderTime from '../../components/RenderTime.astro';

<RenderTime />
9 changes: 9 additions & 0 deletions examples/ssr/src/content/docs/demo.mdx
@@ -0,0 +1,9 @@
---
title: Demonstrating SSR
prev: false
next: false
---

import RenderTime from '../../components/RenderTime.astro';

<RenderTime />
11 changes: 11 additions & 0 deletions examples/ssr/src/content/docs/guides/example.md
@@ -0,0 +1,11 @@
---
title: Example Guide
description: A guide in my new Starlight docs site.
---

Guides lead a user through a specific task they want to accomplish, often with a sequence of steps.
Writing a good guide requires thinking about what your users are trying to do.

## Further reading

- Read [about how-to guides](https://diataxis.fr/how-to-guides/) in the Diátaxis framework
36 changes: 36 additions & 0 deletions examples/ssr/src/content/docs/index.mdx
@@ -0,0 +1,36 @@
---
title: Welcome to Starlight
description: Get started building your docs site with Starlight.
template: splash
hero:
tagline: Congrats on setting up a new Starlight project!
image:
file: ../../assets/houston.webp
actions:
- text: Example Guide
link: /demo
icon: right-arrow
variant: primary
- text: Read the Starlight docs
link: https://starlight.astro.build
icon: external
---

import { Card, CardGrid } from '@astrojs/starlight/components';

## Next steps

<CardGrid stagger>
<Card title="Update content" icon="pencil">
Edit `src/content/docs/index.mdx` to see this page change.
</Card>
<Card title="Add new content" icon="add-document">
Add Markdown or MDX files to `src/content/docs` to create new pages.
</Card>
<Card title="Configure your site" icon="setting">
Edit your `sidebar` and other config in `astro.config.mjs`.
</Card>
<Card title="Read the docs" icon="open-book">
Learn more in [the Starlight Docs](https://starlight.astro.build/).
</Card>
</CardGrid>
11 changes: 11 additions & 0 deletions examples/ssr/src/content/docs/reference/example.md
@@ -0,0 +1,11 @@
---
title: Example Reference
description: A reference page in my new Starlight docs site.
---

Reference pages are ideal for outlining how things work in terse and clear terms.
Less concerned with telling a story or addressing a specific use case, they should give a comprehensive outline of what your documenting.

## Further reading

- Read [about reference](https://diataxis.fr/reference/) in the Diátaxis framework
2 changes: 2 additions & 0 deletions examples/ssr/src/env.d.ts
@@ -0,0 +1,2 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />
3 changes: 3 additions & 0 deletions examples/ssr/tsconfig.json
@@ -0,0 +1,3 @@
{
"extends": "astro/tsconfigs/strict"
}
3 changes: 2 additions & 1 deletion packages/starlight/.gitignore
@@ -1,2 +1,3 @@
# Astro generates this during tests, but we want to ignore it.
src/env.d.ts
env.d.ts
.astro
50 changes: 50 additions & 0 deletions packages/starlight/404SSR.astro
@@ -0,0 +1,50 @@
---
import { getEntry } from 'astro:content';
import config from 'virtual:starlight/user-config';
import EmptyContent from './components/EmptyMarkdown.md';
import Page from './components/Page.astro';
import { generateRouteData } from './utils/route-data';
import type { StarlightDocsEntry } from './utils/routing';
import { useTranslations } from './utils/translations';

export const prerender = false;

const { lang = 'en', dir = 'ltr' } = config.defaultLocale || {};
let locale = config.defaultLocale?.locale;
if (locale === 'root') locale = undefined;

const entryMeta = { dir, lang, locale };
const t = useTranslations(locale);

const fallbackEntry: StarlightDocsEntry = {
slug: '404',
id: '404.md' as StarlightDocsEntry['id'],
body: '',
collection: 'docs',
data: {
title: '404',
template: 'splash',
draft: false,
editUrl: false,
head: [],
hero: { tagline: t('404.text'), actions: [] },
pagefind: false,
sidebar: { hidden: false, attrs: {} },
},
render: async () => ({
Content: EmptyContent,
headings: [],
remarkPluginFrontmatter: {},
}),
};

const userEntry = await getEntry('docs', '404');
const entry = userEntry || fallbackEntry;
const { Content, headings } = await entry.render();
const route = generateRouteData({
props: { ...entryMeta, entryMeta, headings, entry, id: entry.id, slug: entry.slug },
url: Astro.url,
});
---

<Page {...route}><Content /></Page>
1 change: 1 addition & 0 deletions packages/starlight/__tests__/basics/config-errors.test.ts
Expand Up @@ -63,6 +63,7 @@ test('parses valid config successfully', () => {
"locales": undefined,
"pagefind": true,
"pagination": true,
"prerender": true,
"tableOfContents": {
"maxHeadingLevel": 3,
"minHeadingLevel": 2,
Expand Down