Skip to content

Commit 43b22db

Browse files
authored
fix(docs): add canonical URLs to prevent SEO duplicate content (#107)
1 parent 8940ed1 commit 43b22db

4 files changed

Lines changed: 42 additions & 19 deletions

File tree

packages/docs/src/App.tsx

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -29,133 +29,150 @@ export const routes: RouteDefinition[] = [
2929
route({
3030
path: "/",
3131
component: (
32-
<Layout variant="home">
32+
<Layout variant="home" path="/">
3333
<Home />
3434
</Layout>
3535
),
3636
}),
3737
route({
3838
path: "/getting-started",
3939
component: (
40-
<Layout title="Getting Started">
40+
<Layout title="Getting Started" path="/getting-started">
4141
{defer(<GettingStarted />, { name: "GettingStarted" })}
4242
</Layout>
4343
),
4444
}),
4545
route({
4646
path: "/getting-started/migrating-from-vite-spa",
4747
component: (
48-
<Layout title="Migrating from Vite SPA">
48+
<Layout
49+
title="Migrating from Vite SPA"
50+
path="/getting-started/migrating-from-vite-spa"
51+
>
4952
{defer(<MigratingFromViteSPA />, { name: "MigratingFromViteSPA" })}
5053
</Layout>
5154
),
5255
}),
5356
route({
5457
path: "/faq",
5558
component: (
56-
<Layout title="FAQ">{defer(<FAQ />, { name: "FAQ" })}</Layout>
59+
<Layout title="FAQ" path="/faq">
60+
{defer(<FAQ />, { name: "FAQ" })}
61+
</Layout>
5762
),
5863
}),
5964
route({
6065
path: "/api/funstack-static",
6166
component: (
62-
<Layout title="funstackStatic()">
67+
<Layout title="funstackStatic()" path="/api/funstack-static">
6368
{defer(<FunstackStaticApi />, { name: "FunstackStaticApi" })}
6469
</Layout>
6570
),
6671
}),
6772
route({
6873
path: "/api/defer",
6974
component: (
70-
<Layout title="defer()">
75+
<Layout title="defer()" path="/api/defer">
7176
{defer(<DeferApi />, { name: "DeferApi" })}
7277
</Layout>
7378
),
7479
}),
7580
route({
7681
path: "/api/build-entry",
7782
component: (
78-
<Layout title="BuildEntryFunction">
83+
<Layout title="BuildEntryFunction" path="/api/build-entry">
7984
{defer(<BuildEntryApi />, { name: "BuildEntryApi" })}
8085
</Layout>
8186
),
8287
}),
8388
route({
8489
path: "/api/entry-definition",
8590
component: (
86-
<Layout title="EntryDefinition">
91+
<Layout title="EntryDefinition" path="/api/entry-definition">
8792
{defer(<EntryDefinitionApi />, { name: "EntryDefinitionApi" })}
8893
</Layout>
8994
),
9095
}),
9196
route({
9297
path: "/learn/how-it-works",
9398
component: (
94-
<Layout title="How It Works">
99+
<Layout title="How It Works" path="/learn/how-it-works">
95100
{defer(<HowItWorks />, { name: "HowItWorks" })}
96101
</Layout>
97102
),
98103
}),
99104
route({
100105
path: "/learn/rsc",
101106
component: (
102-
<Layout title="React Server Components">
107+
<Layout title="React Server Components" path="/learn/rsc">
103108
{defer(<RSCConcept />, { name: "RSCConcept" })}
104109
</Layout>
105110
),
106111
}),
107112
route({
108113
path: "/learn/optimizing-payloads",
109114
component: (
110-
<Layout title="Optimizing RSC Payloads">
115+
<Layout
116+
title="Optimizing RSC Payloads"
117+
path="/learn/optimizing-payloads"
118+
>
111119
{defer(<OptimizingPayloads />, { name: "OptimizingPayloads" })}
112120
</Layout>
113121
),
114122
}),
115123
route({
116124
path: "/learn/lazy-server-components",
117125
component: (
118-
<Layout title="Using lazy() in Server Components">
126+
<Layout
127+
title="Using lazy() in Server Components"
128+
path="/learn/lazy-server-components"
129+
>
119130
{defer(<LazyServerComponents />, { name: "LazyServerComponents" })}
120131
</Layout>
121132
),
122133
}),
123134
route({
124135
path: "/learn/defer-and-activity",
125136
component: (
126-
<Layout title="Prefetching with defer() and Activity">
137+
<Layout
138+
title="Prefetching with defer() and Activity"
139+
path="/learn/defer-and-activity"
140+
>
127141
{defer(<DeferAndActivity />, { name: "DeferAndActivity" })}
128142
</Layout>
129143
),
130144
}),
131145
route({
132146
path: "/learn/file-system-routing",
133147
component: (
134-
<Layout title="File-System Routing">
148+
<Layout title="File-System Routing" path="/learn/file-system-routing">
135149
{defer(<FileSystemRouting />, { name: "FileSystemRouting" })}
136150
</Layout>
137151
),
138152
}),
139153
route({
140154
path: "/advanced/multiple-entrypoints",
141155
component: (
142-
<Layout title="Multiple Entrypoints (SSG)">
156+
<Layout
157+
title="Multiple Entrypoints (SSG)"
158+
path="/advanced/multiple-entrypoints"
159+
>
143160
{defer(<MultipleEntrypoints />, { name: "MultipleEntrypoints" })}
144161
</Layout>
145162
),
146163
}),
147164
route({
148165
path: "/advanced/ssr",
149166
component: (
150-
<Layout title="Server-Side Rendering">
167+
<Layout title="Server-Side Rendering" path="/advanced/ssr">
151168
{defer(<SSR />, { name: "SSR" })}
152169
</Layout>
153170
),
154171
}),
155172
route({
156173
path: "*",
157174
component: (
158-
<Layout title="Not Found">
175+
<Layout title="Not Found" path="/404">
159176
<NotFound />
160177
</Layout>
161178
),

packages/docs/src/build.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ import path from "node:path";
33
import type { BuildEntryFunction } from "@funstack/static/server";
44
import type { RouteDefinition } from "@funstack/router/server";
55
import { routes } from "./App";
6-
7-
const siteUrl = "https://static.funstack.work";
6+
import { siteUrl } from "./constants";
87

98
function collectPaths(routes: RouteDefinition[]): string[] {
109
const paths: string[] = [];

packages/docs/src/components/Layout/Layout.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type React from "react";
22
import { Suspense } from "react";
3+
import { siteUrl } from "../../constants";
34
import { Header } from "../Header/Header";
45
import { MobileMenu } from "../MobileMenu/MobileMenu";
56
import { Sidebar } from "../Sidebar/Sidebar";
@@ -12,23 +13,28 @@ interface LayoutProps {
1213
children: React.ReactNode;
1314
variant?: LayoutVariant;
1415
title?: string;
16+
path: string;
1517
}
1618

1719
export const Layout: React.FC<LayoutProps> = ({
1820
children,
1921
variant = "docs",
2022
title,
23+
path,
2124
}) => {
2225
const layoutClass =
2326
variant === "home" ? styles.homeLayout : styles.docsLayout;
2427
const fullTitle = title
2528
? `${title} | FUNSTACK Static`
2629
: "FUNSTACK Static - docs";
30+
const canonicalUrl = path === "/" ? `${siteUrl}/` : `${siteUrl}${path}`;
2731

2832
return (
2933
<div className={`${styles.layout} ${layoutClass}`}>
3034
<title>{fullTitle}</title>
35+
<link rel="canonical" href={canonicalUrl} />
3136
<meta property="og:title" content={fullTitle} />
37+
<meta property="og:url" content={canonicalUrl} />
3238
<meta name="twitter:title" content={fullTitle} />
3339
<Header menuSlot={<MobileMenu />} />
3440
<div className={styles.main}>

packages/docs/src/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const siteUrl = "https://static.funstack.work";

0 commit comments

Comments
 (0)