Мой стэк для интернет-магазина на NextJS
Недавно закончил очередной онлайн-магазин отопительного оборудования. Хочу поделиться стэком технологий, который использовал для него.
Сайт:
Github:
На момент запуска в магазине было около 19 тыс товаров, сгруппированных по моделям и коллекциям. В дальнейшем планируется расширение ассортимента до 40-50 тыс товаров.
Фреймворк и база данных
Основу проекта составляют фреймворк NextJS и база данных MongoDB (для работы с ней я использовал mongoose). Последняя выбрана во многом из-за гибкости (есть множество специфичных характеристик для разных моделей радиаторов) и наличия отличного приложения MongoDB Compass, позволяющего наполнять и обновлять базу через импорт CSV (база товаров хранится изначально в Google Sheets).
Связь между документами и коллекциями происходит через текстовое поле `slug` вместо `_id`. Такой подход значительно упрощает обновление и перенос данных. Так, в случае неудачной заливки товаров и моделей в базу, их можно просто удалить и добавить заново импортом файла CSV, не опасаясь за сохранение связей между сущностями.
Этот же подход, хорошо работает и для SQL баз.
Кэширование запросов к базе
У меня были опасения по поводу работы `unstable_cache` с `mongoose`, но пока что кэширование работает, как и ожидалось. Так как данные на сайте обновляются редко, то время кэширования выставлено на 12 часов.
Типичный запрос выглядит так:
```
const line= (await unstable_cache(async () => await Line.findOne({ slug: lineSlug }).lean(), ["cache:line", lineSlug], {revalidate: 60 * 60 * 12 )()) as TLine | null;
```
Wordpress в качестве CMS
В качестве CMS здесь используется WordPress. Это значительно упрощает работу по управлению наполнением страниц. Для идентификации нужно контента используются значения поля `slug` для соответствующих сущностей.
Например, описание для коллекции "Cube" находится по адресу `page-content-line-cube`.Саму настройку WP для использования в качестве CMS я подсмотрел в этом видео:
К сожалению, у меня не получилось использовать встроенные в WP мета-теги, поэтому использовал плагин Advanced Custom Fields, позволяющий заводить для страниц и записей собственные поля.
Компонент Image и CDN
Для передачи изображений товаров используется CDNNow.
Настройка довольна проста, достаточно указать в компоненте `Image` требуемые размеры изображений, исходя из размеров окна и далее уже сам компонент передаст подходящую ширину в функцию `loader`:
```
<Image
loader={({ src, width }) =>`${CdnUrl}/${src}?width=${width}`}
src={img.src}alt={img.alt}
sizes="(max-width: 768px) 50vw, (max-width: 1280px) 33vw, 25vw"
/>
```
`CdnUrl` - адрес, который предоставляет сервер при регистрации вашего сайта.
UI
Визуальная часть создана за счет `tailwindcss` и `shadcn`. Это мой выбор по-умолчанию для большинства проектов. Хотя с последней библиотекой периодически и возникают сложности. Так в этом проекте компонент `Drawer` отвечал за вывод вариантов покраски и подключений радиаторов и некорректно работал на мобильных телефонах. Поэтому его пришлось заменить на похожий по функционалу компонент `Sheet`.