Scalable Vue Components for 1C-Bitrix: A Systematic Architecture

When building an e-commerce store on 1C-Bitrix with Vue.js, it usually starts with a single component—a cart or a filter. A month later, a second and third appear, each with its own server logic, store, and styles. The cart state in the header diverges from the state in the popup, AJAX code duplicat

Our competencies:

Frequently Asked Questions

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1415
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    Website development for FIXPER company
    995
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    Development based on Bitrix, Bitrix24, 1C for the company Development of an Online Appointment Booking Widget for a Medical Center
    733
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    Development based on 1C Enterprise for MIRSANBEL
    863
  • image_crm_dolbimby_434_0.webp
    Website development on CRM Bitrix24 for DOLBIMBY
    772
  • image_crm_technotorgcomplex_453_0.webp
    Development based on Bitrix24 for the company TECHNOTORGKOMPLEKS
    1134

When building an e-commerce store on 1C-Bitrix with Vue.js, it usually starts with a single component—a cart or a filter. A month later, a second and third appear, each with its own server logic, store, and styles. The cart state in the header diverges from the state in the popup, AJAX code duplicates, and styles break the layout. We’ve seen this dozens of times. The only reliable solution is not a collection of components but an architecture: a system where all parts share a common state, a unified API layer, and design tokens. Our company has 10+ years in Bitrix development, over 50 successful projects, and 5 years on the market. With a systematic approach, time to develop a new component drops by 40%, and errors halve. Average annual support savings range from 200,000 to 500,000 rubles for a medium project. Book a consultation—we’ll show you how it works on your project.

Why a single component is integration, but a system is architecture

Integration: you take a ready Vue component and embed it into a template. It works, but each new component requires new crutches: its own store, its own HTTP client, its own loading logic. In six months, the site runs three versions of the cart, two AJAX approaches, and mountains of duplicated code. Architecture: you predefine the system’s core—configuration, stores, API layer, UI base. Each new component uses ready blocks without reinventing the wheel. A component system is 2x faster to maintain than a collection of independent components. According to the lead developer: "Such architecture allowed us to reduce time-to-ship new features by 40%".

How we build the component system: 4 steps

Step 1: Unified initialization and common state

The most common mistake is creating a separate Vue application for each component. This leads to state desynchronization. We use Pinia with a single instance and mount components via data-attributes. Here’s how it looks:

// app.ts import { createApp, defineAsyncComponent } from 'vue' import { createPinia } from 'pinia' const componentRegistry: Record<string, any> = { 'cart-button': defineAsyncComponent(() => import('./components/cart/CartButton.vue')), 'add-to-cart': defineAsyncComponent(() => import('./components/catalog/AddToCartBtn.vue')), 'wishlist-btn': defineAsyncComponent(() => import('./components/catalog/WishlistBtn.vue')), 'compare-btn': defineAsyncComponent(() => import('./components/catalog/CompareBtn.vue')), 'reviews': defineAsyncComponent(() => import('./components/product/Reviews.vue')), 'size-advisor': defineAsyncComponent(() => import('./components/product/SizeAdvisor.vue')), } const pinia = createPinia() document.querySelectorAll('[data-vue-component]').forEach((el) => { const name = el.getAttribute('data-vue-component')! const Component = componentRegistry[name] if (!Component) return const props: Record<string, any> = {} for (const attr of el.attributes) { if (attr.name.startsWith('data-prop-')) { const propName = attr.name.replace('data-prop-', '').replace(/-./g, m => m[1].toUpperCase()) props[propName] = JSON.parse(attr.value) } } const app = createApp(Component, props) app.use(pinia) app.mount(el) }) 

Key point: a single Pinia instance is passed to all applications. This means the cartStore in the header and the cartStore on the product card are the same store—state is synchronized. Lazy loading via defineAsyncComponent + Vite automatically splits code into chunks, so CartDrawer.vue loads only on first interaction.

Step 2: API layer: one HTTP client for all

// api/client.ts const CSRF_TOKEN = (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement)?.content async function request<T>(url: string, options: RequestInit = {}): Promise<T> { const res = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', 'X-Bitrix-Csrf-Token': CSRF_TOKEN, ...options.headers, }, }) if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`) const data = await res.json() if (data.errors?.length) throw new Error(data.errors[0].message) return data } export const apiGet = <T>(url: string) => request<T>(url) export const apiPost = <T>(url: string, body: unknown) => request<T>(url, { method: 'POST', body: JSON.stringify(body) }) 

All components use apiGet / apiPost—a single point for adding auth headers, logging errors, interceptors. This simplifies debugging and ensures a uniform response format.

Step 3: Design system via CSS variables

Colors, fonts, spacing—through CSS variables that match the PHP template variables in Bitrix:

:root { --color-primary: #0052cc; --color-success: #00875a; --color-danger: #de350b; --spacing-sm: 8px; --spacing-md: 16px; --border-radius: 4px; } 

The Vue component Button.vue uses these variables—visually compatible with the rest of the site. Any token change in the Bitrix template automatically applies to the components.

Step 4: How to test the system?

Unit tests for Pinia stores with Vitest:

// stores/cartStore.test.ts import { setActivePinia, createPinia } from 'pinia' import { useCartStore } from './cartStore' describe('cartStore', () => { beforeEach(() => setActivePinia(createPinia())) it('adds a product to the cart', async () => { const store = useCartStore() await store.add(123, 1) expect(store.items).toHaveLength(1) expect(store.count).toBe(1) }) }) 

Component tests via Vue Test Utils + Vitest. The systematic approach allows testing both business logic and rendering, giving confidence during refactoring.

Deliverables Overview

Deliverable Description
Architecture documentation Integration scheme, component diagram, stores and API description
Component source code Implemented Vue components with lazy loading
Configured Vite bundler Configuration, code splitting, minification
Tests Unit tests for Pinia stores and components, integration tests for API
Guide for adding new components Developer instructions
Support for 2 weeks Consultations and bug fixes after delivery

Approximate timelines and cost

Scope What’s included Duration Cost (rubles)
Basic system (3–5 components) Initialization, Pinia, API layer, UI base 3–5 weeks 150,000–250,000
Full system + cart, wishlist, compare, reviews 6–10 weeks 350,000–550,000
+ Design system, tests, CI + tokens, Vitest, auto-build +2–3 weeks +100,000–150,000

Cost is calculated individually—depends on integration complexity and number of components.

Checklist: common mistakes when integrating Vue into Bitrix
  • Creating multiple createApp—use a single Pinia instance.
  • Storing tokens in localStorage—use a meta tag for CSRF.
  • Missing a unified API layer—catch errors in one place.
  • Ignoring code splitting—the initial bundle grows to a megabyte.
  • Mixing component logic and presentation—separate stores and views.

This architecture is ideal for Bitrix frontend Vue development and helps optimize Vue components for maintainability.

Summary

A component system is an investment in maintainability. Without it, the first component is quick to write, but the tenth is painful. With architecture, each new component takes 2–3 hours instead of 2–3 days. A systematic approach reduces maintenance costs by 30–50% and accelerates the delivery of new features.

Contact us to discuss your project’s architecture. Get a consultation on integrating Vue.js into Bitrix—we’ll show you how to save time and money. We guarantee quality and deadlines.

See also: Vue.js on Wikipedia