Разработка фронтенда интернет-магазина на Vue.js для 1С-Битрикс
Типичная ситуация: дизайнер нарисовал каталог с анимированными фильтрами, мгновенным обновлением корзины и переходами между страницами без перезагрузки. Фронтенд-разработчик смотрит на шаблоны bitrix:catalog.section и bitrix:sale.order.ajax — и понимает, что вписать это в стандартную компонентную модель Битрикс невозможно без костылей. Тут и появляется headless-подход: Битрикс остаётся бэкендом, а весь интерфейс живёт на Vue.js.
Это не «модный стек ради моды». Headless оправдан, когда стандартные шаблоны Битрикс не позволяют реализовать требуемый UX, когда фронтенд-команда работает автономно от бэкенд-разработчиков, или когда один API обслуживает сайт, мобильное приложение и киоски в офлайн-точках.
Архитектура: как разделяются слои
В классическом Битрикс-магазине PHP-компонент делает выборку, передаёт массив в template.php, там же подключается CSS и JS. В headless-схеме всё иначе:
-
Битрикс работает как API-сервер. Каталог, цены, остатки, корзина, оформление, авторизация — всё через REST API (модуль
rest) или кастомные контроллеры на базе\Bitrix\Main\Engine\Controller. - Vue.js / Nuxt.js — отдельное приложение. Рендерит интерфейс, управляет маршрутизацией, состоянием, формами.
-
Nginx проксирует:
/api/*уходит в Битрикс, остальное — на статику Vue или Node.js (при SSR).
Деплой фронтенда и бэкенда независимый. Фронтенд-разработчик пушит в свой репозиторий, CI собирает бандл, раскатывает на CDN или Node-сервер. Бэкенд-разработчик обновляет Битрикс отдельно. Контракт между ними — API-спецификация.
REST API Битрикс: что работает, а что придётся дописывать
Модуль rest предоставляет методы для основных сущностей магазина.
Каталог:
-
catalog.product.list— товары с фильтрацией по свойствам, секции, цене -
catalog.product.get— детальная карточка -
catalog.product.offer.list— торговые предложения (SKU) -
catalog.section.list— дерево категорий -
catalog.price.list— цены по типу
Корзина:
-
sale.basket.addItem,sale.basket.updateItem,sale.basket.deleteItem,sale.basket.getItems
Заказ:
-
sale.order.add,sale.order.get,sale.order.list -
sale.shipment.getDeliveryServices,sale.paySystem.getList
На бумаге всё покрыто. На практике начинаются нюансы.
catalog.product.list не возвращает произвольные свойства инфоблока. Нужно дополнительно запрашивать через catalog.product.getFieldsByFilter или писать свой endpoint. Фасетная фильтрация — подсчёт количества товаров по каждому значению фильтра, как в стандартном smart_filter — в REST API отсутствует. Расчёт стоимости доставки по содержимому корзины — ещё один метод, которого нет из коробки.
Решение — кастомные REST-методы. Регистрируются через \CRestServer::onRestServiceBuildDescription() или через \Bitrix\Main\Engine\Controller с аннотацией @restMethod. На стороне Битрикс кастомный контроллер выполняет выборку и возвращает JSON:
-
/api/catalog/filter— товары + фасеты (количество по значениям фильтра) -
/api/cart/calculate— пересчёт корзины с учётом правил корзины, скидок и промокодов -
/api/checkout/submit— оформление заказа одним запросом
Фасетный индекс — отдельная история. Битрикс хранит предрассчитанные фасеты в таблице b_catalog_smart_filter. При headless-подходе нужно либо использовать эту таблицу напрямую через ORM, либо строить фасеты на лету. Первый вариант быстрее, но привязывает к внутренней структуре Битрикс. Второй — медленнее на больших каталогах (50 000+ товаров), зато предсказуем.
Компонентная архитектура Vue-приложения
Структура фронтенда для интернет-магазина:
src/
├── pages/
│ ├── CatalogPage.vue # список товаров с фильтрами
│ ├── ProductPage.vue # карточка товара
│ ├── CartPage.vue # корзина
│ ├── CheckoutPage.vue # оформление
│ └── AccountPage.vue # личный кабинет
├── components/
│ ├── catalog/
│ │ ├── ProductCard.vue
│ │ ├── FilterPanel.vue
│ │ └── FacetCounter.vue
│ ├── cart/
│ │ ├── CartItem.vue
│ │ └── CartSummary.vue
│ └── ui/ # переиспользуемые элементы
├── stores/
│ ├── catalogStore.ts # Pinia: товары, фильтры, пагинация
│ ├── cartStore.ts # корзина, синхронизация с API
│ ├── userStore.ts # авторизация, токен
│ └── checkoutStore.ts # оформление заказа
├── api/
│ ├── catalog.ts # обёртки над API каталога
│ ├── cart.ts
│ └── auth.ts
└── composables/
├── useProductFilter.ts # логика фильтрации
└── useInfiniteScroll.ts # бесконечная прокрутка
Pinia управляет состоянием. cartStore — самый нетривиальный: при добавлении товара нужно мгновенно обновить UI (optimistic update), отправить запрос к API, получить ответ с актуальной ценой (Битрикс мог применить скидку или списать остаток) и синхронизировать локальное состояние с сервером. Для неавторизованных пользователей корзина живёт в localStorage и мигрирует на сервер после логина.
Vue Router с lazy-loading: каждая страница — отдельный chunk. Переходы между категориями не перезагружают приложение, а фильтры пишутся в query-параметры URL для возможности поделиться ссылкой.
SSR: без него в e-commerce нельзя
Vue SPA рендерится на клиенте. Поисковой робот видит пустой <div id="app"></div>. Для интернет-магазина, где карточки товаров и категории должны индексироваться, это приговор.
Nuxt.js с SSR — основной вариант. Node.js-сервер рендерит Vue-компоненты в HTML, данные из Битрикс API запрашиваются через useFetch() или useAsyncData(). Клиент получает готовый HTML, после гидратации приложение работает как SPA.
Nuxt.js с ISR (Incremental Static Regeneration) — гибрид. Страницы каталога кешируются и обновляются по TTL или по вебхуку из Битрикс при изменении товара. Nuxt 3 поддерживает routeRules с swr (stale-while-revalidate):
// nuxt.config.ts
routeRules: {
'/catalog/**': { swr: 3600 }, // кеш на час
'/product/**': { swr: 600 }, // кеш на 10 минут
'/cart': { ssr: false }, // корзина — только клиент
'/checkout': { ssr: false },
}
Для каталогов с 50 000+ товаров SSR предпочтительнее полной статической генерации — nuxt generate для такого объёма займёт часы.
Мета-теги — отдельная задача. В Битрикс шаблоны SEO настраиваются в свойствах инфоблока (шаблоны вида {=this.Name} купить в Минске). В headless-подходе эти шаблоны нужно отдавать через API и применять в Nuxt через useHead() или useSeoMeta().
Авторизация
Два подхода:
OAuth 2.0 через модуль rest: фронтенд перенаправляет на /oauth/authorize/, пользователь логинится на стороне Битрикс, получает code, обменивает на access_token. Стандартный flow, но UX страдает — редирект на другой домен.
Кастомный JWT-endpoint: /api/auth/login принимает логин/пароль, Битрикс проверяет через CUser::Login(), создаёт сессию и возвращает JWT. Фронтенд хранит токен в httpOnly cookie (не в localStorage — иначе XSS-уязвимость). Refresh-токен продлевает сессию без повторного ввода пароля. Проще в реализации, UX лучше.
Что теряется при headless
- Визуальный редактор — не работает. Контент управляется через админку Битрикс, фронтенд забирает данные по API.
- Композитный кеш — не применим. Кеширование на стороне Nuxt (ISR) или CDN.
-
Стандартные компоненты —
bitrix:catalog.section,bitrix:sale.order.ajaxне используются. Вся логика отображения на Vue. - Обмен с 1С — работает без изменений, это серверная сторона.
Сроки по масштабу проекта
| Масштаб | Что входит | Срок |
|---|---|---|
| MVP-каталог | Листинг, карточка товара, фильтры, SSR | 1–2 недели |
| Магазин без личного кабинета | + корзина, оформление, оплата | 3–4 недели |
| Полноценный магазин | + ЛК, история заказов, избранное, сравнение | 5–8 недель |
| B2B-портал | + типы цен по группам, персональные каталоги, быстрый заказ | 8–12 недель |
Headless на Битрикс — компромисс. Современный фронтенд и гибкость в обмен на потерю части экосистемы и увеличение стоимости поддержки. Подход оправдан для проектов с высокими требованиями к интерфейсу, выделенной фронтенд-командой и планами на мультиплатформенность.







