Usamos cookies para mejorar tu experiencia en el sitio
CodeWorlds

Generowanie map witryn i robots.txt

W świecie wyszukiwarek internetowych, dostępność treści i ich poprawna indeksacja stanowią fundament skutecznego SEO (Search Engine Optimization). Next.js oferuje zaawansowane mechanizmy i narzędzia, które ułatwiają generowanie map witryn (sitemaps) oraz plików robots.txt - dwóch kluczowych elementów dla wyszukiwarek takich jak Google, Bing czy Yahoo.

Znaczenie map witryn i pliku robots.txt

Mapa witryny (Sitemap)

Mapa witryny to plik XML, który zawiera listę wszystkich adresów URL twojej strony wraz z dodatkowymi metadanymi, takimi jak:

  • Data ostatniej modyfikacji strony
  • Częstotliwość zmian
  • Priorytet ważności w porównaniu z innymi stronami

Mapa witryny pomaga wyszukiwarkom w następujących aspektach:

  1. Odkrywanie zawartości - informuje o wszystkich stronach na Twojej witrynie
  2. Efektywne indeksowanie - pomaga zrozumieć strukturę witryny
  3. Priorytyzacja - wskazuje, które strony są najważniejsze
  4. Aktualność - informuje, kiedy strony były ostatnio modyfikowane

Plik robots.txt

Robots.txt to prosty plik tekstowy, który zawiera instrukcje dla robotów wyszukiwarek (crawlers). Główne funkcje robots.txt to:

  1. Kontrola dostępu - określa, które strony mogą być indeksowane, a które nie
  2. Zarządzanie ruchem botów - zapobiega przeciążeniu serwera przez ograniczenie dostępu
  3. Wskazywanie lokalizacji mapy witryny - informuje boty o lokalizacji pliku sitemap.xml

Ręczne generowanie mapy witryny w Next.js

Zacznijmy od najprostszego podejścia - ręcznego stworzenia mapy witryny jako statycznego pliku XML:

1// app/sitemap.xml/route.ts
2import { BASE_URL } from '@/lib/constants';
3import { getAllPostSlugs } from '@/lib/api';
4
5export async function GET() {
6  // Pobierz dynamiczne dane, np. adresy URL wszystkich postów bloga
7  const postSlugs = await getAllPostSlugs();
8  
9  // Aktualna data dla lastmod
10  const date = new Date().toISOString();
11  
12  // Tworzenie zawartości XML
13  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
14    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
15      <url>
16        <loc>${BASE_URL}</loc>
17        <lastmod>${date}</lastmod>
18        <changefreq>daily</changefreq>
19        <priority>1.0</priority>
20      </url>
21      <url>
22        <loc>${BASE_URL}/about</loc>
23        <lastmod>${date}</lastmod>
24        <changefreq>monthly</changefreq>
25        <priority>0.8</priority>
26      </url>
27      <url>
28        <loc>${BASE_URL}/products</loc>
29        <lastmod>${date}</lastmod>
30        <changefreq>weekly</changefreq>
31        <priority>0.9</priority>
32      </url>
33      ${postSlugs.map(slug => `
34        <url>
35          <loc>${BASE_URL}/blog/${slug}</loc>
36          <lastmod>${date}</lastmod>
37          <changefreq>weekly</changefreq>
38          <priority>0.7</priority>
39        </url>
40      `).join('')}
41    </urlset>`;
42  
43  // Zwróć odpowiedź z odpowiednim Content-Type
44  return new Response(sitemap, {
45    headers: {
46      'Content-Type': 'application/xml',
47      'Cache-Control': 'public, max-age=3600, s-maxage=3600'
48    }
49  });
50}

To podejście jest elastyczne i pozwala na pełną kontrolę nad zawartością mapy witryny, ale wymaga ręcznego zarządzania i aktualizacji.

Automatyczne generowanie mapy witryny za pomocą funkcji sitemap()

Next.js 13.4+ wprowadził specjalną funkcję

sitemap()
, która upraszcza generowanie map witryn. W tym podejściu definiujesz plik
sitemap.ts
lub
sitemap.js
w katalogu głównym aplikacji:

1// app/sitemap.ts
2import { MetadataRoute } from 'next';
3import { getAllProducts } from '@/lib/products';
4import { getAllPosts } from '@/lib/blog';
5
6export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
7  // Pobierz wszystkie produkty
8  const products = await getAllProducts();
9  const productEntries = products.map(product => ({
10    url: `https://example.com/products/${product.slug}`,
11    lastModified: new Date(product.updatedAt),
12    changeFrequency: 'weekly' as const,
13    priority: 0.8,
14  }));
15  
16  // Pobierz wszystkie posty bloga
17  const posts = await getAllPosts();
18  const blogEntries = posts.map(post => ({
19    url: `https://example.com/blog/${post.slug}`,
20    lastModified: new Date(post.publishedAt),
21    changeFrequency: 'monthly' as const,
22    priority: 0.7,
23  }));
24  
25  // Statyczne strony
26  const staticPages = [
27    {
28      url: 'https://example.com',
29      lastModified: new Date(),
30      changeFrequency: 'daily' as const,
31      priority: 1.0,
32    },
33    {
34      url: 'https://example.com/about',
35      lastModified: new Date(),
36      changeFrequency: 'monthly' as const,
37      priority: 0.5,
38    },
39    {
40      url: 'https://example.com/contact',
41      lastModified: new Date(),
42      changeFrequency: 'yearly' as const,
43      priority: 0.5,
44    },
45  ];
46  
47  // Połącz wszystkie wpisy
48  return [...staticPages, ...productEntries, ...blogEntries];
49}

Kiedy budujesz aplikację, Next.js automatycznie wygeneruje plik

/sitemap.xml
na podstawie zwracanych danych. Dodatkowe korzyści tego podejścia:

  • Wbudowane typowanie TypeScript - dzięki
    MetadataRoute.Sitemap
  • Automatyczna walidacja - Next.js sprawdza poprawność struktury danych
  • Integracja z systemem kompilacji - mapa witryny jest generowana podczas budowania

Generowanie mapy witryny dla dużych stron: podejście wieloplikowe

Dla większych stron z tysiącami URL, zaleca się tworzenie wielu map witryn i indeksu map witryn. Oto przykład implementacji:

1// app/sitemap-index.xml/route.ts
2export async function GET() {
3  const baseUrl = 'https://example.com';
4  
5  const sitemapIndex = `<?xml version="1.0" encoding="UTF-8"?>
6    <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
7      <sitemap>
8        <loc>${baseUrl}/sitemaps/static-sitemap.xml</loc>
9        <lastmod>${new Date().toISOString()}</lastmod>
10      </sitemap>
11      <sitemap>
12        <loc>${baseUrl}/sitemaps/products-sitemap.xml</loc>
13        <lastmod>${new Date().toISOString()}</lastmod>
14      </sitemap>
15      <sitemap>
16        <loc>${baseUrl}/sitemaps/blog-sitemap.xml</loc>
17        <lastmod>${new Date().toISOString()}</lastmod>
18      </sitemap>
19    </sitemapindex>`;
20  
21  return new Response(sitemapIndex, {
22    headers: {
23      'Content-Type': 'application/xml',
24      'Cache-Control': 'public, max-age=3600, s-maxage=3600'
25    }
26  });
27}
28
29// app/sitemaps/static-sitemap.xml/route.ts
30export async function GET() {
31  // Logika generowania mapy statycznych stron...
32}
33
34// app/sitemaps/products-sitemap.xml/route.ts
35export async function GET() {
36  // Logika generowania mapy produktów...
37}
38
39// app/sitemaps/blog-sitemap.xml/route.ts
40export async function GET() {
41  // Logika generowania mapy blogów...
42}

To podejście jest skalowalne i pozwala każdej mapie witryny pozostać poniżej limitu 50,000 URL (zalecany maksymalny rozmiar pojedynczej mapy witryny).

Tworzenie pliku robots.txt

Ręczne tworzenie robots.txt

Najprostszym sposobem jest stworzenie pliku Route Handler dla robots.txt:

1// app/robots.txt/route.ts
2export async function GET() {
3  const robotsTxt = `# https://www.robotstxt.org/robotstxt.html
4User-agent: *
5Allow: /
6
7Disallow: /admin/
8Disallow: /api/
9Disallow: /internal/
10
11Sitemap: https://example.com/sitemap.xml`;
12  
13  return new Response(robotsTxt, {
14    headers: {
15      'Content-Type': 'text/plain',
16      'Cache-Control': 'public, max-age=3600, s-maxage=3600'
17    }
18  });
19}

Użycie funkcji robots() w Next.js

Next.js 13.4+ wprowadził również dedykowaną funkcję

robots()
do generowania pliku robots.txt:

1// app/robots.ts
2import { MetadataRoute } from 'next';
3
4export default function robots(): MetadataRoute.Robots {
5  return {
6    rules: {
7      userAgent: '*',
8      allow: '/',
9      disallow: ['/admin/', '/api/', '/internal/'],
10    },
11    sitemap: 'https://example.com/sitemap.xml',
12  };
13}

Podobnie jak w przypadku funkcji

sitemap()
, Next.js automatycznie wygeneruje plik
/robots.txt
na podstawie zwracanych danych, z wbudowaną walidacją i obsługą TypeScript.

Dynamiczne generowanie maps witryn i robots.txt

Dla bardziej zaawansowanych przypadków użycia, możesz tworzyć zależne od środowiska lub dynamiczne mapy witryn i pliki robots.txt:

1// app/robots.ts
2import { MetadataRoute } from 'next';
3
4export default function robots(): MetadataRoute.Robots {
5  // Różne zasady dla różnych środowisk
6  const isProduction = process.env.NODE_ENV === 'production';
7  
8  if (!isProduction) {
9    return {
10      rules: {
11        userAgent: '*',
12        disallow: '/',
13      },
14    };
15  }
16  
17  return {
18    rules: {
19      userAgent: '*',
20      allow: '/',
21      disallow: ['/admin/', '/api/'],
22    },
23    sitemap: 'https://example.com/sitemap.xml',
24  };
25}

W powyższym przykładzie, w środowisku deweloperskim robots.txt blokuje indeksację całej witryny, podczas gdy w produkcji pozwala na indeksację większości stron.

Weryfikacja i testowanie

Po wdrożeniu map witryn i pliku robots.txt, ważne jest ich przetestowanie, aby upewnić się, że działają poprawnie:

Narzędzia do testowania

  1. Google Search Console - dodaj swoją stronę i prześlij mapę witryny do weryfikacji
  2. Bing Webmaster Tools - podobnie jak Google, oferuje narzędzia do weryfikacji
  3. Narzędzia sprawdzania map witryn i Robots.txt:

Ręczna weryfikacja

Możesz także ręcznie sprawdzić swoje pliki, aby upewnić się, że zawierają oczekiwane dane:

  1. Odwiedź
    https://yourdomain.com/sitemap.xml
    w przeglądarce - powinien pokazać się poprawnie sformatowany plik XML
  2. Odwiedź
    https://yourdomain.com/robots.txt
    - powinien pokazać się poprawny plik tekstowy
  3. Sprawdź przykładowe URL z mapy witryny, aby upewnić się, że są one dostępne i zawierają oczekiwaną treść

Najlepsze praktyki

Dla map witryn

  1. Aktualizuj regularnie - generuj mapy witryn przy każdym wdrożeniu lub zmianie treści
  2. Uwzględniaj tylko kanoniczne URL - unikaj duplikatów i wersji alternatywnych tej samej treści
  3. Używaj dokładnych dat lastmod - nie generuj daty dynamicznie, jeśli treść się nie zmieniła
  4. Uwzględniaj tylko ważne strony - pomijaj strony administracyjne, logowania, koszyki itp.
  5. Uwzględniaj alternatywne wersje językowe - używaj elementu
    <xhtml:link rel="alternate">
    dla wielojęzycznych stron

Dla pliku robots.txt

  1. Bądź selektywny z Disallow - blokuj tylko te ścieżki, które naprawdę nie powinny być indeksowane
  2. Używaj odpowiednich User-agent - rozważ różne zasady dla różnych robotów
  3. Dodaj link do mapy witryny - zawsze uwzględniaj odniesienie do sitemap.xml
  4. Komentuj swoje zasady - dodawaj komentarze wyjaśniające, dlaczego blokujesz określone ścieżki
  5. Testuj zmiany - weryfikuj, czy zmiany w robots.txt nie blokują ważnych stron

Automatyzacja aktualizacji map witryn

Dla stron, które często się zmieniają, rozważ automatyzację generowania map witryn:

1// scripts/generate-sitemap.js
2const fs = require('fs');
3const path = require('path');
4const { getAllDynamicPaths } = require('../lib/api');
5
6async function generateSitemap() {
7  console.log('Generowanie mapy witryny...');
8  
9  // Pobierz wszystkie dynamiczne ścieżki
10  const dynamicPaths = await getAllDynamicPaths();
11  
12  // Generuj XML
13  const date = new Date().toISOString();
14  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
15<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
16  <url>
17    <loc>https://example.com</loc>
18    <lastmod>${date}</lastmod>
19    <priority>1.0</priority>
20  </url>
21  ${dynamicPaths.map(path => `
22  <url>
23    <loc>https://example.com${path}</loc>
24    <lastmod>${date}</lastmod>
25    <priority>0.8</priority>
26  </url>
27  `).join('')}
28</urlset>`;
29  
30  // Zapisz do pliku
31  const publicPath = path.join(process.cwd(), 'public');
32  fs.writeFileSync(path.join(publicPath, 'sitemap.xml'), sitemap);
33  
34  console.log('Mapa witryny wygenerowana pomyślnie!');
35}
36
37generateSitemap().catch(console.error);

Skrypt ten można uruchamiać jako krok w procesie wdrażania lub poprzez zaplanowane zadanie.

Integracja z CMS

Jeśli korzystasz z CMS (Content Management System), możesz automatycznie generować mapy witryn na podstawie zawartości zarządzanej przez CMS:

1// app/sitemap.ts
2import { MetadataRoute } from 'next';
3import { getCmsClient } from '@/lib/cms';
4
5export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
6  const cms = getCmsClient();
7  
8  // Pobierz wszystkie strony z CMS
9  const pages = await cms.getPages();
10  const pageEntries = pages.map(page => ({
11    url: `https://example.com/${page.slug}`,
12    lastModified: new Date(page.updatedAt),
13    changeFrequency: 'weekly' as const,
14    priority: 0.8,
15  }));
16  
17  // Pobierz wszystkie posty z CMS
18  const posts = await cms.getPosts();
19  const postEntries = posts.map(post => ({
20    url: `https://example.com/blog/${post.slug}`,
21    lastModified: new Date(post.updatedAt),
22    changeFrequency: 'weekly' as const,
23    priority: 0.7,
24  }));
25  
26  // Połącz wszystkie wpisy
27  return [
28    {
29      url: 'https://example.com',
30      lastModified: new Date(),
31      changeFrequency: 'daily' as const,
32      priority: 1.0,
33    },
34    ...pageEntries,
35    ...postEntries,
36  ];
37}

Obsługa map witryn obrazów i wideo

Dla stron z dużą ilością obrazów lub wideo, warto rozważyć specjalne mapy witryn:

Mapa witryny obrazów

1// app/image-sitemap.xml/route.ts
2import { getAllProductImages } from '@/lib/products';
3
4export async function GET() {
5  const images = await getAllProductImages();
6  
7  const sitemap = `<?xml version="1.0" encoding="UTF-8"?>
8    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
9            xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">
10      ${images.map(image => `
11        <url>
12          <loc>https://example.com/products/${image.productSlug}</loc>
13          <image:image>
14            <image:loc>https://example.com${image.url}</image:loc>
15            <image:title>${image.title}</image:title>
16            <image:caption>${image.caption}</image:caption>
17          </image:image>
18        </url>
19      `).join('')}
20    </urlset>`;
21  
22  return new Response(sitemap, {
23    headers: {
24      'Content-Type': 'application/xml',
25      'Cache-Control': 'public, max-age=3600, s-maxage=3600'
26    }
27  });
28}

Podsumowanie

Mapa witryny i plik robots.txt to kluczowe elementy każdej aplikacji Next.js, które chcą być widoczne w wynikach wyszukiwania. Next.js 13.4+ wprowadził dedykowane funkcje

sitemap()
i
robots()
, które znacznie upraszczają proces generowania tych plików, zapewniając jednocześnie wsparcie dla TypeScript i automatyczną walidację.

Pamiętaj, że skuteczne SEO to nie tylko techniczne aspekty jak mapy witryn, ale szerszy zestaw praktyk, w tym jakość treści, szybkość ładowania i dostępność. Generowanie map witryn i robots.txt to jednak ważny krok w kierunku zwiększenia widoczności twojej aplikacji Next.js w wyszukiwarkach internetowych.

Ir a CodeWorlds