Одностраничное приложение на React + Vite (TypeScript), работает поверх публичного API https://app-stage.zavarka39.ru/api.
# установить зависимости
npm install
# dev-режим
npm run dev
# прод-сборка
npm run build
# прод-сборка с pre-rendering (для SEO)
npm run build:prerender
# предпросмотр
npm run previewsrc/
├── main.tsx # Entry point
├── App.tsx # Корневой компонент, роутинг
├── api.ts # HTTP-клиент (JWT + auto-refresh)
├── config.ts # Константы (URL, ключи)
│
├── components/ # Переиспользуемые UI-компоненты
├── pages/ # Страницы приложения
├── hooks/ # React-хуки (auth, cart, route, theme)
├── types/ # TypeScript-типы
├── utils/ # Утилиты (format, seo, categories)
│
└── styles/ # CSS (ITCSS + CSS Layers)
├── global.css # Точка входа (@import + @layer)
├── _tokens.css # Design tokens
├── _reset.css # Browser reset + a11y
├── _animations.css # Все @keyframes
├── _utilities.css # Утилитарные классы
├── components/ # Стили компонентов (BEM)
└── pages/ # Стили страниц
Для улучшения индексации поисковыми системами используется pre-rendering. Скрипт генерирует статические HTML-файлы для всех страниц продуктов с правильными <title> тегами.
Как это работает:
- После обычной сборки (
npm run build) запускается скрипт pre-rendering - Скрипт получает список всех продуктов из API
- Используя Puppeteer, рендерит каждую страницу и сохраняет HTML с обновлённым title
- Результат сохраняется в
dist/
# Полная сборка с pre-rendering
npm run build:prerender
# Только pre-rendering (после build)
npm run prerenderPre-rendering занимает время (зависит от количества продуктов). Для быстрой разработки используйте обычный
npm run build.
- Главная — каталог с поиском, фильтрами по категориям и быстрым добавлением товара.
- Страница товара — описание, выбор варианта фасовки, добавление в корзину.
- Галерея изображений с лайтбоксом, свайпом (мобильные), pinch-to-zoom и навигацией клавиатурой.
- Для категории «чай»: блок заваривания (профили с тултипами), вкусовой профиль (шкалы + чипсы), эффект.
- Кнопки «Поделиться» (Telegram, WhatsApp, VK, Email) и «Копировать ссылку».
- Корзина — изменение количества, удаление, итоговая сумма.
- Оформление заказа — контактные данные, способ доставки, отправка в API.
- Переключатель темы (светлая / тёмная) с сохранением в
localStorage.
Корзина и оформление заказа доступны только авторизованным пользователям.
Стили организованы по принципу ITCSS (от общих к специфичным) с явным управлением каскадом через CSS @layer.
| Слой | Файл(ы) | Назначение |
|---|---|---|
tokens |
_tokens.css |
CSS custom properties: цвета, тени, радиусы, переходы, z-index, типографика |
reset |
_reset.css |
Browser reset, focus-visible, prefers-reduced-motion |
animations |
_animations.css |
Все @keyframes (единственное место) |
utilities |
_utilities.css |
Переиспользуемые классы (.button, .pill, .input, .alert) |
components |
components/_*.css |
Стили компонентов (BEM) |
pages |
pages/_*.css |
Стили страниц |
Новый компонент:
- Создать
src/styles/components/_name.css - Добавить
@import './components/_name.css' layer(components);вglobal.css
Новая страница:
- Создать
src/styles/pages/_name.css - Добавить
@import './pages/_name.css' layer(pages);вglobal.css
- Все значения — через токены:
var(--text-sm),var(--radius-md),var(--transition-fast),var(--shadow-sm),var(--z-overlay) - Полупрозрачные цвета:
color-mix(in srgb, var(--primary) 50%, transparent)вместоrgba() - CSS nesting (
&) — только для:hover,:focus,.modifier,[data-theme='dark'] & - BEM-элементы (
__element) и модификаторы (--modifier) — плоские селекторы (нативный nesting не поддерживает конкатенацию строк) - Логические свойства:
margin-inline-startвместоmargin-left - Динамические значения из TSX — через CSS custom properties:
style={{ '--delay': '0.1s' }}+animation-delay: var(--delay) @keyframes— определять только в_animations.css- Новые токены — добавлять в
_tokens.css
prefers-reduced-motion: reduce— глобальный сброс анимаций/переходовcolor-scheme: light dark— нативная поддержка тёмной темыaccent-color: var(--primary)— стилизация нативных form controls:focus-visible— видимый фокус для клавиатурной навигации
При выборе стека для этого проекта была допущена стратегическая ошибка: чистый React (SPA) плохо подходит для e-commerce сайтов, где SEO критически важен.
-
Client-Side Rendering (CSR) — React рендерится на клиенте, поэтому поисковые боты изначально видят пустой
<div id="root">. Хотя Googlebot умеет исполнять JavaScript, это:- Замедляет индексацию (ботам нужно ждать рендеринга)
- Не гарантирует корректную индексацию (бот может уйти раньше)
- Другие поисковики (Яндекс, Bing) хуже справляются с JS-рендерингом
-
Динамические meta-теги —
<title>,<meta description>, Open Graph теги должны быть в исходном HTML. В SPA они обновляются через JavaScript, что поисковики могут не увидеть. -
Проблема с 404 страницами — SPA всегда отдаёт 200 OK для любого URL (nginx делает fallback на
index.html), что мешает корректной обработке удалённых страниц.
-
Pre-rendering через Puppeteer (
scripts/prerender.js) — отдельный шаг сборки, который рендерит каждую страницу в headless Chrome и сохраняет статический HTML. Медленно, хрупко, требует поддержки. -
Детекция ботов в nginx — специальные правила для определения поисковых ботов и редирект их на pre-rendered версии. Дополнительная сложность в конфигурации.
-
Ручное управление meta-тегами — кастомный хук
useSEO, который черезdocument.titleи манипуляции с DOM обновляет теги. Работает, но это обходной путь. -
Статические 404 страницы — отдельная логика для возврата 404 статуса при обращении к несуществующим страницам.
-
Генерация sitemap.xml — отдельный скрипт, который должен знать о всех возможных URL.
Цель: миграция на SEO-friendly фреймворк.
Рассматриваемые варианты:
| Фреймворк | Преимущества | Недостатки |
|---|---|---|
| Next.js | SSR/SSG из коробки, App Router, React Server Components, отличная экосистема | Привязка к Vercel для лучшего опыта, может быть избыточен |
| Astro | Islands architecture, минимум JS на клиенте, отличный для контентных сайтов | Меньше интерактивности, новый подход |
| Remix | SSR, прогрессивное улучшение, хорошая работа с формами | Менее популярен, меньше экосистема |
| Nuxt 3 (Vue) | SSR/SSG, отличный DX, хорошая документация | Переход с React на Vue |
Наиболее вероятный выбор: Next.js — позволит переиспользовать React-компоненты, обеспечит SSR/SSG из коробки, имеет встроенную генерацию sitemap и обработку meta-тегов.
Для любого проекта, где SEO важен (e-commerce, лендинги, контентные сайты), с самого начала выбирайте фреймворк с SSR/SSG: Next.js, Nuxt, Astro, SvelteKit. Чистый SPA (Create React App, Vite + React) подходит только для приложений за авторизацией (админки, дашборды, внутренние инструменты).