Wzorzec · TypeScript
Dynamiczny sitemap.xml w Next.js (app/sitemap.ts)
Jedna mapa witryny ze ścieżkami statycznymi i treściowymi; zgodność z collectIndexableUrls i adresem kanonicznym.
Poziom: średniSzacunek czasu: ~40 min
Generator sitemap zbiera stabilne ścieżki i slugi z CMS/plików; lastmod pochodzi z daty treści, jeśli jest dostępna.
- Każdy URL w sitemap musi zgadzać się z kanonicznym
- nie umieszczaj stron noindex
- przy dużym katalogu użyj podziału lub indeksu sitemap
app/sitemap.tsw App Router zwraca tablicę adresów URL. W jednym przebiegu zbierz trasy statyczne i dynamiczne slugi (blog, biblioteka, case studies).
Kod
Poniżej — faktyczna logika z app/sitemap.ts w tym projekcie (ścieżki statyczne, case’y, wpisy, wzorce biblioteki):
import type { MetadataRoute } from 'next'
import { caseSlugOrder } from '@/data/cases'
import { SITE_STATIC_PATHS } from '@/data/site-static-paths'
import { getAllPosts, getPostModifiedDate } from '@/lib/blog'
import { getAllLibraryEntries, getLibraryModifiedDate } from '@/lib/library'
import { getStaticPagesLastModified } from '@/lib/site-static-lastmod'
import { getSiteUrl } from '@/lib/site'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const site = getSiteUrl()
const base = site.replace(/\/$/, '')
const staticLastMod = getStaticPagesLastModified()
const posts = await getAllPosts()
const library = await getAllLibraryEntries()
const entries: MetadataRoute.Sitemap = [
...SITE_STATIC_PATHS.map((path) => ({
url: `${base}${path}`,
lastModified: staticLastMod,
changeFrequency: 'weekly' as const,
priority: path === '/' ? 1 : 0.7,
})),
...caseSlugOrder.map((slug) => ({
url: `${base}/kejsy/${slug}/`,
lastModified: staticLastMod,
changeFrequency: 'monthly' as const,
priority: 0.65,
})),
...posts.map((p) => ({
url: `${base}/blog/${p.slug}/`,
lastModified: new Date(getPostModifiedDate(p)),
changeFrequency: 'monthly' as const,
priority: 0.6,
})),
...library.map((e) => ({
url: `${base}/biblioteka/${e.slug}/`,
lastModified: new Date(getLibraryModifiedDate(e)),
changeFrequency: 'monthly' as const,
priority: 0.62,
})),
]
return entries
}
Weryfikacja
Co sprawdzić:
-
Plik się otwiera. W przeglądarce wejdź na
https://twoja-domena/sitemap.xml— powinien załadować się XML bez błędu 404 w HTML. Jeśli widzisz aplikację Next zamiast XML, upewnij się, że wapp/jestsitemap.ts(lubsitemap.js) i że eksportuje funkcję domyślną. -
Search Console. W Google Search Console sekcja „Mapy witryn” → dodaj URL
https://twoja-domena/sitemap.xml. Status „Nie pobrano” lub błędy parsowania oznaczają, że plik jest niedostępny dla robota albo XML jest niepoprawny. -
Zgodność z canonical. Wybierz kilka URL z pliku, otwórz strony, w źródle znajdź
<link rel="canonical" ...>. Adres musi zgadzać się z URL w sitemap (włącznie z końcowym/, jeśli tak ustawiono kanoniczny na stronie). -
Spójność z noindex. Strony z
robots: { index: false }lub<meta name="robots" content="noindex">zwykle nie umieszczaj w sitemap — w przeciwnym razie wysyłasz sprzeczne sygnały do wyszukiwarki.
Źródła
Inne wzorce
Wpisy na blogu
- SEO
Wielojęzyczność B2B: indeksowalne locale vs widget tłumaczący
Tłumacz na stronie i indeksowalne wersje językowe to różne zadania. Omawiamy URL, meta, zaufanie i drabinę dojrzałości dla eksportu i łańcuchów dostaw — bez magii.
Czytaj artykuł - SEO
Architektura SEO: dlaczego strona nie sprzedaje bez struktury
Jak właściwa struktura strony wpływa na sprzedaż i pozycje. Dlaczego design jest drugorzędny, a semantyka pierwsza.
Czytaj artykuł
Wdrożyć pod Twoją domenę i stack?
Krótki formularz: imię, telefon, strona. Po wysłaniu — odpowiedź z kolejnością prac i orientacją etapów; szczegóły doprecyzujemy na kontakcie.