Skip to content

Commit a2ce0ec

Browse files
authored
Merge pull request #15 from DavideDaniel/claude/fix-prerender-bug-2brsI
Add server-side helmet integration for SEO meta tags
2 parents fe6ef9e + 2f566a2 commit a2ce0ec

2 files changed

Lines changed: 63 additions & 3 deletions

File tree

public/robots.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ User-agent: *
22
Allow: /
33

44
Sitemap: https://daviddaniel.tech/sitemap.xml
5+
Sitemap: https://daviddaniel.tech/research/sitemap.xml

scripts/prerender.js

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,73 @@ async function prerender() {
2121
const { render } = await import(path.resolve(dist, 'server/entry-server.js'))
2222

2323
for (const route of routes) {
24-
const { html } = render(route)
24+
const { html, helmet } = render(route)
2525

26-
// Inject pre-rendered content into the root div
27-
const output = template.replace(
26+
// Start with injecting pre-rendered content into the root div
27+
let output = template.replace(
2828
'<div id="root"></div>',
2929
`<div id="root">${html}</div>`
3030
)
3131

32+
// Inject page-specific <head> tags from react-helmet-async
33+
if (helmet) {
34+
const helmetTitle = helmet.title.toString()
35+
const helmetMeta = helmet.meta.toString()
36+
const helmetLink = helmet.link.toString()
37+
const helmetScript = helmet.script.toString()
38+
39+
// Replace the existing <title> with the page-specific one
40+
if (helmetTitle) {
41+
output = output.replace(/<title>[^<]*<\/title>/, helmetTitle)
42+
}
43+
44+
// Replace homepage meta description and robot-indexable meta tags with page-specific ones
45+
// Remove existing meta tags that helmet will provide (description, robots, og:*, twitter:*)
46+
if (helmetMeta) {
47+
output = output.replace(
48+
/\s*<meta name="description"[^>]*>/g,
49+
''
50+
)
51+
output = output.replace(
52+
/\s*<meta name="robots"[^>]*>/g,
53+
''
54+
)
55+
output = output.replace(
56+
/\s*<meta property="og:[^"]*"[^>]*>/g,
57+
''
58+
)
59+
output = output.replace(
60+
/\s*<!-- Open Graph -->/g,
61+
''
62+
)
63+
output = output.replace(
64+
/\s*<meta name="twitter:[^"]*"[^>]*>/g,
65+
''
66+
)
67+
output = output.replace(
68+
/\s*<!-- Twitter Card -->/g,
69+
''
70+
)
71+
// Inject helmet meta tags before </head>
72+
output = output.replace('</head>', ` ${helmetMeta}\n </head>`)
73+
}
74+
75+
// Replace homepage canonical link with page-specific one
76+
if (helmetLink) {
77+
output = output.replace(
78+
/\s*<link rel="canonical"[^>]*>/g,
79+
''
80+
)
81+
// Inject helmet link tags before </head>
82+
output = output.replace('</head>', ` ${helmetLink}\n </head>`)
83+
}
84+
85+
// Inject any page-specific script tags (e.g., JSON-LD structured data)
86+
if (helmetScript) {
87+
output = output.replace('</head>', ` ${helmetScript}\n </head>`)
88+
}
89+
}
90+
3291
// Determine output path
3392
const outputPath =
3493
route === '/'

0 commit comments

Comments
 (0)