Урок 47 из 49 · Месяц 6. TypeScript и выход на работу
Основы SEO-оптимизации
Содержание урока
Можно сделать отличный сайт, но если его не найти в поиске, о нём никто не узнает. SEO — это набор правил, которые помогают поисковикам понять ваш сайт и показать его людям выше в результатах. В этом уроке разберём, как работают поисковые системы, какие мета-теги и семантику нужно добавить, почему у одностраничных React-приложений проблемы с SEO и как их решают SSR и Next.js, что такое Core Web Vitals, robots.txt и sitemap.
Что такое SEO и как работает поиск
SEO (Search Engine Optimization) — «оптимизация для поисковых систем». Её задача — чтобы Google, Яндекс и другие поисковики правильно поняли страницу и показали её по нужным запросам.
Поисковик работает в три шага:
- Сканирование (crawling). Программа-робот (краулер) ходит по ссылкам и скачивает страницы.
- Индексация (indexing). Поисковик разбирает текст, заголовки, ссылки и сохраняет страницу в свою базу — индекс.
- Ранжирование (ranking). Когда человек что-то ищет, поисковик выбирает из индекса подходящие страницы и сортирует их.
Аналогия: поисковик — библиотекарь. Сначала он собирает книги (сканирование), потом составляет карточки в каталоге (индексация), а когда читатель спрашивает «что почитать про React?», достаёт самые подходящие (ранжирование). Наша задача — чтобы книгу было легко найти и на обложке было понятно, о чём она.
Мета-теги
Мета-теги лежат в <head> и пользователь их не видит, а вот поисковики и соцсети читают внимательно.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Беспроводные наушники — купить в Бишкеке | Shop</title>
<meta
name="description"
content="Беспроводные наушники с шумоподавлением. Доставка по городу за 1 день, гарантия 12 месяцев."
/>
<link rel="canonical" href="https://shop.example.com/catalog/headphones" />
<meta property="og:title" content="Беспроводные наушники | Shop" />
<meta property="og:description" content="Шумоподавление, 30 часов работы." />
<meta property="og:image" content="https://shop.example.com/og/headphones.jpg" />
<meta property="og:url" content="https://shop.example.com/catalog/headphones" />
<meta property="og:type" content="website" />
</head>
<body>
...
</body>
</html>
Разбор по строкам:
lang="ru"— язык страницы; помогает поисковику и экранным дикторам;viewport— обязательный тег для мобильных; без него сайт считается неадаптивным;<title>— самый важный тег: заголовок вкладки и синяя ссылка в выдаче. Около 50–60 символов, главное — в начале, уникальный для каждой страницы;description— описание под ссылкой в выдаче (поисковик может заменить его своим). Около 140–160 символов, живым языком;canonical— «главный» адрес страницы. Нужен, если одна страница открывается по нескольким адресам (?sort=price,?utm=...), чтобы поисковик не считал их дублями;og:*— протокол Open Graph: так выглядит превью ссылки в Telegram, WhatsApp, Facebook.
Ещё один полезный тег — запрет индексации для служебных страниц (личный кабинет, корзина, результаты поиска по сайту):
<meta name="robots" content="noindex, nofollow" />
Семантическая вёрстка
Поисковый робот не видит дизайн — он читает HTML. Семантические теги (урок HTML5: основные теги) объясняют ему структуру страницы.
<body>
<header>
<a href="/">Shop</a>
<nav>
<a href="/catalog">Каталог</a>
<a href="/delivery">Доставка</a>
</nav>
</header>
<main>
<article>
<h1>Беспроводные наушники X200</h1>
<img src="/img/x200.webp" alt="Чёрные беспроводные наушники X200 в кейсе" width="600" height="600" />
<section>
<h2>Характеристики</h2>
<ul>
<li>Шумоподавление</li>
<li>30 часов работы</li>
</ul>
</section>
<section>
<h2>Отзывы</h2>
...
</section>
</article>
</main>
<footer>© 2026 Shop</footer>
</body>
Правила:
- один
<h1>на страницу — главная тема; дальше<h2>,<h3>по порядку, без пропусков уровней; <header>,<nav>,<main>,<article>,<section>,<footer>вместо безликих<div>;- у каждой картинки осмысленный
alt— поисковик не видит изображения, он читает их описание; - ссылки — это
<a href>, а не<div onClick>: робот переходит только по настоящим ссылкам; - текст ссылки говорит, куда она ведёт: «Условия доставки», а не «нажмите здесь».
Бонус: семантика одновременно улучшает доступность — экранные дикторы для незрячих людей читают ту же структуру.
SPA и SEO
В чём проблема
React-приложение на Vite — это SPA (Single Page Application, урок SPA на React Router). Посмотрите, какой HTML приходит с сервера (Ctrl+U — «Просмотр кода страницы»):
<body>
<div id="root"></div>
<script type="module" src="/assets/index-a1b2c3.js"></script>
</body>
Внутри пусто. Весь контент появляется только после того, как браузер скачает и выполнит JavaScript. Это называется CSR (Client-Side Rendering — отрисовка на стороне клиента).
Что из этого следует:
- Google умеет выполнять JavaScript, но делает это позже и не всегда полностью — индексация медленнее и менее надёжна;
- многие другие роботы (превью в мессенджерах, часть поисковиков) JavaScript не выполняют и видят пустую страницу;
- у всех страниц одинаковый
<title>изindex.html, если не менять его вручную; - пользователь дольше смотрит на белый экран — это ухудшает метрики скорости.
Мета-теги в React 19
Начиная с React 19, теги <title>, <meta> и <link> можно писать прямо внутри компонента — React сам перенесёт их в <head>:
type Product = { id: number; title: string; description: string };
export function ProductPage({ product }: { product: Product }) {
return (
<article>
<title>{`${product.title} — купить | Shop`}</title>
<meta name="description" content={product.description} />
<link rel="canonical" href={`https://shop.example.com/products/${product.id}`} />
<h1>{product.title}</h1>
<p>{product.description}</p>
</article>
);
}
Обратите внимание: <title> получает одну строку через шаблон `...`, а не смесь текста и выражений — так React корректно обновит заголовок.
Это решает проблему одинаковых заголовков во вкладке, но не решает главную: на сервере HTML по-прежнему пустой, теги появляются только после выполнения JS.
SSR, SSG и Next.js
Решение — отдавать с сервера уже готовый HTML. Есть несколько способов:
| Подход | Когда создаётся HTML | Подходит для |
|---|---|---|
| CSR | В браузере, после загрузки JS | Личные кабинеты, админки — где SEO не нужно |
| SSR (Server-Side Rendering) | На сервере при каждом запросе | Каталоги, новости — данные часто меняются |
| SSG (Static Site Generation) | Один раз при сборке проекта | Лендинги, блоги, документация |
| ISR (Incremental Static Regeneration) | При сборке, и обновляется по таймеру | Каталог, который меняется раз в час |
Аналогия: CSR — вам привозят набор «собери сам» (мебель из коробки), SSR — привозят собранный шкаф под заказ, SSG — шкаф со склада, собранный заранее.
Самый популярный фреймворк для этого в мире React — Next.js. В нём страница — это React-компонент, который по умолчанию отрисовывается на сервере, а мета-теги задаются специальным экспортом. Пример в стиле App Router:
// app/products/[id]/page.tsx
import type { Metadata } from "next";
type Props = { params: Promise<{ id: string }> };
async function getProduct(id: string) {
const res = await fetch(`https://api.example.com/products/${id}`);
return res.json() as Promise<{ title: string; description: string }>;
}
export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { id } = await params;
const product = await getProduct(id);
return {
title: `${product.title} | Shop`,
description: product.description,
};
}
export default async function ProductPage({ params }: Props) {
const { id } = await params;
const product = await getProduct(id);
return (
<main>
<h1>{product.title}</h1>
<p>{product.description}</p>
</main>
);
}
Что здесь важно на уровне обзора:
- компонент страницы —
async, он получает данные на сервере, и браузер сразу получает HTML с заголовком и текстом; generateMetadataформирует<title>иdescriptionдля каждой страницы отдельно;- папка
[id]— динамический сегмент адреса, как:idв React Router.
Подробно Next.js изучают отдельно — документация на nextjs.org/docs. Сейчас достаточно понимать, зачем он нужен и чем SSR отличается от SPA.
Core Web Vitals: скорость и удобство
Поисковики учитывают, насколько удобно пользоваться страницей. Google измеряет это тремя метриками — Core Web Vitals:
| Метрика | Что измеряет | Хорошо |
|---|---|---|
| LCP (Largest Contentful Paint) | Когда появился самый крупный элемент (главная картинка, заголовок) | до 2,5 с |
| INP (Interaction to Next Paint) | Как быстро страница реагирует на клики и ввод | до 200 мс |
| CLS (Cumulative Layout Shift) | Насколько «прыгает» вёрстка во время загрузки | до 0,1 |
Как улучшать:
- LCP: сжимайте картинки (WebP/AVIF), не грузите огромные баннеры, главной картинке добавьте
fetchpriority="high"; - INP: не делайте тяжёлых вычислений при каждом клике, разбивайте большие компоненты, используйте
useMemoпо делу (урок useRef, useMemo и useCallback); - CLS: указывайте
widthиheightу картинок, резервируйте место под баннеры и шрифты.
<!-- главная картинка: грузим сразу и с высоким приоритетом -->
<img src="/hero.webp" alt="Новая коллекция" width="1200" height="600" fetchpriority="high" />
<!-- картинки ниже первого экрана: грузим, только когда пользователь до них долистает -->
<img src="/card-1.webp" alt="Кроссовки" width="400" height="400" loading="lazy" />
Проверить метрики можно во вкладке Lighthouse в Chrome DevTools: «Analyze page load» — и через пару секунд получите оценки Performance, Accessibility, Best Practices и SEO с советами, что исправить.
robots.txt и sitemap.xml
robots.txt
robots.txt — текстовый файл в корне сайта (https://site.com/robots.txt) с правилами для роботов: куда можно, куда нельзя.
User-agent: *
Disallow: /admin/
Disallow: /cart
Disallow: /profile
Sitemap: https://shop.example.com/sitemap.xml
User-agent: *— правила для всех роботов;Disallow— разделы, которые не нужно сканировать;Sitemap— где лежит карта сайта.
sitemap.xml
Карта сайта — список всех страниц, которые вы хотите видеть в поиске:
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://shop.example.com/</loc>
<lastmod>2026-09-01</lastmod>
</url>
<url>
<loc>https://shop.example.com/catalog</loc>
<lastmod>2026-09-20</lastmod>
</url>
<url>
<loc>https://shop.example.com/catalog/headphones</loc>
<lastmod>2026-09-25</lastmod>
</url>
</urlset>
В проекте на Vite оба файла кладут в папку public/ — при сборке они окажутся в корне сайта. В больших проектах sitemap генерируют автоматически (в Next.js для этого есть файлы app/sitemap.ts и app/robots.ts).
После публикации сайт добавляют в Google Search Console и Яндекс Вебмастер — там видно, какие страницы проиндексированы и какие ошибки нашёл робот.
Типичные ошибки
- Одинаковые
titleиdescriptionна всех страницах. - Несколько
<h1>или заголовки ради крупного шрифта, а не структуры. - Картинки без
altи безwidth/height— минус к SEO и прыгающая вёрстка. - Навигация на
<div onClick>вместо<a href>— робот не найдёт страницы. - Ожидание, что SPA на Vite будет хорошо индексироваться «само».
- Случайно оставленный
noindexилиDisallow: /после тестового сервера — сайт пропадает из поиска.
Практика
- Мета-теги. Добавьте в
index.htmlсвоего проектаlang,title,description, Open Graph. Ожидаемый результат: ссылка, отправленная в мессенджер после деплоя, показывает превью с картинкой и описанием. - Семантика. Переделайте одну страницу проекта: один
<h1>,<main>,<nav>,altу всех картинок. Ожидаемый результат: в Lighthouse оценка SEO и Accessibility выросла. - Заголовки в SPA. Используя теги
<title>и<meta>из React 19, сделайте уникальный заголовок вкладки на каждой странице вашего React Router-приложения. Ожидаемый результат: при переходах меняется название вкладки. - robots и sitemap. Создайте
public/robots.txtиpublic/sitemap.xmlдля своего проекта. Ожидаемый результат: послеnpm run buildфайлы лежат вdist/и открываются по/robots.txtи/sitemap.xml. - Аудит скорости. Запустите Lighthouse, выпишите LCP и CLS, исправьте две проблемы (сжать картинки, добавить размеры,
loading="lazy"). Ожидаемый результат: оценка Performance выросла, CLS не больше 0,1.
Итоги
- Поисковик сканирует, индексирует и ранжирует страницы; фронтендер отвечает за техническое SEO.
- Главные теги:
title,description,viewport,canonical, Open Graph; служебные страницы закрываемnoindex. - Семантика: один
<h1>, иерархия заголовков,<main>/<nav>/<article>,altи настоящие ссылки. - SPA отдаёт пустой HTML — для публичных страниц используют SSR/SSG, например Next.js.
- Core Web Vitals: LCP до 2,5 с, INP до 200 мс, CLS до 0,1; проверяем в Lighthouse.
robots.txtподсказывает роботам, куда не ходить,sitemap.xml— какие страницы есть; в Vite оба файла лежат вpublic/.