Skip to content

Commit db0da56

Browse files
feat: sitemap.xml and robots.txt (#122)
1 parent 0dfb1bd commit db0da56

28 files changed

Lines changed: 1715 additions & 214 deletions

docs/src/routes/guide/(2)config.mdx

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,12 @@ interface SolidBaseConfig<ThemeConfig> {
4747
title?: string;
4848
titleTemplate?: string;
4949
description?: string;
50+
siteUrl?: string;
5051
logo?: string;
5152
issueAutolink?: IssueAutoLinkConfig | false;
5253
llms?: boolean;
54+
sitemap?: boolean | SitemapConfig;
55+
robots?: boolean | RobotsConfig;
5356
lang?: string;
5457
locales?: Record<string, LocaleConfig<ThemeConfig>>;
5558
themeConfig?: ThemeConfig;
@@ -73,11 +76,14 @@ There are several options for setting site-wide metadata and behavior. These opt
7376
title: "My Documentation Site",
7477
titleTemplate: "%s - MySite",
7578
description: "A comprehensive guide to MySite.",
79+
siteUrl: "https://docs.example.com",
7680
logo: "/logo.png",
7781
}
7882
// ..
7983
```
8084

85+
Set `siteUrl` to the canonical public URL for your site. SolidBase uses it as the shared base for generated sitemap URLs, `robots.txt`, and default Open Graph URL metadata.
86+
8187
:::note
8288
For multilingual support, you can use the `locales` option to define different configurations for each locale. More details can be found in the [Internationalization guide](/guide/features/i18n).
8389
:::
@@ -90,18 +96,65 @@ In addition to setting the site title and description, you can also configure ot
9096
- `lastUpdated`: An object to configure the display of the last updated timestamp on each page. Set to `false` to disable this feature.
9197
- `issueAutolink`: An object to configure automatic linking of issue references in your markdown content. Set to `false` to disable this feature.
9298
- `llms`: Set to `true` to emit an `llms.txt` index and markdown copies of your routes for LLM-friendly documentation output.
99+
- `sitemap`: Set to `true` to emit `/sitemap.xml`. You can also pass an object to override the hostname or control sitemap chunking for very large sites.
100+
- `robots`: Set to `true` to emit a simple Google-friendly `/robots.txt` file that allows crawling and points to your sitemap.
93101

94102
```ts title="app.config.ts"
95103
// ..
104+
siteUrl: "https://docs.example.com"
96105
editPath: "https://github.com/[USERNAME]/[REPO]/edit/main/docs/:path"
97106
lastUpdated: false;
98107
issueAutolink: "https://github.com/[USERNAME]/[REPO]/issues/:issue"
99108
llms: true;
109+
sitemap: true;
110+
robots: true;
100111
// ..
101112
```
102113

103114
See the [LLMs.txt guide](/guide/features/llms) for page-level exclusion and output details.
104115

116+
## Sitemap and robots
117+
118+
SolidBase can generate both `/sitemap.xml` and `/robots.txt` during the build.
119+
120+
```ts title="app.config.ts"
121+
// ..
122+
siteUrl: "https://docs.example.com",
123+
sitemap: true,
124+
robots: true,
125+
// ..
126+
```
127+
128+
This emits:
129+
130+
- `/sitemap.xml` with fully-qualified canonical URLs for your markdown routes
131+
- `hreflang` alternates for localized routes, plus `x-default` when a default-locale route exists
132+
- `/robots.txt` with an allow-all policy and a `Sitemap:` reference
133+
134+
If you need more control, `sitemap` also accepts an object:
135+
136+
```ts title="app.config.ts"
137+
// ..
138+
siteUrl: "https://docs.example.com",
139+
sitemap: {
140+
maxUrlsPerSitemap: 10000,
141+
},
142+
robots: {
143+
rules: [
144+
{
145+
userAgent: "*",
146+
allow: ["/"],
147+
disallow: ["/admin/"],
148+
},
149+
],
150+
},
151+
// ..
152+
```
153+
154+
Use `siteUrl` for the normal case. Override `sitemap.hostname` only when your sitemap should use a different canonical host than the rest of the site.
155+
156+
See the [Sitemap and robots guide](/guide/features/sitemap-and-robots) for a full walkthrough of localized alternates, page exclusion, and custom crawler rules.
157+
105158
### Markdown Configuration
106159

107160
In addition to the default markdown support provided by SolidBase, you can include additional markdown plugins, configurations, and other options through the `markdown` option.
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
---
2+
title: Sitemap and Robots
3+
---
4+
5+
# {frontmatter.title}
6+
7+
SolidBase can generate both `/sitemap.xml` and `/robots.txt` during the build so search engines can discover and crawl your docs more reliably.
8+
9+
## Enable the feature
10+
11+
Set a canonical `siteUrl`, then turn both features on in your SolidBase config:
12+
13+
```ts title="app.config.ts"
14+
import { createSolidBase, defineTheme } from "@kobalte/solidbase/config";
15+
import defaultTheme from "@kobalte/solidbase/default-theme";
16+
17+
const theme = defineTheme({
18+
componentsPath: import.meta.resolve("./src/solidbase-theme"),
19+
extends: defaultTheme,
20+
});
21+
22+
const solidBase = createSolidBase(theme);
23+
24+
export default {
25+
...solidBase.startConfig({
26+
ssr: true,
27+
}),
28+
plugins: [
29+
solidBase.plugin({
30+
title: "My Docs",
31+
description: "Documentation for my project",
32+
siteUrl: "https://docs.example.com",
33+
sitemap: true,
34+
robots: true,
35+
}),
36+
],
37+
};
38+
```
39+
40+
With that config, SolidBase emits:
41+
42+
- `/sitemap.xml` with fully-qualified canonical URLs
43+
- `/robots.txt` with an allow-all policy and a `Sitemap:` reference
44+
45+
## What goes into the sitemap
46+
47+
SolidBase builds the sitemap from markdown routes under `src/routes`.
48+
49+
- `.md` and `.mdx` routes are included automatically
50+
- `[...404]` routes are excluded
51+
- localized routes include `hreflang` alternates
52+
- multilingual route groups include `x-default` when a default-locale page exists
53+
54+
If your site grows large enough, SolidBase automatically switches from a single `sitemap.xml` file to a sitemap index plus chunked sitemap files.
55+
56+
## Localized URLs
57+
58+
When you use `lang` and `locales`, SolidBase groups equivalent localized pages together in the sitemap.
59+
60+
```ts title="app.config.ts"
61+
// ..
62+
siteUrl: "https://docs.example.com",
63+
lang: "en-US",
64+
locales: {
65+
fr: {
66+
label: "Français",
67+
lang: "fr-FR",
68+
},
69+
},
70+
sitemap: true,
71+
// ..
72+
```
73+
74+
That means a page like `/guide/getting-started` can emit alternates for both `en-US` and `fr-FR`, plus `x-default` pointing at the default-locale URL.
75+
76+
## Excluding pages from the sitemap
77+
78+
You can exclude individual pages with frontmatter:
79+
80+
```md title="src/routes/internal.mdx"
81+
---
82+
title: Internal
83+
sitemap:
84+
exclude: true
85+
---
86+
```
87+
88+
You can also disable sitemap inclusion entirely for a page with `sitemap: false`.
89+
90+
## Custom sitemap and robots config
91+
92+
The default setup is enough for most sites. If you need more control, you can pass config objects instead of booleans.
93+
94+
```ts title="app.config.ts"
95+
// ..
96+
siteUrl: "https://docs.example.com",
97+
sitemap: {
98+
maxUrlsPerSitemap: 10000,
99+
},
100+
robots: {
101+
rules: [
102+
{
103+
userAgent: "*",
104+
allow: ["/"],
105+
disallow: ["/admin/"],
106+
},
107+
],
108+
},
109+
// ..
110+
```
111+
112+
Use `siteUrl` for the normal case. Only override `sitemap.hostname` when your sitemap should use a different canonical host than the rest of the site.
113+
114+
## Google-friendly defaults
115+
116+
SolidBase keeps the generated files intentionally conservative:
117+
118+
- sitemap URLs are absolute and canonical
119+
- `priority` and `changefreq` are omitted
120+
- `lastmod` is omitted unless SolidBase can source it accurately in the future
121+
- `robots.txt` allows crawling by default instead of blocking resources automatically
122+
123+
If you need page-level metadata details, see the [Frontmatter reference](/reference/frontmatter). For the full config surface, see [Configure Your App](/guide/config).

docs/src/routes/guide/index.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Out of the box support for Markdown and MDX with almost all extensions you'd eve
1919

2020
Generate an `llms.txt` index and markdown mirrors of your docs for AI tooling and machine-readable documentation workflows. Learn more in the [LLMs.txt guide](/guide/features/llms).
2121

22+
### Search engine discovery
23+
24+
Generate a sitemap and `robots.txt` with localized alternates and sensible defaults for search crawlers. Learn more in the [Sitemap and robots guide](/guide/features/sitemap-and-robots).
25+
2226
### Customizable
2327

2428
All the SolidBase components can be overridden to transform your website into your own unique design. To see how, visit the [Extending Themes](/guide/customization/extending-themes) documentation.

docs/src/routes/reference/frontmatter.mdx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,17 @@ llms:
4949
```
5050

5151
You can also write `llms: false` to exclude the page entirely.
52+
53+
## Sitemap
54+
55+
The `sitemap` frontmatter key controls whether a page is included in generated sitemap output.
56+
57+
```md
58+
---
59+
title: About
60+
sitemap:
61+
exclude: true
62+
---
63+
```
64+
65+
You can also write `sitemap: false` to exclude the page entirely.

docs/src/solidbase-theme/Layout.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ function OpenGraph() {
7070
name="og:url"
7171
content={new URL(
7272
location.pathname,
73-
import.meta.env.VITE_ORIGIN ?? "https://solidbase.netlify.app",
73+
solidBaseCtx.config().siteUrl ??
74+
import.meta.env.VITE_ORIGIN ??
75+
"https://solidbase.netlify.app",
7476
).toString()}
7577
/>
7678
<Meta name="twitter:card" content="summary_large_image" />

docs/vite.config.mts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ export default defineConfig({
2323
title: "SolidBase",
2424
description:
2525
"Fully featured, fully customisable static site generation for SolidStart",
26+
siteUrl: "https://solidbase.dev",
2627
llms: true,
28+
sitemap: true,
29+
robots: true,
2730
issueAutolink: "https://github.com/kobaltedev/solidbase/issues/:issue",
2831
lang: "en",
2932
markdown: {

src/config/index.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ export interface SolidBaseConfig<ThemeConfig> {
1313
title?: string;
1414
titleTemplate?: string;
1515
description?: string;
16+
siteUrl?: string;
1617
llms?: boolean;
18+
sitemap?: boolean | SitemapConfig;
19+
robots?: boolean | RobotsConfig;
1720
logo?: string;
1821
issueAutolink?: IssueAutoLinkConfig | false;
1922
lang?: string;
@@ -33,6 +36,8 @@ type ResolvedConfigKeys =
3336
| "title"
3437
| "description"
3538
| "llms"
39+
| "sitemap"
40+
| "robots"
3641
| "lang"
3742
| "issueAutolink"
3843
| "lastUpdated";
@@ -50,6 +55,22 @@ export type LocaleConfig<ThemeConfig> = {
5055
themeConfig?: ThemeConfig;
5156
};
5257

58+
export type SitemapConfig = {
59+
hostname?: string;
60+
maxUrlsPerSitemap?: number;
61+
};
62+
63+
export type RobotsRule = {
64+
userAgent: string | string[];
65+
allow?: string[];
66+
disallow?: string[];
67+
};
68+
69+
export type RobotsConfig = {
70+
rules?: RobotsRule[];
71+
sitemap?: string | false;
72+
};
73+
5374
export type ThemeDefinition<Config> = {
5475
componentsPath: string;
5576
extends?: ThemeDefinition<Config>;
@@ -70,6 +91,8 @@ export function createSolidBase<ThemeConfig>(
7091
description:
7192
"Fully featured, fully customisable static site generation for SolidStart",
7293
llms: false,
94+
sitemap: false,
95+
robots: false,
7396
lang: "en-US",
7497
issueAutolink: false,
7598
lastUpdated: { dateStyle: "short", timeStyle: "short" },
@@ -118,3 +141,23 @@ export function defineTheme<C>(def: ThemeDefinition<C>) {
118141
return def;
119142
}
120143
export type Theme<C> = ReturnType<typeof defineTheme<C>>;
144+
145+
export function normalizeSiteUrl(siteUrl: string) {
146+
return siteUrl.endsWith("/") ? siteUrl : `${siteUrl}/`;
147+
}
148+
149+
export function getSiteUrl(config: Pick<SolidBaseConfig<any>, "siteUrl">) {
150+
if (!config.siteUrl) return undefined;
151+
return normalizeSiteUrl(config.siteUrl);
152+
}
153+
154+
export function getSitemapHostname(
155+
config: Pick<SolidBaseConfig<any>, "siteUrl" | "sitemap">,
156+
) {
157+
if (!config.sitemap) return undefined;
158+
if (config.sitemap !== true && config.sitemap.hostname) {
159+
return normalizeSiteUrl(config.sitemap.hostname);
160+
}
161+
162+
return getSiteUrl(config);
163+
}

0 commit comments

Comments
 (0)