логотип PurpleSchool
логотип PurpleSchool

Создание и структурирование Vue.js приложения

Автор

Ирина Лазарева

Введение

Vue.js считается одним из наиболее простых и мощных фреймворков для создания современных интерфейсов. Его гибкость позволяет разрабатывать как небольшие виджеты, так и масштабные приложения. Однако с ростом приложения вы можете столкнуться с вопросами организации кода, поддерживаемости и масштабируемости. Грамотно структурировать Vue.js проект — это фундамент для эффективной разработки и командной работы.

В этой статье я покажу вам, как создать Vue.js приложение с нуля и организовать проект так, чтобы вы могли развивать его без хаоса в кодовой базе. Вы узнаете, как правильно распределить файлы по папкам, как работать с компонентами, роутингом и состоянием приложения. Я приведу кодовые примеры и объясню детали каждого этапа.

Начальная инициализация Vue.js приложения

Выбор инструментов

Начинать рекомендую с официального инструмента Vue CLI или с Vite, который стал стандартом для новых Vue 3 проектов.

  • Vue CLI хорош для проектов с требованиями к большой кастомизации.
  • Vite обеспечивает молниеносную сборку и горячую перезагрузку, подходит для большинства задач.

Для примера возьмём Vite + Vue 3, так как это самый быстрый и актуальный способ.

Создание проекта с помощью Vite

Откройте терминал и выполните:

npm create vite@latest my-vue-app -- --template vue
  • my-vue-app — это ваша будущая папка с проектом.
  • Флаг --template vue указывает, что нужен шаблон Vue.

Далее:

cd my-vue-app
npm install
npm run dev

Теперь локальный сервер запущен, и вы видите стартовую страницу Vue-приложения.

Структура начального проекта

Давайте посмотрим, какие файлы вы получаете сразу:

my-vue-app/
├─ public/
│  └─ favicon.svg
├─ src/
│  ├─ assets/
│  ├─ components/
│  ├─ App.vue
│  └─ main.js
├─ index.html
├─ package.json
├─ vite.config.js

На этом скелете дальше строится архитектура реального приложения.

Развернутая структура приложения

Почему важна структура?

Грамотная структура директорий упрощает навигацию по проекту, ускоряет онбординг новых участников и помогает избежать путаницы. Вам не придется терять время на поиски нужной функции или компонента. К тому же, хорошая структура облегчает автоматизацию, тестирование и масштабирование.

Базовая и расширенная структура

Предлагаю следующую схему, которую вы встретите во многих успешных проектах:

src/
├─ assets/          # Статические ресурсы (стили, изображения)
├─ components/      # Переиспользуемые компоненты
├─ views/           # Страницы приложения
├─ router/          # Файлы роутинга
├─ store/           # Централизованное состояние (Vuex, Pinia)
├─ services/        # Работа с API
├─ utils/           # Утилиты и хелперы
├─ composables/     # Композиционные функции (Vue 3)
├─ App.vue          # Корневой компонент
├─ main.js          # Точка входа

Давайте обсудим назначение каждой папки.

assets

Содержит изображения, иконки, стили и шрифты:

src/assets/logo.png
src/assets/styles/global.css

components

Здесь лежат микро-компоненты, которые можно использовать во многих местах, например, кнопки или карточки товаров:

src/components/BaseButton.vue
src/components/ProductCard.vue

views

Это страницы для роутинга. Например, главная и профиль пользователя:

src/views/HomeView.vue
src/views/ProfileView.vue

router

Здесь размещается настройка роутера:

src/router/index.js   // или router.js
Пример файла роутинга
// src/router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: HomeView
  },
  {
    path: '/profile',
    name: 'Profile',
    // Ленивая загрузка компонента
    component: () => import('../views/ProfileView.vue')
  }
]

const router = createRouter({
  history: createWebHistory(),
  routes
})

export default router

store

Здесь хранятся модули состояния. В Vue 3 чаще всего используется Pinia вместо Vuex.

Пример файла Pinia-стора
// src/store/user.js

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    name: '',
    authenticated: false
  }),
  actions: {
    login(name) {
      this.name = name
      this.authenticated = true
    },
    logout() {
      this.name = ''
      this.authenticated = false
    }
  }
})

services

Вынесите API-запросы и другую бизнес-логику.

// src/services/api.js

import axios from 'axios'

export function getUser(id) {
  // Получение информации о пользователе по id
  return axios.get(`/api/users/${id}`)
}

utils

Здесь находятся функции-помощники:

// src/utils/formatDate.js

export function formatDate(date) {
  // Преобразует дату в вид 'dd.mm.yyyy'
  const d = new Date(date)
  return `${d.getDate()}.${d.getMonth() + 1}.${d.getFullYear()}`
}

composables (в Vue 3)

В Vue 3 используются composables для повторного использования логики.

// src/composables/useToggle.js

import { ref } from 'vue'

export function useToggle(init = false) {
  // Возвращает реактивное состояние и функцию для его переключения
  const state = ref(init)
  function toggle() {
    state.value = !state.value
  }
  return { state, toggle }
}

Структура и написание компонентов

Однофайловые компоненты (Single File Components)

В Vue.js компонент обычно размещается в файле с расширением .vue. Такая структура делит компонент на три части:

  • <template> — шаблон разметки,
  • <script> — логика компонента,
  • <style> — непосредственные стили, часто с модификаторами scoped.

Пример простого компонента

<template>
  <button @click="increment">{{ count }}</button>
</template>

<script>
import { ref } from 'vue'

export default {
  setup() {
    // Создание реактивной переменной count
    const count = ref(0)
    function increment() {
      count.value++
    }
    return { count, increment }
  }
}
</script>

<style scoped>
button {
  padding: 10px 24px;
  font-size: 18px;
}
</style>

Организация крупных компонентов

Если компонент становится громоздким, разделите его на дочерние:

  • Вынесите части интерфейса или повторяющуюся логику в отдельные файлы в папке components/.
  • Используйте Base-префикс для базовых компонентов (BaseButton.vue, BaseInput.vue).

Использование props и событий

Vue-компоненты "общаются" между собой через props (пропсы) и события:

<!-- src/components/UserGreeting.vue -->
<template>
  <div @click="$emit('clicked')">Привет, {{ name }}!</div>
</template>

<script>
export default {
  props: {
    name: String
  }
}
</script>

Подключение роутинга и состояния

Роутинг: переход между страницами

В файле main.js регистрируем роутер:

// src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

createApp(App)
  .use(router)
  .mount('#app')

Состояние: глобальный store

Для глобального состояния современный выбор — Pinia:

// src/main.js

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'

const app = createApp(App)

app.use(createPinia())
app.use(router)
app.mount('#app')

Теперь вы можете использовать store в компонентах:

import { useUserStore } from '../store/user'

export default {
  setup() {
    const user = useUserStore()
    // user.login('Ирина')
    // user.logout()
    return { user }
  }
}

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

Использование глобальных, модульных и scoped-стилей

  • global.css кладём в assets и импортируем один раз в main.js.
  • В каждом компоненте используйте <style scoped>, если стили применимы только к этому компоненту.
  • Применяйте CSS-модули, если нужно исключить конфликты стилей в больших проектах.

Работа с ассетами

Импортировать изображения можно прямо в шаблонах или скриптах:

<template>
  <img :src="logo" alt="Логотип" />
</template>
<script>
import logo from '../assets/logo.png'

export default {
  setup() {
    return { logo }
  }
}
</script>

Тестирование и best practices

Где размещать тесты

Локализуйте тесты рядом с файлами компонентов или внутри отдельной папки tests/.

src/components/
  ├─ BaseButton.vue
  └─ __tests__/
       └─ BaseButton.spec.js

Советы по организации кода

  • Соблюдайте принцип "однофайловых компонентов": всё, что относится к одному компоненту — в одном файле.
  • Не копируйте код, а выносите повторяемую логику в composables или утилиты.
  • Именуйте компоненты в PascalCase (UserProfile.vue).
  • Используйте папки для модулей — по фичам и доменам для больших приложений.

Заключение

Создание Vue.js приложения начинается с грамотной и продуманной структуры — это обеспечивает максимум удобства и адаптивности проекта при его развитии. Используя современные инструменты вроде Vite и Pinia, комбинируя компоненты, роутинг, глобальное состояние и четкую структуру директорий, вы делаете приложение поддерживаемым и легким для расширения. Деление по принципу "views–components–store–services–utils–composables" позволит избежать хаоса в будущем, особенно если проект быстро растет или вы работаете в команде.


Частозадаваемые технические вопросы по теме статьи и ответы на них

1. Как подключить стороннюю библиотеку компонентов (например, Element Plus) в проекте на Vue 3?

Ответ:
Установите библиотеку через npm:
npm install element-plus
Импортируйте нужные компоненты и css в main.js:
```js import ElementPlus from 'element-plus' import 'element-plus/dist/index.css'

const app = createApp(App) app.use(ElementPlus) ``` Теперь вы можете использовать компоненты Element Plus в шаблонах.


2. Что делать, если роутер не работает — ссылки не меняют страницу?

Ответ:
Убедитесь, что вы правильно используете <router-view /> в App.vue, а навигацию осуществляете с помощью <router-link> или $router.push(). Проверьте, что пути указываются правильно в файле routes, и что роутер зарегистрирован в main.js через app.use(router).


3. Как работать с environment-переменными в Vite/Vue?

Ответ:
Создайте файл .env (или .env.local) в корне проекта.
Переменные должны начинаться с VITE_, например:
VITE_API_URL=https://api.example.com
В коде эти значения доступны через import.meta.env.VITE_API_URL.


4. Где лучше размещать глобальные фильтры и как их реализовать в Vue 3?

Ответ:
Вместо фильтров из Vue 2 используйте функции (например, в src/utils). Импортируйте и используйте их в компонентах либо регистрируйте как глобальные методы через provide/inject или app.config.globalProperties.


5. Как настроить абсолютные пути для импортов, чтобы не писать '../../../'?

Ответ:
В Vite настройте поле resolve.alias в файле vite.config.js:
js import { fileURLToPath, URL } from 'node:url' export default defineConfig({ resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } }) Теперь можно импортировать, например, @/components/MyComponent.vue.


Стрелочка влевоРабота со стилями и CSS в Vue js для красивых интерфейсовНастройка и сборка проектов Vue с использованием современных инструментовСтрелочка вправо

Все гайды по Vue

Работа с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueОбзор популярных шаблонов и стартовых проектов на VueКак организовать страницы и маршруты в проекте на VueСоздание серверных приложений на Vue с помощью Nuxt jsРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияНастройка и сборка проектов Vue с использованием современных инструментов
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование метода map в Vue для обработки массивовОбработка пользовательского ввода в Vue.jsОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitИспользование директив и их особенности на Vue с помощью defineСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в Vue
Открыть базу знаний