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

Организация файлов и структура проекта Vue.js

Автор

Олег Марков

Введение

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

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

Что такое структура проектов во Vue.js

Краткое общее описание

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

Если вы когда-либо создавали проект через Vue CLI, системы сборки типа Vite, или вручную — вы наверняка видели схожие шаблоны директорий. Вот пример базовой структуры, которую создает Vue CLI:

my-vue-project/
├─ node_modules/
├─ public/
│  └─ index.html
├─ src/
│  ├─ assets/
│  ├─ components/
│  ├─ App.vue
│  ├─ main.js
├─ .gitignore
├─ package.json
├─ README.md

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

Корневые директории и их назначение

Папка public

Это место для статичных ресурсов, которые не будут проходить через систему сборки Webpack или Vite. Сюда относят файлы, которые как есть попадут в итоговую сборку: favicon иконки, robots.txt, index.html.

Пример:

  • public/favicon.ico — иконка сайта в браузере.
  • public/index.html — главный HTML-файл с точкой монтирования приложения.

Почему это важно? Любое содержимое внутри public скопируется на сервер как есть, без изменений.

Папка src

Это главный "рабочий" каталог, где находится весь исходный код приложения: компоненты, стили, модули состояния, страницы и утилиты.

Основные подпапки:

  • assets/ — изображения, шрифты, статические стили.
  • components/ — переиспользуемые элементы Vue-компонентов.
  • views/ или pages/ — компоненты-страницы, которые используются роутером.
  • router/ — конфигурация маршрутизации (например, index.js с описанием путей).
  • store/ — управление состоянием приложения (Vuex, Pinia).
  • App.vue — корневой компонент (шаблон обертки для всего приложения).
  • main.js или main.ts — точка входа в приложение.

Ниже вы увидите развернутую структуру, рекомендованную для проектов средней и высокой степени сложности.

Пример расширенной структуры Vue.js приложения

src/
├─ assets/
│  ├─ styles/
│  │  └─ main.scss
│  └─ images/
├─ components/
│  ├─ BaseButton.vue
│  └─ TheHeader.vue
├─ views/
│  ├─ HomeView.vue
│  └─ AboutView.vue
├─ router/
│  └─ index.js
├─ store/
│  └─ index.js
├─ utils/
│  └─ helpers.js
├─ App.vue
├─ main.js

Пояснения:

  • assets/styles/main.scss — глобальные стили.
  • components/BaseButton.vue — базовый компонент для кнопок.
  • utils/helpers.js — вспомогательные функции.

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

Почему стоит дробить компоненты

Vue.js построен вокруг компонентов: модульных, переиспользуемых блоков интерфейса. Разбивка компонентов помогает вам держать код читабельным, редко встречаться с конфликтами имен и ускоряет процесс переиспользования.

Категории компонентов

  • Базовые (Base, App) — используют префиксы для обозначения (BaseButton, AppLogo).
  • Макросоставные (TheSidebar, TheHeader) — определяют основные части макета сайта.
  • Функциональные или логические — специфичны для одной задачи или домена (UserProfile, TaskCard).

Пример базового компонента

Вот так может выглядеть универсальная кнопка:

<!-- components/BaseButton.vue -->
<template>
  <button :class="type" @click="$emit('click')">
    <slot/>
  </button>
</template>

<script>
export default {
  name: 'BaseButton',
  props: {
    type: {
      type: String,
      default: 'primary' // Используется CSS класс для стиля кнопки
    }
  }
}
</script>

<style scoped>
.primary { background: blue; color: #fff; }
.secondary { background: gray; color: #222; }
</style>

Теперь вы можете использовать <BaseButton> в разных местах, не дублируя логику и стили.

Группировка компонентов по доменам

В проектах посложнее иногда рекомендуют организовывать компоненты по фичам (feature-based structure):

src/
├─ features/
│  ├─ auth/
│  │  ├─ Login.vue
│  │  └─ Register.vue
│  └─ profile/
│     ├─ ProfileEdit.vue
│     └─ AvatarUpload.vue

Такой подход облегчает поддержку и масштабирование, поскольку все компоненты одной сущности лежат в одном месте.

Организация страниц (Views или Pages)

Если вы используете vue-router, каждая страница должна быть отдельным компонентом чаще всего, крупным Vue-файлом. Для них обычно создают папку views или pages:

src/
├─ views/
│  ├─ HomeView.vue
│  ├─ AboutView.vue
│  └─ UserProfile.vue

Здесь страницы не подразумевают переиспользования (в отличие от компонентов). Это конечные пункты маршрутов.

Пример маршрутизации:

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

const routes = [
  { path: '/', name: 'Home', component: HomeView },
  { path: '/about', name: 'About', component: AboutView }
]

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

export default router

Здесь каждый путь ведет к конкретному компоненту страницы.

Организация состояния (Store)

В современных проектах Vue.js чаще применяют либо Vuex, либо Pinia. Обычно состояние размещают в папке store или stores.

Пример структуры c Pinia: src/ ├─ stores/ │ └─ user.js

user.js: ```js import { defineStore } from 'pinia'

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

Как видно, папка долна содержать отдельные модули для разных аспектов состояния, такие как user, products и так далее.

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

Где хранить стили

Глобальные стили обычно держат в src/assets/styles/ или — для малых проектов — прямо в App.vue.

Используйте препроцессоры (Sass, Less) для структурирования больших файлов стилей, разделяйте их по смыслу: variables, mixins, base, layout и так далее.

Пример импортов стилей в главный файл:

// assets/styles/main.scss
@import 'variables';
@import 'mixins';
@import 'base';
@import 'layout';

В каждом компоненте стили можно хранить как scoped (действуют только в рамках этого компонента).

Организация утилит и вспомогательных функций

В папке utils часто хранят функции, которые используются сразу в нескольких местах приложения.

Пример: js // utils/date.js export function formatDate(date) { // Преобразует дату к виду ДД.ММ.ГГГГ return new Date(date).toLocaleDateString('ru-RU') } Использование в компоненте: ```js import { formatDate } from '@/utils/date'

setup() { return { formatted: formatDate('2024-04-19T14:30:00.000Z') } } ```

Логическая группировка по областям приложения

Когда проект становится большим, структура по прямой специализации (assets, components, views) может уже не подходить. Решение — группировка по областям (feature or domain-based):

src/
├─ features/
│  ├─ cart/
│  │  ├─ CartView.vue
│  │  ├─ CartItem.vue
│  │  └─ cartStore.js
│  └─ product/
│     ├─ ProductList.vue
│     └─ productStore.js

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

Как организовать логику для тестов

Для модульных тестов создайте папку tests/unit/, для end-to-end — tests/e2e/. Обычно структура тестов повторяет структуру исходников.

tests/
├─ unit/
│  ├─ components/
│  ├─ views/

Тесты обычно именуют как ComponentName.spec.js.

Советы по масштабируемости

  • Следите за размером папок: если в папке становится слишком много файлов одного типа — делите ее дальше или переименовывайте по смыслу.
  • Разделяйте осмысленно: не бойтесь создавать новые уровни вложенности, если это облегчает навигацию.
  • Используйте alias для путей (@/components/ComponentName.vue), чтобы импорты не стали сложными при большом количестве уровней.

Поддержка TypeScript

Если используете Vue с TypeScript, структура аналогична, только файлы компонентов могут иметь расширение .vue, а логика — .ts или .d.ts.

Пример: src/ ├─ components/ │ └─ TypedButton.vue ├─ types/ │ └─ user.ts

Вынесите общие типы в src/types.

Заключение

Грамотная организация файлов и папок в проекте Vue.js играет ключевую роль в поддерживаемости и масштабируемости вашего приложения. На старте проекта важно выбрать стратегию структуры: классическое разделение компонентов или группировка по областям (features), и придерживаться выбранного подхода по мере роста. Такой подход поможет вашей команде экономить время, избегать дублирования кода и успешно развивать проект в долгосрочной перспективе.


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

Как подключить глобальную библиотеку стилей (например, Bootstrap или Tailwind) в проект Vue.js?

Ответ:
Добавьте нужную библиотеку через npm (npm install bootstrap), после чего импортируйте CSS-файл нужной библиотеки в main.js или в главный файл стилей (assets/styles/main.scss). Например: js // main.js import 'bootstrap/dist/css/bootstrap.min.css' В случае c Tailwind — создайте файл стилей, например, src/assets/styles/tailwind.css, и импортируйте его в точке входа (main.js).


Как разделять сторы в Vuex или Pinia между областями бизнес-логики?

Ответ:
Создавайте по отдельному модулю стор для каждой области. Например, для пользователей — src/stores/user.js, для корзины — src/stores/cart.js. В Pinia каждый store — отдельная функция через defineStore, а в Vuex — отдельный модуль в modules/.


Как добавить alias для импортов (например, чтобы можно было использовать @/components/...)?

Ответ:
Для Vite отредактируйте vite.config.js, добавьте в resolve.alias: ```js import { fileURLToPath, URL } from 'node:url'

export default defineConfig({ resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } } }) `` Для Vue CLI используйте настройку вvue.config.js` (или используйте по умолчанию @, который уже нацелен на src).


Как организовать вложенные маршруты (Nested Routes) и компоненты для них?

Ответ:
В router/index.js для маршрута используйте свойство children, где указываете дочерние маршруты: js const routes = [ { path: '/dashboard', component: DashboardView, children: [ { path: 'stats', component: StatsView } ] } ] В компоненте DashboardView используйте <router-view/> для вывода дочерних компонентов.


Где хранить конфиденциальные данные и переменные окружения (например, API ключи)?

Ответ:
Создайте файл .env в корне и определите переменные с префиксом VUE_APP_ (или VITE_ для Vite):

VITE_API_KEY=your_api_key_here

Получайте из кода через import.meta.env.VITE_API_KEY (Vite) или process.env.VUE_APP_MY_KEY (Vue CLI). Не коммитьте реальные ключи в репозиторий!

Стрелочка влевоОбработка пользовательского ввода в Vue.jsКомпоненты Vue создание передача данных события и emitСтрелочка вправо

Все гайды по 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
Открыть базу знаний