feat: update SEO handling by dynamically setting canonical links and exclude auth pages from sitemap

pull/55/head
David Montero Crespo 2026-03-23 15:06:49 -03:00
parent 22a9681cc4
commit d61f2b7ab0
3 changed files with 19 additions and 16 deletions

View File

@ -13,7 +13,7 @@
<meta name="keywords" content="arduino emulator, arduino simulator, arduino simulator free, avr8 emulator, avr simulator, atmega328p simulator, atmega2560 simulator, attiny85 simulator, arduino uno simulator, arduino mega simulator, arduino nano simulator, rp2040 emulator, raspberry pi pico simulator, esp32 emulator, esp32 simulator, esp32-c3 simulator, esp32-s3 emulator, risc-v simulator, ch32v003, raspberry pi 3 emulator, wokwi alternative, arduino ide browser, arduino online, electronics simulator, velxio" /> <meta name="keywords" content="arduino emulator, arduino simulator, arduino simulator free, avr8 emulator, avr simulator, atmega328p simulator, atmega2560 simulator, attiny85 simulator, arduino uno simulator, arduino mega simulator, arduino nano simulator, rp2040 emulator, raspberry pi pico simulator, esp32 emulator, esp32 simulator, esp32-c3 simulator, esp32-s3 emulator, risc-v simulator, ch32v003, raspberry pi 3 emulator, wokwi alternative, arduino ide browser, arduino online, electronics simulator, velxio" />
<meta name="author" content="David Montero Crespo" /> <meta name="author" content="David Montero Crespo" />
<meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1" /> <meta name="robots" content="index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1" />
<link rel="canonical" href="https://velxio.dev/" /> <!-- canonical is set dynamically per-route by the useSEO hook -->
<!-- Google Search Console verification — replace token after verifying in Search Console --> <!-- Google Search Console verification — replace token after verifying in Search Console -->
<!-- <meta name="google-site-verification" content="REPLACE_WITH_YOUR_VERIFICATION_TOKEN" /> --> <!-- <meta name="google-site-verification" content="REPLACE_WITH_YOUR_VERIFICATION_TOKEN" /> -->

View File

@ -129,18 +129,6 @@
<priority>0.85</priority> <priority>0.85</priority>
</url> </url>
<url> <!-- Auth pages intentionally excluded from sitemap (not for indexing) -->
<loc>https://velxio.dev/login</loc>
<lastmod>2026-03-06</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
<url>
<loc>https://velxio.dev/register</loc>
<lastmod>2026-03-06</lastmod>
<changefreq>yearly</changefreq>
<priority>0.3</priority>
</url>
</urlset> </urlset>

View File

@ -47,6 +47,17 @@ export function useSEO({ title, description, url, ogImage, jsonLd }: SEOMeta) {
const origTwDesc = get(twDescEl); const origTwDesc = get(twDescEl);
const origCanonical = canonicalEl?.getAttribute('href') ?? ''; const origCanonical = canonicalEl?.getAttribute('href') ?? '';
// If no <link rel="canonical"> exists yet, create one so each SPA route
// gets its own canonical (avoids all routes appearing to point back to /).
let createdCanonical = false;
let activeCanonical: HTMLLinkElement | null = canonicalEl as HTMLLinkElement | null;
if (!activeCanonical) {
activeCanonical = document.createElement('link') as HTMLLinkElement;
activeCanonical.rel = 'canonical';
document.head.appendChild(activeCanonical);
createdCanonical = true;
}
// Apply // Apply
document.title = title; document.title = title;
set(descEl, description); set(descEl, description);
@ -56,7 +67,7 @@ export function useSEO({ title, description, url, ogImage, jsonLd }: SEOMeta) {
if (ogImage) set(ogImgEl, ogImage); if (ogImage) set(ogImgEl, ogImage);
set(twTitleEl, title); set(twTitleEl, title);
set(twDescEl, description); set(twDescEl, description);
canonicalEl?.setAttribute('href', url); activeCanonical.setAttribute('href', url);
// Inject JSON-LD once (module-level constants don't change) // Inject JSON-LD once (module-level constants don't change)
if (jsonLd && !scriptRef.current) { if (jsonLd && !scriptRef.current) {
@ -77,7 +88,11 @@ export function useSEO({ title, description, url, ogImage, jsonLd }: SEOMeta) {
if (ogImage) set(ogImgEl, origOgImg); if (ogImage) set(ogImgEl, origOgImg);
set(twTitleEl, origTwTitle); set(twTitleEl, origTwTitle);
set(twDescEl, origTwDesc); set(twDescEl, origTwDesc);
canonicalEl?.setAttribute('href', origCanonical); if (createdCanonical && activeCanonical && document.head.contains(activeCanonical)) {
document.head.removeChild(activeCanonical);
} else {
activeCanonical?.setAttribute('href', origCanonical);
}
if (scriptRef.current) { if (scriptRef.current) {
document.head.removeChild(scriptRef.current); document.head.removeChild(scriptRef.current);
scriptRef.current = null; scriptRef.current = null;