React performance і SEO: що покращує Core Web Vitals
Покращуйте React SEO та Core Web Vitals через rendering, JavaScript delivery, images, caching, hydration і interaction bottlenecks.
25 лютого 2026 р.

React докорінно змінив спосіб створення інтерактивних веб-застосунків, але при цьому поставив унікальне завдання: зробити React-застосунки SEO-friendly, зберігаючи при цьому продуктивність і зручність користування, які роблять цей фреймворк таким просунутим. У OSTER Tech ми оптимізували десятки React-застосунків для пошукових систем і зрозуміли, що проблема не в самому React, а в тому, як React зазвичай реалізується за замовчуванням.
Хороша новина полягає в тому, що проблеми React з продуктивністю для SEO цілком можна вирішити. За допомогою правильних технік ви можете створювати React-застосунки, які добре ранжуються в Google, швидко завантажуються і забезпечують винятковий користувацький досвід. Цей посібник охоплює вісім перевірених технік, які ми використовуємо для оптимізації React-застосунків як для пошукових систем, так і для реальних користувачів.
Чому React-застосунки мають проблеми з SEO (і як це виправити)
Стандартний підхід React — рендеринг на стороні клієнта — створює фундаментальну проблему для оптимізації пошукових систем. Коли ви відправляєте React-застосунок до браузера користувача, браузер отримує мінімальний HTML-код. Він завантажує пакет JavaScript, парситьйого, виконує, а потім рендерить фактичний контент. Цей процес займає час, і протягом цього часу пошукові системи можуть не бачити ваш контент.
Ось що зазвичай зустрічає пошукова система з клієнтським застосунком React:
<!DOCTYPE html>
<html>
<head>
<title>My React App</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>Ось і все. Пошукова система бачить порожню сторінку зі тегом скрипту. Вона може виконати JavaScript (Google це робить, але багато інших пошукових систем цього не роблять), але процес повільний і ненадійний. Тим часом ваш фактичний контент — текст, зображення та метадані, які повинні бути проіндексовані — невидимі для первинного кроулінгу.
Проблема Core Web Vitals
Окрім можливості кроулінгу, React-застосунки стикаються з другою проблемою: Core Web Vitals. Google підтвердив, що продуктивність є фактором ранжування в його алгоритмі пошуку. Три найважливіші показники:
- Largest Contentful Paint (LCP): скільки часу потрібно, щоб найбільший елемент на сторінці став видимим. Ціль: менше 2,5 секунди.
- Interaction to Next Paint (INP): швидкість реакції сторінки на дію користувача. Ціль: менше 200 мілісекунд.
- Cumulative Layout Shift (CLS): наскільки змінюється макет сторінки під час завантаження контенту. Ціль: менше 0,1.
Неоптимізовані React-застосунки зазвичай не відповідають цим показникам, оскільки вони містять великі пакети JavaScript, які потребують часу на парсинг і виконання. Ми бачили React-застосунки з часом LCP, що перевищував 6 секунд — майже в 2,5 рази більше рекомендованого Google порогу.
Рішення
Вісім технік, описаних у цьому гайді, повнітю вирішують ці проблеми. Після прочитання цієї статті ви зрозумієте, як реалізувати серверний рендеринг, оптимізувати розмір пакета, динамічно керувати метатегами та контролювати показники продуктивності, що мають значення для SEO. Ми не описуємо теоретичні концепції — це практичні техніки, які ми використали для поліпшення клієнтських застосунків від «SEO провалу» до «світиться на першій сторінці».
1. Впровадьте серверний рендеринг (SSR) або статичне генерування
Серверний рендеринг — це найефективніша техніка для React SEO. Замість того, щоб надсилати порожній HTML-файл і дозволяти браузеру рендерити все, SSR рендерить ваші React-компоненти на сервері та надсилає повністю сформований HTML-код до браузера та пошукових систем.
Як працює SSR
Коли користувач (або пошукова система) надсилає запит, ваш сервер:
- Отримує запит.
- Рендерить ваші React-компоненти в HTML-рядок.
- Відправляє цей HTML-рядок до браузера.
- Браузер негайно відображає вміст (навіть до завантаження JavaScript).
- JavaScript потім «оживляє» сторінку, додаючи інтерактивність.
Пошукова система бачить повністю відрендерений HTML при першому запиті. Не потрібно чекати виконання JavaScript. Жодного ризику, що контент не буде рендеритися.
Next.js: практичний вибір
Next.js спрощує впровадження SSR. Ось як виглядає базова сторінка SSR:
// pages/products/[id].js
export async function getServerSideProps(context) {
const { id } = context.params;
const product = await fetchProductData(id);
return {
props: {
product,
},
revalidate: 60, // Revalidate every 60 seconds
};
}
export default function ProductPage({ product }) {
return (
<div>
<h1>{product.name}</h1>
<p>{product.description}</p>
<p>${product.price}</p>
</div>
);
}ФункціяgetServerSidePropsвиконується на сервері перед відправкою сторінки в браузер. Дані про продукт фетчаться, компонент рендериться, і браузер отримує вже готовий HTML.
Статичне генерування сайту (SSG): ще краще для SEO
Якщо ваш контент не змінюється часто, статичне генерування сайту (Static Site Generation,SSG)є кращим за SSR. SSG робить pre-render сторінок під час build time, тому кожен запит отримує ідентичний HTML без обробки сервером.
// pages/blog/[slug].js
export async function getStaticProps(context) {
const { slug } = context.params;
const post = await fetchBlogPost(slug);
return {
props: {
post,
},
revalidate: 3600, // Revalidate every hour
};
}
export async function getStaticPaths() {
const posts = await fetchAllBlogPosts();
const paths = posts.map(post => ({
params: { slug: post.slug }
}));
return {
paths,
fallback: 'blocking',
};
}
export default function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<p>{post.content}</p>
</article>
);
}Сторінки SSG обслуговуються з CDN, що забезпечує швидше завантаження та кращі показники SEO. Ми скоротили час завантаження найбільшого контенту клієнта з 4,2 секунди до 1,8 секунди, перейшовши від клієнтського рендерингу до SSG з Next.js.
Remix: альтернативний підхід
Хоча Next.js домінує, Remix пропонує інше досконале рішення SSR з іншою філософією. Remix наголошує на фундаментальних принципах веб-розробки та надає вбудовану підтримку progressive enhancement, що означає, що ваш сайт працюватиме навіть у разі, якщо JavaScript не завантажиться.
Коли вибирати SSR, SSG чи клієнтський рендеринг
- Використовуйте SSGдля контенту, який рідко змінюється (публікації в блогах, сторінки продуктів, маркетингові сторінки)
- Використовуйте SSRдля динамічного контенту, який змінюється за кожним запитом (профілі користувачів, персоналізовані рекомендації)
- Використовуйте клієнтський рендерингтільки для дашбордів або real-time застосунків, де SEO не є пріоритетом
Переваги продуктивності
Різниця є значною. З клієнтським рендерингом користувач може бачити порожній екран протягом 3-5 секунд. З SSR або SSG він бачить контент за 1-2 секунди. Пошукові системи бачать повний, індексований контент одразу.
2. Оптимізуйте Core Web Vitals за допомогою Code Splitting та Lazy Loading
Навіть із SSR застосунки React можуть не відповідати вимогам Core Web Vitals, якщо вони містять надмірну кількість JavaScript. Code splitting та lazy завантаження є важливими техніками для зменшення початкового бандла JavaScript та покращення продуктивності завантаження.
Розділення коду: розбиття вашого пакету
Сучасні бандлери, такі як Webpack (використовується Create React App і Next.js), підтримують code splitting, яке розбиває вашу програму на менші частини. Замість одного пакету розміром 500 КБ, у вас може бути:
main.js(150 КБ) - Основний код програмиproducts.js(120 КБ) — код сторінки продуктуcheckout.js(100 КБ) — код процесу оформлення замовленняadmin.js(130 КБ) — код адміністративної панелі
Браузер завантажує тільки ті частини, які йому потрібні. Користувач, який відвідує головну сторінку, не завантажує код адміністративної панелі.
React.lazy() і Suspense
Вбудована функція ReactReact.lazy()дозволяє розділяти код на рівні компонентів з мінімальними налаштуваннями:
import React, { Suspense, lazy } from 'react';
const ProductDetails = lazy(() => import('./ProductDetails'));
const ReviewSection = lazy(() => import('./ReviewSection'));
export default function ProductPage() {
return (
<div>
<h1>Product</h1>
<Suspense fallback={<div>Loading product details...</div>}>
<ProductDetails />
</Suspense>
<Suspense fallback={<div>Loading reviews...</div>}>
<ReviewSection />
</Suspense>
</div>
);
}Коли сторінка завантажується, компонентиProductDetailsтаReviewSectionне включені до початкового пакету. Вони завантажуються асинхронно за потреби, що зменшує обсяг початкового JavaScript, який браузер повинен проаналізувати та виконати.
Визначення важких компонентів
Не всі компоненти потребують lazy завантаження. Зосередьтеся на:
- Великих модалках або діалогових вікнах, які не видно під час завантаження сторінки
- Бібліотеках діаграм (Chart.js, D3.js, Recharts)
- Редакторах багатоформатного тексту (Slate, Draft.js)
- Компонентах карт (Mapbox, Google Maps)
- важких конструкторах форм
Ми проаналізували React-застосунок клієнта і виявили, що модалка, яке містила складну бібліотеку діаграм (180 КБ), завантажувалася на кожній сторінці, хоча користувачі рідко їїї відкривали. Завдяки lazy завантаження ми зменшили початковий пакет на 35%.
Lazy Loading для зображень
Зображення часто становлять найбільшу частину завантажень сторінки. Нативне Lazy Loading тепер добре підтримується:
export default function ProductGallery({ images }) {
return (
<div>
{images.map(image => (
<img
key={image.id}
src={image.url}
alt={image.alt}
loading="lazy"
/>
))}
</div>
);
}Для старих браузерів або для більшого контролю використовуйте бібліотеку, таку якreact-lazyload:
import LazyLoad from 'react-lazyload';
export default function ProductGallery({ images }) {
return (
<div>
{images.map(image => (
<LazyLoad key={image.id} height={300} offset={100}>
<img src={image.url} alt={image.alt} />
</LazyLoad>
))}
</div>
);
}Вимірювання покоращень
Використовуйте Lighthouse, щоб перевірити ефективність оптимізації:
- Відкрийте Chrome DevTools (F12).
- Перейдіть на вкладку Lighthouse.
- Виберіть «Performance» (Продуктивність) і запустіть аудит.
- Перевірте показник «Largest Contentful Paint» (Найбільший обсяг завантаженого контенту).
Ми побачили поліпшення з 5,2 секунди до 2,1 секунди завдяки стратегічному code splitting та lazy завантаження. Це різниця між рейтингом на 3-й сторінці та 1-й сторінці.
3. Опануйте метатеги та динамічний рендеринг для SEO
Пошукові системи покладаються на метатеги, щоб зрозуміти вміст вашої сторінки. У клієнтських React-застосунках метатеги зазвичай є статичними — кожна сторінка має однаковий заголовок та опис. Це є критичною проблемою для SEO.
Проблема зі статичними метатегами
З клієнтським рендерингом вашindex.htmlможе виглядати так:
<!DOCTYPE html>
<html>
<head>
<title>My React App</title>
<meta name="description" content="Welcome to my React app">
</head>
<body>
<div id="root"></div>
</body>
</html>Кожна сторінка вашого сайту має однаковий заголовок і опис, навіть якщо ви відображаєте різний контент залежно від URL. Пошукові системи не бачать різниці між вашою домашньою сторінкою, сторінками продуктів і публікаціями в блозі. Ваш click-through rate страждає, оскільки всі результати пошуку виглядають однаково.
Рішення 1: React Helmet
React Helmet динамічно відображає метатеги на основі вмісту сторінки:
import { Helmet } from 'react-helmet-async';
export default function ProductPage({ product }) {
return (
<>
<Helmet>
<title>{product.name} | My Store</title>
<meta name="description" content={product.shortDescription} />
<meta name="keywords" content={product.keywords} />
<link rel="canonical" href={`https://mystore.com/products/${product.id}`} />
</Helmet>
<h1>{product.name}</h1>
<p>{product.description}</p>
</>
);
}React Helmet оновлює заголовок документа щоразу, коли компонент рендериться. Кожна сторінка продукту отримує унікальні метатеги на основі даних про продукт.
Рішення 2: Вбудоване управління метатегами Next.js
Якщо ви використовуєте Next.js, компонентnext/headдає подібний функціонал, але з кращою продуктивністю:
import Head from 'next/head';
export default function ProductPage({ product }) {
return (
<>
<Head>
<title>{product.name} | My Store</title>
<meta name="description" content={product.shortDescription} />
<meta name="keywords" content={product.keywords} />
<link rel="canonical" href={`https://mystore.com/products/${product.id}`} />
<meta property="og:title" content={product.name} />
<meta property="og:description" content={product.shortDescription} />
<meta property="og:image" content={product.image} />
</Head>
<h1>{product.name}</h1>
<p>{product.description}</p>
</>
);
}Додавання структурованих даних для розширених сніпетів
Структуровані дані (JSON-LD) допомагають пошуковим системам розуміти ваш контент і можуть призвести до появи розширених сніпетів у результатах пошуку:
import Head from 'next/head';
export default function ProductPage({ product }) {
const structuredData = {
"@context": "https://schema.org/",
"@type": "Product",
"name": product.name,
"description": product.description,
"image": product.image,
"offers": {
"@type": "Offer",
"price": product.price,
"priceCurrency": "USD",
"availability": "https://schema.org/InStock"
},
"aggregateRating": {
"@type": "AggregateRating",
"ratingValue": product.rating,
"reviewCount": product.reviewCount
}
};
return (
<>
<Head>
<title>{product.name} | My Store</title>
<script type="application/ld+json">
{JSON.stringify(structuredData)}
</script>
</Head>
<h1>{product.name}</h1>
<p>{product.description}</p>
</>
);
}Динамічний рендеринг для пошукових систем
Якщо ви використовуєте клієнтський рендеринг і не можете відразу перейти на SSR, динамічний рендеринг є тимчасовим рішенням. Ідентифікуйте ботів пошукових систем і віддавайте їм попередньо відрендерений HTML, а звичайним користувачам — JavaScript.
Бібліотеки, такі якprerender-spa-plugin, або сервіси, такі як Prerender.io, роблять це автоматично. Однак це додає складності та витрат. Ми рекомендуємо це лише як тимчасовий захід, поки ви плануєте перехід на SSR.
Тестування метатегів
Використовуйте інструмент перевірки URL-адрес Google Search Console, щоб переконатися, що пошукові системи бачать ваші метатеги правильно:
- Перейдіть до Google Search Console.
- Введіть свою URL-адресу в поле пошуку.
- Натисніть «Перевірити URL-адресу».
- Перевірте вкладку «Rendered HTML», щоб побачити те, що бачить Googlebot.
Так ви перевірите, чи правильно рендеряться ваші метатеги для пошукових систем.
4. Мінімізуйте JavaScript і оптимізуйте розмір бандлу
Надмірне використання JavaScript є основним фактором, що знижує продуктивність React-застосунків. Кожен кілобайт JavaScript потрібно завантажувати, парисити та виконувати — ці процеси займають час і витрачають заряд батареї мобільних пристроїв.
Перевірка вашого пакета
Перший крок — зрозуміти, що міститься у вашому бандлі. Використовуйтеwebpack-bundle-analyzer, щоб візуалізувати ваші залежності:
npm install --save-dev webpack-bundle-analyzerУ вашому Next.js config:
// next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
})
module.exports = withBundleAnalyzer({
// your Next.js config
})Потім запустіть:
ANALYZE=true npm run buildЦе створює інтерактивну візуалізацію, яка показує, які пакети займають місце. Ми виявили, що більшість застосунків React мають 3-5 залежностей, які можна замінити на більш легкі альтернативи.
Поширені винуватці та заміни
- moment.js(67 КБ) →date-fns(13 КБ) абоday.js(2 КБ)
- lodash(71 КБ) →lodash-esз tree-shaking (20 КБ) або окремими функціями
- jQuery(87 КБ) → Нативні API DOM або vanilla JavaScript
- axios(13 КБ) →fetch API(нативний)
- prop-types(8 КБ) → TypeScript (якщо ви все одно його використовуєте)
Клієнт мав moment.js, lodash і важку бібліотеку компонентів інтерфейсу користувача, які разом становили 40% його пакета. Замінивши moment на date-fns, використовуючи tree-shaking для lodash і перейшовши на легшу бібліотеку інтерфейсу користувача, ми зменшили розмір бандлу на 180 КБ.
Увімкніть Tree-Shaking
Tree-shaking видаляє невикористаний код під час білду. Переконайтеся, що ваша конфігурація білду підтримує цю функцію:
// webpack.config.js
module.exports = {
mode: 'production', // Essential for tree-shaking
optimization: {
usedExports: true,
sideEffects: false,
},
}У файлі package.json позначте пакети як такі, що не мають побічних ефектів:
{
"name": "my-package",
"sideEffects": false
}Це повідомляє бандлерам, що ваш код не має побічних ефектів і невикористані експортовані елементи можна безпечно видалити.
Продакшн білди
Завжди використовуйте продакшн балди для розгортання. Розробницькі булди містять код для дебагінгу і є в 2-3 рази більшими:
# Wrong - development bundle
npm run build
# Right - production bundle with optimization
npm run build -- --mode productionЦільові розміри бандлів
- Оптимальний: менше 100 КБ у форматі gzip для початкового пакета
- Хороший: менше 200 КБ у форматі gzip
- Прийнятний: менше 300 КБ у форматі gzip
- Поганий: більше 300 КБ у форматі gzip
Більшість застосунків React без оптимізації потрапляють до категорії «Поганий». Ми допомогли клієнтам зменшити розмір з 450 КБ до 180 КБ у форматі gzip, що призвело до прискорення завантаження сторінок на 60%.
5. Впровадьте стратегії прелоадингу та prefetching
Хоча зменшення розміру пакета є надзвичайно важливим, стратегії прелоадингу та попереднього вивантаження гарантують, що користувачі отримають найважливіші ресурси якомога швидше.
Прелоадинг важливих ресурсів
Прелаод вказує браузеру завантажити ресурс заздалегідь, навіть якщо він не потрібен негайно. Використовуйте це для:
- Важливих шрифтів
- Зображень у верхній частині сторінки
- Необхідних таблиць стилів
У HTML head:
<link rel="preload" as="font" href="/fonts/Roboto-Regular.woff2" crossorigin>
<link rel="preload" as="image" href="/hero-image.jpg">
<link rel="preload" as="style" href="/critical-styles.css">Або у Next.js:
import Head from 'next/head';
export default function Page() {
return (
<>
<Head>
<link rel="preload" as="font" href="/fonts/Roboto-Regular.woff2" crossorigin />
</Head>
{/* content */}
</>
);
}Prefetch ресурсів з нижчим пріоритетом
Prefetch вказує браузеру завантажувати ресурс, поки браузер перебуває в режимі очікування. Використовуйте це для:
- Фрагмента JavaScript наступної сторінки
- Зображень нижче лінії згину
- Додаткових таблиць стилів
<link rel="prefetch" href="/products-chunk.js">
<link rel="prefetch" href="/below-fold-image.jpg">Оптимізація зображень Next.js
Компонент Image Next.js автоматично обробляє попереднє завантаження above-the-fold зображень:
import Image from 'next/image';
export default function Hero() {
return (
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority
/>
);
}Пропpriorityвказує Next.js попередньо завантажити зображення, гарантуючи, що воно завантажиться раніше за вміст з нижчим пріоритетом.
Prefetching маршрутів
У Next.js маршрути автоматично попередньо завантажуються, коли вони з’являються у вікні перегляду:
import Link from 'next/link';
export default function HomePage() {
return (
<div>
<h1>Home</h1>
<Link href="/products">
<a>View Products</a>
</Link>
</div>
);
}Користувачі, які натискають на посилання, бачать миттєву навігацію, оскільки сторінка вже була попередньо завантажена.
Моніторинг Preload/Prefetch
Використовуйте Chrome DevTools, щоб перевірити, чи працюють попереднє завантаження та попереднє вивантаження:
- Відкрийте DevTools (F12)
- Перейдіть на вкладку «Мережа»
- Знайдіть ресурси у стовпці «Пріоритет»
- Попередньо завантажені ресурси відображаються як ресурси з «Високим» пріоритетом
- Попередньо завантажені ресурси відображаються як «Низький» пріоритет.
Це гарантує, що ваша стратегія дійсно забезпечує доставку ресурсів тоді, коли ви цього очікуєте.
6. Обробка нескінченного скролу та динамічного контенту для індексації
Нескінченний скрол — це жахливо для SEO. Коли користувачі прокручують сторінку, вміст завантажується динамічно, але URL-адреса ніколи не змінюється. Пошукові системи не можуть виявити пагінацію або вміст, який виходить за межі того, що видно при першому завантаженні сторінки.
Проблема нескінченної прокрутки
Уявіть собі список продуктів, що використовує нескінченну прокрутку. Користувач прокручує і завантажує 20, 40, 60 продуктів. Але URL-адреса залишається/products. Пошукові системи сканують/products, бачать 20 продуктів і рухаються далі. Решта продуктів ніколи не індексуються.
Рішення 1: Традиційна пагінація
Найпростішим рішенням є традиційна пагінація з унікальними URL-адресами:
// pages/products/page/[pageNumber].js
export async function getStaticProps(context) {
const pageNumber = parseInt(context.params.pageNumber);
const pageSize = 20;
const products = await fetchProducts({
skip: (pageNumber - 1) * pageSize,
take: pageSize,
});
return {
props: { products, pageNumber },
};
}
export default function ProductsPage({ products, pageNumber }) {
return (
<div>
<h1>Products</h1>
<div>
{products.map(product => (
<div key={product.id}>{product.name}</div>
))}
</div>
<nav>
{pageNumber > 1 && (
<Link href={`/products/page/${pageNumber - 1}`}>Previous</Link>
)}
<Link href={`/products/page/${pageNumber + 1}`}>Next</Link>
</nav>
</div>
);
}Кожна сторінка має унікальний URL-адресу:/products/page/1,/products/page/2тощо. Пошукові системи сканують кожну сторінку та індексують усі товари.
Рішення 2: нескінченна прокрутка з оновленням URL-адреси
Якщо ви віддаєте перевагу нескінченній прокрутці для зручності користувачів, оновлюйте URL-адресу під час завантаження вмісту:
import { useEffect, useState } from 'react';
import { useRouter } from 'next/router';
export default function ProductsPage() {
const router = useRouter();
const [products, setProducts] = useState([]);
const [page, setPage] = useState(1);
useEffect(() => {
// Load products for current page
fetchProducts(page).then(newProducts => {
setProducts(prev => [...prev, ...newProducts]);
});
}, [page]);
useEffect(() => {
// Update URL when page changes
router.push(`/products?page=${page}`, undefined, { shallow: true });
}, [page]);
const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
setPage(prev => prev + 1);
}
};
useEffect(() => {
window.addEventListener('scroll', handleScroll);
return () => window.removeEventListener('scroll', handleScroll);
}, []);
return (
<div>
{products.map(product => (
<div key={product.id}>{product.name}</div>
))}
</div>
);
}Тепер URL-адреса оновлюється до/products?page=1,/products?page=2, коли користувачі прокручують сторінку. Пошукові системи можуть кроулити кожну сторінку окремо.
Додайте розмітку схеми пагінації
Допоможіть пошуковим системам зрозуміти взаємозв’язки між сторінками за допомогою rel="next" та rel="prev":
import Head from 'next/head';
export default function ProductsPage({ pageNumber, totalPages }) {
return (
<>
<Head>
<title>Products - Page {pageNumber}</title>
{pageNumber > 1 && (
<link rel="prev" href={`/products?page=${pageNumber - 1}`} />
)}
{pageNumber < totalPages && (
<link rel="next" href={`/products?page=${pageNumber + 1}`} />
)}
</Head>
{/* content */}
</>
);
}Також додайте схему пагінації JSON-LD:
const paginationSchema = {
"@context": "https://schema.org",
"@type": "CollectionPage",
"url": `https://mystore.com/products?page=${pageNumber}`,
"hasPart": products.map(p => ({
"@type": "Product",
"url": `https://mystore.com/products/${p.id}`,
"name": p.name,
})),
};
if (pageNumber > 1) {
paginationSchema.previousPage = `https://mystore.com/products?page=${pageNumber - 1}`;
}
if (pageNumber < totalPages) {
paginationSchema.nextPage = `https://mystore.com/products?page=${pageNumber + 1}`;
}7. Моніторинг та вимірювання ефективності з SEO Tулзами
Оптимізація без контролю це марна трата часу. Вам потрібно бачити, чи дійсно ваші зміни покращують ефективність та рейтинги.
Аудит Lighthouse
Lighthouse — це золотий стандарт аудиту ефективності. Він вимірює:
- Оцінку ефективності (0-100)
- Оцінку доступності
- Оцінку найкращих практик
- Оцінку SEO
- Основні показники веб-активності (LCP, INP, CLS)
Запустіть Lighthouse в Chrome DevTools:
- Відкрийте DevTools (F12)
- Перейдіть на вкладку Lighthouse
- Виберіть «Ефективність»
- Натисніть «Analyze page load»
Lighthouse генерує детальний звіт, який точно показує, що уповільнює роботу вашого сайту і як це виправити.
Lighthouse CI для безперервного моніторингу
Налаштуйте Lighthouse CI у вашому build пайплайні, щоб автоматично перевіряти кожне розгортання:
npm install -g @lhci/cli@latestСтворіть конфігураціюlighthouserc.json:
{
"ci": {
"collect": {
"numberOfRuns": 3,
"url": ["https://mysite.com"]
},
"upload": {
"target": "temporary-public-storage"
},
"assert": {
"preset": "lighthouse:recommended",
"assertions": {
"categories:performance": ["error", { "minScore": 0.9 }],
"categories:seo": ["error", { "minScore": 0.9 }]
}
}
}
}Тепер кожн деплой автоматично перевіряється, і збірка завершується з помилкою, якщо продуктивність погіршується.
Звіт Google Search Console: Core Web Vitals
Відстежуйте реальні дані Core Web Vitals у Google Search Console:
- Перейдіть до Google Search Console.
- Виберіть свій ресурс.
- Перейдіть до розділу «Досвід» > «Core Web Vitals».
- Перегляньте показники LCP, INP та CLS для вашого сайту.
Це показує, як ваш сайт працює для реальних користувачів, а не тільки в лабораторних тестах.
React DevTools Profiler
Визначте найповільніші компоненти рендерингу:
- Встановіть розширення React DevTools для браузера
- Відкрийте DevTools (F12)
- Перейдіть на вкладку Profiler
- Натисніть Record
- Взаємодійте з вашим сайтом
- Зупиніть запис
Profiler показує, які компоненти рендерилися найдовше і які рендерилися повторно без необхідності. Ми виявили компоненти, які рендерилися повторно при кожному натисканні клавіші — одна оптимізація скоротила час рендерингу на 70%.
Бібліотека Web Vitals
Надішліть дані про реальну продуктивність до вашої аналітики:
npm install web-vitalsimport { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getFCP(console.log);
getLCP(console.log);
getTTFB(console.log);Або інтегруйте з вашим постачальником аналітики:
import { getCLS, getFID, getLCP } from 'web-vitals';
function sendToAnalytics(metric) {
// Send to Google Analytics, Segment, etc.
gtag('event', metric.name, {
value: Math.round(metric.value),
event_category: 'Web Vitals',
});
}
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getLCP(sendToAnalytics);Тепер ви маєте уявлення, як ваші оптимізації впливають на реальних користувачів.
Бенчмаркінг відносно конкурентів
Використовуйте такі інструменти, як SimilarWeb або Ahrefs, щоб порівняти ефективність вашого сайту з конкурентами. Якщо ваш сайт працює в 2 рази повільніше за конкурентів, ви втрачаєте рейтинги та трафік.
8. Уникайте типових помилок React SEO
Навіть з гарними намірами легко припуститися помилок, які підривають ваші зусилля з оптимізації. Ось найпоширеніші помилки, які ми бачимо, і як їх уникнути.
Помилка 1: Маршрутизація на основі хешу
Маршрутизація на основі хешу (#/page) розглядає весь ваш сайт як одну сторінку:
// Bad - hash-based routing
<BrowserRouter>
<Route path="/#/products" component={Products} />
<Route path="/#/about" component={About} />
</BrowserRouter>Пошукові системи бачать тільки один URL-адресу (домашню сторінку) і не можуть сканувати окремі сторінки. Замість цього використовуйте API історії:
// Good - history-based routing
<BrowserRouter>
<Route path="/products" component={Products} />
<Route path="/about" component={About} />
</BrowserRouter>Або використовуйте Next.js, який за замовчуванням використовує маршрутизацію на основі файлів.
Проблема 2: Блокування важливих ресурсів за допомогою robots.txt
Деякі розробники блокують CSS і JavaScript у файлі robots.txt, щоб заощадити бюджет сканування:
User-agent: *
Disallow: /*.js
Disallow: /*.cssЦе катастрофа. Пошукові системи потребують CSS і JavaScript для відображення вашого React-застосунку. Без них вони бачать порожню сторінку. Дозвольте пошуковим системам сканувати ці ресурси:
User-agent: *
Allow: /Проблема 3: Відтворення вмісту в useEffect
Вміст, відтворений вuseEffect, не включено в початковий HTML, тому пошукові системи його не бачать:
// Bad - content not in initial HTML
export default function ProductPage() {
const [product, setProduct] = useState(null);
useEffect(() => {
fetchProduct().then(setProduct);
}, []);
return <h1>{product?.name}</h1>;
}Використовуйте SSR або отримуйте дані під час фази рендерингу:
// Good - content in initial HTML with SSR
export async function getServerSideProps() {
const product = await fetchProduct();
return { props: { product } };
}
export default function ProductPage({ product }) {
return <h1>{product.name}</h1>;
}Проблема 4: Ігнорування продуктивності на мобільних пристроях
Застосунки React часто працюють гірше на мобільних пристроях через повільніші процесори та мережу. Тестуйте на реальних мобільних пристроях, а не тільки на десктопах:
# Use Chrome DevTools device emulation
# But also test on real phonesМи бачили застосунки, які добре працюють на настільних комп’ютерах, але не відповідають вимогам Core Web Vitals на мобільних пристроях. Оптимізація з урахуванням мобільних пристроїв є надзвичайно важливою.
Помилка 5: Відсутність тестування за допомогою Googlebot
Використовуйте інструмент перевірки URL-адрес Google Search Console, щоб побачити те саме, що бачить Googlebot:
- Перейдіть до Google Search Console.
- Введіть URL-адресу.
- Натисніть «Перевірити URL-адресу».
- Перейдіть на вкладку «Rendered HTML».
Тут ви побачите, чи може Googlebot бачити ваш контент. Якщо ви бачите порожню сторінку, це означає, що ваша React-програма не рендериться правильно для пошукових систем.
Проблема 6: надмірна оптимізація за рахунок користувацького досвіду
Іноді розробники оптимізують сайт для SEO за рахунок користувацького досвіду. Повільний несправний сайт, який має високий рейтинг, гірший за швидкий несправний сайт, який не має рейтингу. На першому місці мають бути реальні користувачі, а SEO — на другому.
Перелік питань для перевірки перед запуском SEO
Перед запуском React-застосунку перевірте:
- Метатеги є унікальними для кожної сторінки (не статичні)
- Оцінки Core Web Vitals у Lighthouse зелені
- Початковий пакет менше 200 КБ у форматі gzip
- Реалізовано рендеринг на стороні сервера або статичне генерування
- Зображення завантажуються з lazy-load
- Пагінація має унікальні URL-адреси (ніякого нескінченного скролу без оновлення URL-адрес)
- robots.txt дозволяє CSS і JavaScript
- Перевірка URL-адрес у Google Search Console показує відрендерений контент
- Структуровані дані реалізовано для розширених сніпетів
- Продуктивність на мобільних пристроях перевіряється на реальних пристроях
Оптимізація продуктивності React — це безперервний процес
Проблеми з продуктивністю React для SEO є реальними, але їх можна повністю вирішити. Протягом останніх кількох років ми допомогли десяткам клієнтів перетворити React-застосунки з «без рейтингу» на «ранжуються на першій сторінці» завдяки впровадженню технік, описаних у цьому посібнику.
Ключові висновки
- Рендеринг на сервері або статичне генерування є фундаментальним.Воно вирішує основну проблему індексації. Без нього пошукові системи не можуть побачити ваш контент. З ним ви на 80% на шляху до SEO-оптимізованого React-застосунку.
- Core Web Vitals мають значення.Продуктивність є підтвердженим фактором ранжування. Код-спліттінг, лейзі лоідінг та зменшення розміру бандла безпосередньо покращують ці показники.
- Динамічні метатеги необхідні.Кожна сторінка потребує унікальних заголовків, описів та структурованих даних. Компоненти React Helmet або Next.js head спрощують це.
- Вимірювання сприяє вдосконаленню.Встановіть базові показники за допомогою Lighthouse, впровадьте оптимізації та перевірте, чи вони працюють. Те, що вимірюється, вдосконалюється.
- React не є поганим для SEO.Погана реалізація — це погано. А React-застосунки, побудовані з використанням відповідних фреймворків (Next.js, Remix) та відповідних методів оптимізації, мають такий самий рейтинг, як і традиційні сайти, що відображаються на сервері.
Ширший контекст
Оптимізація React існує в ширшому контексті технічних основ SEO. Важливе значення мають можливість кроулінгу, індексація та архітектура сайту. Оптимізація React гарантує, що ваш сайт можна сканувати та він є продуктивним, але це лише частина комплексної стратегії SEO.
Наступні кроки
- Проведіть аудит вашого застосунка React.Запустіть Lighthouse в Chrome DevTools. Визначте ботлнек у продуктивності.
- Впровадьте найефективнішу оптимізацію.Для більшості застосунків це перехід на серверний рендеринг або статичне генерування за допомогою Next.js.
- Виміряйте поліпшення.Запустіть Lighthouse знову. Порівняйте Core Web Vitals до і після.
- Повторіть.Впровадьте наступну оптимізацію. Повторіть.
- Моніторинг поточної продуктивності.Налаштуйте моніторинг Lighthouse CI та Google Search Console, щоб виявляти регресії.
Якщо ви створюєте новий застосунок React з нуля, важливо відразу закласти правильну архітектуру. Наша команда пропонує повний циклвеб-розробки з нуля, ми створюємо React та Next.js застосунки з урахуванням SEO, продуктивності та Core Web Vitals.
Якщо ви підтримуєте існуючий застосунок React, оптимізації, описані в цьому посібнику, значно покращать вашу SEO-продуктивність та користувацький досвід.
У OSTER Tech ми бачили, як React-застосунки покращувалися від провалу Core Web Vitals до їх проходження, від невидимості в пошуку до рейтингу на першій сторінці. Ці техніки працюють. Питання в тому, чи будете ви їх впроваджувати.
Змістовний React HTML на edge
OSTER не покладає доставку індексованого контенту на клієнтський JavaScript. Next.js з OpenNext на Cloudflare Workers дозволяє для кожного маршруту обрати статичну генерацію, ревалідацію або серверний рендеринг відповідно до частоти змін. Title, заголовки, links, schema.org і основний текст уже є в початковому HTML. Гідратація додає взаємодію, а не вирішує, чи побачать сторінку користувач і пошуковий робот.
Спочатку менше роботи, потім оптимізація компонентів
Найбільший ефект часто дають рішення на рівні доставки: прибрати зайві client boundaries, підключати сторонні скрипти лише на потрібних маршрутах, безпечно кешувати публічні відповіді, стискати сучасні ресурси й віддавати зображення у правильних форматах та розмірах. Cloudflare наближає кешований контент до відвідувача і захищає origin, а bundle analysis показує JavaScript, який усе ще потрапляє у браузер.
Performance-контроль для наступних релізів
OSTER поєднує автоматичні бюджети з робоче середовище-спостереженням. Перед релізом перевіряємо серверний HTML, розміри ресурсів, cache headers, HTTP-статуси та критичні сценарії; Cloudflare Analytics і логи Workers показують регіональні або origin-регресії. Версійний розгортання забезпечує швидкий відкат. Так React може розвиватися без непомітної втрати crawlability, швидкість реакції чи конверсійної ефективності.
Виправте controlling bottleneck
React performance варто починати з real-user підтвердження і найповільнішого важливого journey, а не generic checklist. OSTER може простежити застосунок, відділити frontend symptoms від backend і delivery causes та реалізувати найбільш впливові fixes.