Структура крупных проектов

Quasar — это фреймворк на основе Vue.js, который позволяет создавать масштабируемые веб-приложения, SPA, SSR, PWA, мобильные приложения через Cordova или Capacitor и десктопные приложения с Electron. При разработке крупных проектов критически важно придерживаться строгой архитектуры, чтобы обеспечить масштабируемость, поддерживаемость и высокую производительность.


Разделение приложения на модули

Ключевое правило — разделение кода на логические модули. Каждый модуль должен иметь собственный набор компонентов, сервисов, маршрутов и стилей. Структура может выглядеть так:

src/
├── components/        # Общие компоненты
├── layouts/           # Основные макеты страниц
├── pages/             # Страницы приложения
├── router/            # Настройка маршрутов
├── store/             # Vuex-модули
├── services/          # Логика работы с API и бизнес-логика
├── boot/              # Инициализация сторонних библиотек и плагинов
└── assets/            # Стили, изображения и шрифты

Принципы модульного подхода:

  • Каждый модуль изолирован от других, минимально зависит от глобальных переменных.
  • Компоненты внутри модуля могут использовать общие утилиты и сервисы.
  • Vuex-хранилище структурируется по модулям с именованными пространствами (namespaced), что предотвращает коллизии имен и упрощает поддержку.

Использование Layouts и Pages

Quasar предоставляет мощный механизм layouts, который позволяет централизованно управлять общей структурой страниц. Например, общий шапка и боковое меню реализуются в layout, а конкретный контент — в pages.

Пример layout:

<template>
  <q-layout view="lHh Lpr lFf">
    <q-header elevated>
      <q-toolbar>
        <q-toolbar-title>Название приложения</q-toolbar-title>
      </q-toolbar>
    </q-header>

    <q-drawer v-model="drawer" show-if-above>
      <q-list>
        <q-item to="/dashboard">Dashboard</q-item>
        <q-item to="/settings">Settings</q-item>
      </q-list>
    </q-drawer>

    <q-page-container>
      <router-view />
    </q-page-container>
  </q-layout>
</template>

Особенности использования layouts в больших проектах:

  • Разделение layout по типам страниц (например, admin, auth, public).
  • Использование slot для динамического контента.
  • Управление состоянием глобальных элементов (например, бокового меню) через Vuex или Composition API.

Управление состоянием с Vuex

Для крупных приложений крайне важно грамотно структурировать хранилище Vuex. Основные рекомендации:

  1. Модульность: отдельный модуль на функциональный блок (например, user, products, orders).
  2. Namespaced modules: предотвращает конфликт имен и делает код более читаемым.
  3. Getter, Mutation, Action: отделение вычисляемых свойств, синхронных изменений и асинхронных операций.
  4. Ленивая загрузка модулей: при необходимости динамически подключать Vuex-модули для уменьшения времени старта.

Пример Vuex-модуля:

export const user = {
  namespaced: true,
  state: () => ({
    profile: null,
    token: null
  }),
  getters: {
    isAuthenticated: (state) => !!state.token
  },
  mutations: {
    setProfile(state, profile) {
      state.profile = profile
    },
    setToken(state, token) {
      state.token = token
    }
  },
  actions: {
    async login({ commit }, credentials) {
      const response = await api.login(credentials)
      commit('setToken', response.token)
      commit('setProfile', response.user)
    }
  }
}

Организация сервисов и утилит

Все взаимодействия с API и бизнес-логика должны быть вынесены в services:

src/
└── services/
    ├── api.js        # Общий API-клиент
    ├── userService.js
    └── productService.js

Рекомендации:

  • Использовать один общий API-клиент для всех запросов (axios, fetch) с централизованной обработкой ошибок и токенов.
  • Разделять бизнес-логику и вызовы API, чтобы компоненты оставались максимально простыми.
  • Для утилитарных функций создать отдельный каталог utils.

Пример сервиса:

import api from './api'

export const userService = {
  async getProfile() {
    return await api.get('/user/profile')
  },
  async updateProfile(data) {
    return await api.put('/user/profile', data)
  }
}

Boot-файлы для инициализации

Quasar предоставляет механизм boot-файлов, который позволяет инициализировать сторонние библиотеки, плагины или глобальные объекты перед стартом приложения.

Пример boot/axios.js:

import { boot } from 'quasar/wrappers'
import axios from 'axios'

export default boot(({ app, store }) => {
  app.config.globalProperties.$axios = axios

  axios.interceptors.request.use(config => {
    const token = store.state.user.token
    if (token) config.headers.Authorization = `Bearer ${token}`
    return config
  })
})

Роутинг и Lazy Loading

Quasar использует Vue Router, что позволяет:

  • Разделять маршруты по модулям.
  • Использовать ленивую загрузку страниц (dynamic import) для ускорения первого рендера.
  • Гибко настраивать guard’ы для авторизации.

Пример маршрута с lazy-loading:

const routes = [
  {
    path: '/dashboard',
    component: () => import('pages/Dashboard.vue'),
    meta: { requiresAuth: true }
  },
  {
    path: '/login',
    component: () => import('pages/Login.vue')
  }
]

Стилизация и SCSS-модули

Для крупных приложений критически важно организованное управление стилями:

  • Глобальные переменные и миксины в src/css или src/styles.
  • Компоненты используют scoped SCSS для локальных стилей.
  • Темизация Quasar через quasar.conf.js с возможностью динамической смены темы.

Пример глобальных переменных SCSS:

// src/css/variables.scss
$primary-color: #1976d2;
$secondary-color: #424242;
$border-radius: 4px;

Тестирование и документация

  • Для крупных проектов необходимо интегрировать модульное тестирование компонентов и сервисов (Jest, Vue Test Utils).
  • Документация компонентов с использованием Storybook позволяет создавать визуальный справочник UI-элементов.
  • Линтеры и Prettier обеспечивают единый стиль кода.

Структурированный подход, модульность, грамотное использование Vuex, сервисов, boot-файлов и ленивой загрузки страниц позволяет создавать масштабируемые приложения на Quasar, которые легко поддерживать и расширять.