Skip to content

Commit 51d8d46

Browse files
committed
feat(seo): generate robots.txt and sitemap.xml during prerender
Produce robots.txt with sitemap reference and sitemap.xml from the routes manifest during the prerender phase. Base URL is configurable via SITE_BASE_URL env var, defaulting to https://commitbee.dev.
1 parent 38475bd commit 51d8d46

1 file changed

Lines changed: 34 additions & 4 deletions

File tree

src/bin/prerender.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,32 @@ fn main() {
122122
fs::copy(&index_path, dist_dir.join("404.html")).ok();
123123
}
124124

125+
// Generate robots.txt
126+
let base_url = env_base_url().unwrap_or_else(|| "https://commitbee.dev".to_string());
127+
let robots = format!("User-agent: *\nAllow: /\n\nSitemap: {base_url}/sitemap.xml\n");
128+
fs::write(dist_dir.join("robots.txt"), &robots).expect("Failed to write robots.txt");
129+
println!(" robots.txt -> dist/robots.txt");
130+
131+
// Generate sitemap.xml
132+
let mut sitemap = String::from(
133+
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\
134+
<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n",
135+
);
136+
for route in &routes {
137+
let priority = if *route == "/" { "1.0" } else { "0.8" };
138+
let loc = if *route == "/" {
139+
base_url.clone()
140+
} else {
141+
format!("{base_url}{route}")
142+
};
143+
sitemap.push_str(&format!(
144+
" <url>\n <loc>{loc}</loc>\n <priority>{priority}</priority>\n </url>\n"
145+
));
146+
}
147+
sitemap.push_str("</urlset>\n");
148+
fs::write(dist_dir.join("sitemap.xml"), &sitemap).expect("Failed to write sitemap.xml");
149+
println!(" sitemap.xml -> dist/sitemap.xml");
150+
125151
// Stop server
126152
server.kill().ok();
127153
server.wait().ok();
@@ -136,6 +162,10 @@ fn env_port() -> Option<u16> {
136162
std::env::var("PRERENDER_PORT").ok()?.parse().ok()
137163
}
138164

165+
fn env_base_url() -> Option<String> {
166+
std::env::var("SITE_BASE_URL").ok()
167+
}
168+
139169
fn wait_for_server(port: u16, timeout: Duration) -> bool {
140170
let start = Instant::now();
141171
while start.elapsed() < timeout {
@@ -182,10 +212,10 @@ fn walk_find(dir: &Path, filename: &str, path_contains: &str) -> Option<PathBuf>
182212
{
183213
return Some(path);
184214
}
185-
if path.is_dir() {
186-
if let Some(found) = walk_find(&path, filename, path_contains) {
187-
return Some(found);
188-
}
215+
if path.is_dir()
216+
&& let Some(found) = walk_find(&path, filename, path_contains)
217+
{
218+
return Some(found);
189219
}
190220
}
191221
None

0 commit comments

Comments
 (0)