You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Рекомендации по ускорению загрузки и оптимизации кода для лучшего UX и метрик (LCP, FID, CLS). Применяются к публичной части в nextjs-project (App Router, layout и страницы в (site)).
Сделано
1. Главная страница — запросы к БД
Было: два одинаковых запроса постов (новости и статьи) с одними параметрами — лишний round-trip к БД.
Стало: два раздельных запроса с фильтром по type ('news' / 'article'). В блоках «Новости» и «Статьи» отображаются корректные данные, дублирования запросов нет.
2. Hero-изображение (LCP)
Было:next/image с unoptimized — отключена оптимизация (формат, размер, lazy).
Стало:unoptimized убран. Изображение обрабатывается через Image Optimization API (WebP/AVIF при поддержке), что улучшает LCP.
3. Лого в хедере
Было: обычный <img> без оптимизации.
Стало:next/image с priority и фиксированным контейнером. Лого в above-the-fold загружается с приоритетом.
4. Корзина — убран Framer Motion
Было: анимация открытия/закрытия через framer-motion (AnimatePresence, motion.div).
Стало: те же эффекты реализованы на CSS (transition opacity/transform). Панель и фон всегда в DOM, видимость через классы. Бандл без framer-motion на этой странице.
5. ISR вместо force-dynamic
Было:export const dynamic = 'force-dynamic' на главной, layout сайта, каталоге и странице категории — каждый запрос вёл к полному рендеру и запросам к БД.
Стало:export const revalidate = 60 (кэш на 60 секунд). Страницы отдаются из кэша и обновляются не чаще раза в минуту.
Стало: 3 начертания (400, 600, 700). Меньший объём загрузки шрифтов.
7. Пагинация каталога
Было: загрузка всех товаров на /catalog.
Стало: по 24 товара на страницу, навигация «Назад» / «Вперёд» и параметр ?page=. Запрос с take: 25 и skip для определения наличия следующей страницы.
8. Страницы товаров — ISR
Было:force-dynamic на product/[slug]/page.tsx и product/id/[id]/page.tsx.
Стало:revalidate = 60. Карточки товаров кэшируются на 60 секунд.
9. Корзина — доступность (a11y)
При закрытии панель и фон помечаются aria-hidden={true}, скринридеры их не озвучивают.
Для панели при закрытии выставляется атрибут inert (через ref + useEffect), чтобы элементы внутри не попадали в порядок табуляции.
10. Удалена зависимость framer-motion
В package.json удалён пакет framer-motion — в коде он больше не используется (корзина переведена на CSS).
Детальная проверка (аудит)
Проверка
Статус
Главная: один тип запросов постов (news/article), без дублей
✅ Два запроса с разными type, дублей нет
Hero: нет unoptimized, есть priority
✅
Лого в хедере: next/image + priority
✅
Корзина: без framer-motion, анимации на CSS
✅
revalidate 60 на главной, layout, каталоге, категории, товарах
✅
Шрифты: только 400, 600, 700
✅
Пагинация каталога: 24 на страницу, ?page=, Назад/Вперёд
✅
Нет оставшихся force-dynamic в (site)
✅
framer-motion удалён из package.json
✅
Корзина: при закрытии не ловит фокус (inert + aria-hidden)
✅
Пагинация: при ?page=abc или отрицательном значении используется страница 1. При ровно 24 товарах кнопка «Вперёд» не показывается.
Шрифты: в CSS используются font-weight: 500 и др. — браузер подставляет ближайшее начертание (400/600/700). При необходимости можно подключить 300 или 500 точечно.
Рекомендации по дальнейшей оптимизации
Рендеринг и кэш
Что
Где
Действие
revalidate
Выставлен 60 с на главной, layout, каталоге, категории, страницах товара.
При необходимости чаще обновлять контент — уменьшить значение; для более статичного — увеличить (например 300).
Фоны задаются через CSS url(), Next Image не используется. Варианты: предзагрузка критичных фонов, использование next/image с fill в обёртке или сохранение текущего подхода с оптимизированными файлами (WebP, сжатие).
Картинки товаров
ProductCard
Уже используется next/image с sizes — ок. Следить, чтобы photo всегда был локальным путём или настроенным доменом в next.config.
Форматы
Статика в /public
Хранить hero, лого, фоны в современном формате (WebP/AVIF где возможно) и сжатыми — уменьшит вес и улучшит LCP.
Каталог и данные
Что
Где
Действие
Пагинация
catalog/page.tsx
Реализована: 24 товара на страницу, ссылки Назад/Вперёд. При очень большом каталоге можно добавить виртуализацию списка или бесконечный скролл.
Выборка полей
Prisma-запросы
Уже используется select/include только нужных полей — хорошо. Продолжать не тянуть лишние поля (например, content у постов на списках).
JavaScript и бандл
Что
Где
Действие
Framer Motion
Убран из корзины, зависимость удалена из package.json.
—
Динамический импорт
Тяжёлые компоненты
Модалки, админские редакторы (TipTap и т.п.) подгружать через next/dynamic с ssr: false там, где они не нужны для первого рендера.
Шрифты
layout.tsx — Montserrat
Оставлены 3 начертания (400, 600, 700). При необходимости добавить 300/500/800 — подключать точечно.
Стили
Что
Где
Действие
globals.css
~1200 строк
При росте файла можно выносить редко используемые блоки (например, анимации логина) в отдельные модули и подключать только на нужных маршрутах.
will-change / анимации
Hero (aurora), marquee
Уже используются. Следить за тем, чтобы will-change не висел на большом количестве элементов — только на анимированных.
Прочее
Что
Действие
next.config
В проекте используется next.config.ts. При использовании внешних изображений настроить images.domains / images.remotePatterns. Для локальных картинок дефолтная конфигурация достаточна.
Метрики
Подключить замеры (e.g. Web Vitals в Vercel Analytics или через reportWebVitals) и отслеживать LCP, FID, CLS после изменений.
Чек-лист перед релизом
Проверить LCP: hero и лого без unoptimized, с priority где нужно.
Убедиться, что нет дублирующих запросов к БД на одной странице.
При большом каталоге — пагинация или ленивая подгрузка товаров.
Тяжёлые клиентские библиотеки — корзина на CSS; при неиспользовании framer-motion — удалить из зависимостей.
Шрифты: только нужные начертания (400, 600, 700) и subset (latin + cyrillic).