Главная / Статьи

Технический SEO в Next.js App Router: метаданные, карты сайта и JSON-LD

Узнайте, как вспомогательные инструменты для общих метаданных, стандартная структура корневого элемента, файл robots.ts, динамическая карта сайта, корректно сформированные данные JSON-LD и аудит страниц создают надежную основу для SEO в приложении Next.js.

Издатель: REACTAPP.TOP4 мин чтения1024 слов

Источники: How I Got a Next.js Project to 100% SEO on Lighthouse

Приложение Next.js может выглядеть готовым, но по-прежнему оставаться сложным для индексации поисковыми системами: у страниц отсутствуют канонические URL, правила работы роботов не определены, а новый контент никогда не попадает в схему сайта. В этом руководстве рассматривается сайт с API-данными для тестов, у которого на первой проверке SEO-инструмента Lighthouse балл составлял низкий уровень, и показано, как довести его до 100 баллов с помощью семи изменений, внесенных с использованием встроенных API метаданных App Router.

Создание метаданных страниц с помощью одного вспомогательного инструмента

Ручное вводение метаданных на каждой странице приводит к постепенным ошибкам — например, отсутствию канонического URL здесь или устаревшему заголовку Open Graph там. Небольшой фабричный инструмент решает эту проблему: каждая страница передает только свой заголовок, описание, путь и необязательный флаг noIndex, после чего вспомогательный инструмент преобразует их в поля канонического URL, настроек для роботов и информации Open Graph:

export function createPageMetadata({
  title,
  description,
  path,
  noIndex = false,
}: PageMetadata) {
  return {
    title,
    description,
    alternates: {
      canonical: path,
    },
    robots: noIndex ? "noindex, nofollow" : "index, follow",
    openGraph: {
      title,
      description,
      url: path,
      type: "website",
    },
  };
}

Индексация отключается по желанию: один флаг приводит к тому, что страница становится noindex, nofollow. Поскольку path является относительным, вспомогательный инструмент опирается на базовый URL, заданный в корневом макете.

Установите общие настройки для всего сайта в корневом макете

Всё, что используется на всем сайте, должно находиться в экспорте metadata из файла layout.tsx:

  • metadataBase
  • шаблон заголовка
  • стандартное описание
  • настройки Open Graph
  • параметры карточки Twitter
  • стандартные настройки robots
  • атрибут lang в элементе <html>

Упрощённая версия этого экспорта выглядит так:

export const metadata: Metadata = {
  metadataBase: new URL("https://mockdata.ir"),
  title: {
    default: "MockData",
    template: "%s | MockData",
  },
  description: "...",
};

С использованием шаблона %s | MockData страница с названием «Users API» отображается как «Users API | MockData», в то время как страницы без названия используют значение default. Поле metadataBase отвечает за преобразование относительных значений canonical и URL для Open Graph, заданных в хелпере, в абсолютные URL-адреса. Обратите внимание, что lang не является полем метаданных; его следует установить в теге <html>, который отображается в лейауте.

Определение правил парсера с помощью robots.ts

Вместо того чтобы оставить правила парсера неопределенными, генерируйте файл robots.txt из файла app/robots.ts, который возвращает объект типа MetadataRoute.Robots.

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: "*",
      allow: "/",
    },
    sitemap: "https://mockdata.ir/sitemap.xml",
  };
}

Этот файл преднамеренно минимален: все пользовательские агенты могут парсить любой контент, причем указывается местоположение сайт-карты.

Генерация сайт-карты на основе ваших данных

При наличии страниц с ресурсами для пользователей, публикаций, продуктов и многого другого ручно ведомый XML-сайт-карта не способен масштабироваться. По умолчанию экспортируемый файл sitemap.ts может быть async, что позволяет ему запрашивать тот же источник, что и используют страницы:

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const resources = await getPublicResources();

return [
    {
      url: "https://mockdata.ir",
      lastModified: new Date(),
    },
    ...resources.map((resource) => ({
      url: `https://mockdata.ir/${resource.slug}`,
      lastModified: resource.updatedAt,
    })),
  ];
}

Каждый ресурс соответствует URL, в котором updatedAt заменяется на lastModified, благодаря чему новые публичные ресурсы автоматически добавляются в сайт-карту. Одно усовершенствование: использование new Date() для главной страницы приводит к отметке об изменениях при каждой генерации; более точным будет использование реального временного метки контента.

Добавляйте структурированные данные только там, где это действительно необходимо

JSON-LD с лексиконом Schema.org информирует поисковые системы о том, что представляет собой страница. Само приложение описывается как SoftwareApplication, а используемые типы — это:

  • WebSite
  • Organization
  • SoftwareApplication
  • BreadcrumbList
  • Старайтесь добиваться точности, а не объема: маркировка должна описывать содержимое, которое действительно находится на странице. Вымышленные отзывы, оценки или другие фиктивные характеристики вводят в заблуждение и могут нарушать руководящие принципы поисковых систем.

    Сохраняйте согласованность «хлебных крошек» между интерфейсом и схемой

    Вложенные страницы документации показывают видимый путь, например Главная → Документация → API пользователей, и та же иерархия передается в виде структурированных данных BreadcrumbList. Видимый путь и маркировка всегда должны описывать одну и ту же структуру.

    Вручную проверяйте каждую индексируемую страницу

    Наконец, индивидуально просмотрите каждую публичную страницу:

    • Есть ли на ней ровно один четко определенный H1?
    • Описывает ли заголовок именно эту конкретную страницу?
    • Соответствует ли описание реальному содержимому?
    • Есть ли на ней полезные внутренние ссылки туда и обратно?
  • Должна ли эта страница вообще попадать в индекс?
  • Открываются ли роботам-поисковикам какие-либо пустые или малозначимые страницы?
  • Не каждый путь должен присутствовать в результатах поиска; часто правильным решением является использование атрибута noindex. Что касается структуры заголовков, ознакомьтесь с этим руководством по семантическому HTML для работы с маркировкой.

    Что означает и чего не означает идеальный балл SEO в Lighthouse

    После этих исправлений Lighthouse показал балл SEO 100. Это число проверяет такие технические аспекты, как заголовки, описания и возможность индексации; оно ничего не говорит об ранжировании. Ранжирование зависит от качества контента, намерений поисковиков, авторитетности сайта, обратных ссылок, конкуренции, производительности и многих других факторов.

    Настоящая ценность заключается в прочной технической основе. Проведение аудита перед публикацией любого приложения Next.js стоит недорого и помогает выявить множество незначительных ошибок.

    Основные выводы

    • Централизуйте метаданные каждой страницы в специальном помощнике и установите общие параметры по умолчанию, включая metadataBase, в корневом макете.
    • Используйте robots.ts и асинхронный файл sitemap.ts, чтобы правила поисковых роботов и URL оставались синхронизированными с вашими данными.
    • Добавляйте только структурированные данные, которые точно описывают страницу, и сохраняйте структуру навигационных пунктов одинаковой как в интерфейсе, так и в схеме.
    • Рассматривайте параметр noindex как законный способ скрыть страницы, которые не должны появляться в результатах поиска.
    • Оценку Lighthouse 100 следует воспринимать как «технически корректную», а не как гарантию высокого рейтинга.