Привет .
Меня зовут Михаил, более 10 лет разрабатываю интернет-проекты: от сайтов до систем автоматизации.

Привет

Карта сайта важна для SEO, ведь она даёт поисковым системам дополнительное представление о сайте.

И в этом небольшом уроке я покажу, как создать карту сайта. Карта сайта представляет собой XML-документ, который традиционно доступен из корня сайта. Допустим, https://quasi-art.ru/sitemap.xml.

Требования

Невозможно создать универсальный код для создания карты сайта абсолютно для любого проекта. Всегда нужно учитывать структуру сайта, количество страниц и как их следует индексировать (частота индексирования, приоритет и пр). Но если понять основы, то можно создать карту сайта для любого проекта.

Так что в этом уроке я ориентируюсь на один свой проект. Я использую статическую генерацию, вложенность страниц минимальная.

Шаг 1

Для начала нужно создать файл sitemap.xml.js (или sitemap.xml.ts, если используете TypeScript) внутри каталога pages.

Таким образом, после сборки проекта становится доступной страница https://domain.ru/sitemap.xml.

Теперь поместим в созданный файл следующий код:

const Sitemap = () => {}

export const getServerSideProps = async ({ res }) => {
  res.setHeader('Content-Type', 'text/xml')
  res.write(`
    <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
      <url>
        <loc>https://domain.ru/works/3</loc>
        <lastmod>2022-02-20T11:39:43.436Z</lastmod>
        <changefreq>monthly</changefreq>
        <priority>1.0</priority>
      </url>
      <url>
        <loc>https://domain.ru/works/10</loc>
        <lastmod>2022-02-20T11:39:43.436Z</lastmod>
        <changefreq>monthly</changefreq>
        <priority>1.0</priority>
      </url>
      <url>
    </urlset>
  `)
  res.end()

  return {
    props: {},
  }
}

export default Sitemap

Что здесь происходит:

  • Объявлен компонент страницы — Sitemap.
  • Объявлен метод getServerSideProps.

Метод getServerSideProps запускается для пре-рендера страницы при каждом запросе. В нём и будем описывать всю логику того, какие страницы и каким образом попадут на карту сайта.

Сейчас в этом методе карта сайта содержит не реальные данные, а хардкод.

Шаг 2

Настало время усложнить код.

По какому принципу всё будет работать: во время запроса страницы будет произведён сбор информации обо всех страницах (конкретно у меня — в массив объектов), которые нужно добавить в карту сайта. Затем на основании собранной информации будет собрана вёрстка. И эту вёрстку мы отрисуем в браузере.

import { fetchWorksData } from '@root/lib/works'

const Sitemap = () => {}

const getSitemapWrapperTemplate = (content: string) => {
    return `<?xml version="1.0" encoding="UTF-8"?>
      <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
        ${content}
      </urlset>
  `
}

type Page = {
    url: string;
    changefreq: 'never' | 'yearly' | 'monthly' | 'weekly' | 'daily' | 'hourly' | 'always';
    priority: '1.0';
}

export const getServerSideProps = async ({ res }) => {
    const baseUrl = {
        development: 'http://localhost:3000',
        production: 'https://domain.ru',
    }[process.env.NODE_ENV]
    const pagesInfo: Page[] = []

    const works = await fetchWorksData()
    for (let i = 0; i < works.length; i++) {
        pagesInfo.push({
            url: `${baseUrl}/works/${works[i].id}`,
            priority: '1.0',
            changefreq: 'monthly',
        })
    }

    const rows = pagesInfo
        .map((pageInfo) => `
            <url>
                <loc>${pageInfo.url}</loc>
                <lastmod>${new Date().toISOString()}</lastmod>
                <changefreq>${pageInfo.changefreq}</changefreq>
                <priority>${pageInfo.priority}</priority>
            </url>
        `)
        .join('')

    res.setHeader('Content-Type', 'text/xml')
    res.write(getSitemapWrapperTemplate(rows))
    res.end()
  
    return {
      props: {},
    }
  }

export default Sitemap

  1. В функцию getSitemapWrapperTemplate я вынес шаблон XML-документа. Цель: немного разгрузить функцию getServerSideProps.
  2. В переменной baseUrl содержится домен сайта, так как URI страниц в карте сайта должны быть абсолютными.
  3. Затем я объявляю массив pagesInfo.
  4. С помощью собственного метода fetchWorksData по API собираю информацию обо всех сущностях, которые на сайте имеют собственную страницу.
  5. Наполняю массив pagesInfo информацией о страницах.
  6. На основании этого массива формирую содержимое карты сайта: последовательно идущие теги url.
  7. Устанавливаю корректный тип содержимого для XML и записываю в объект ответа собранную в виде строки карту сайта.

Вывод

Я показал пример довольно частного случая, потому что всё зависит от многих параметров.

Можно в разный момент генерировать карту сайта (при сборке или при запросе), можно по-разному собирать информацию о страницах (из API или файловой системы) и так далее.

Но как отправная точка — сойдёт.