логотип 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Компоненты Vue создание передача данных события и emitСтрелочка вправо

Постройте личный план изучения Vue до уровня Middle — бесплатно!

Vue — часть карты развития Frontend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackУправление пакетами Vue js с помощью npmИнструкция по установке и компонентам Vue sliderУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsИспользование Vue Devtools для отладки и мониторинга приложенийРабота с конфигурационными файлами и скриптами VueРабота с модулями и пакетами в VueСоздание и настройка проектов Vue с помощью Vue CLIИнструкция по реализации календаря во VueРабота с Canvas во Vue3 способа интеграции Chart.js с Vue для создания графиковРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРазрешение конфликтов и ошибок с помощью Vue resolveРабота с обновлениями компонента и жизненным циклом updateИспользование query-параметров и их обработка в маршрутах VueЗагрузка и управление состоянием загрузки в VueИспользование библиотек Vue для расширения функционалаРабота с JSON данными в приложениях VueКак работать с экземплярами компонента Instance во VueПолучение данных и API-запросы во Vue.jsЭкспорт и импорт данных и компонентов в VueОбработка событий и их передача между компонентами VuejsГайд по defineEmits на Vue 3Понимание core функционала Vue и его применениеПонимание и применение Composition API в Vue 3Понимание и работа с компилятором VueКогда и как использовать $emit и call во VueВзаимодействие с внешними API через Axios в Vue
Веб приложения на Vue архитектура и лучшие практикиИспользование Vite для быстрого старта и сборки проектов на Vue 3Работа с URL и ссылками в приложениях на VueРабота с пользовательскими интерфейсами и UI библиотеками во VueОрганизация и структура исходных файлов в проектах VueИспользование Quasar Framework для разработки на Vue с готовыми UI-компонентамиОбзор популярных шаблонов и стартовых проектов на VueИнтеграция Vue с PHP для создания динамичных веб-приложенийКак организовать страницы и маршруты в проекте на VueNuxt JS и Vue 3 для SSR приложенийСоздание серверных приложений на Vue с помощью Nuxt jsИспользование Vue Native для разработки мобильных приложенийОрганизация и управление индексной страницей в проектах VueИспользование Docker для контейнеризации приложений на VueИнтеграция Vue.js с Django для создания полноценных веб-приложенийСоздание и работа с дистрибутивом build dist Vue приложенийРабота со стилями и CSS в Vue js для красивых интерфейсовСоздание и структурирование Vue.js приложенияКак исправить ошибку cannot find module vueНастройка и сборка проектов Vue с использованием современных инструментовИнтеграция Vue с Bitrix для корпоративных решенийРазработка административных панелей на Vue js
5 библиотек для создания tree view во VueИнтеграция Tailwind CSS с Vue для современных интерфейсовИнтеграция Vue с серверной частью и HTTPS настройкамиКак обрабатывать async операции с Promise во VueИнтеграция Node.js и Vue.js для разработки приложенийРуководство по интеграции Vue js в NET проектыПримеры использования JSX во VueГайд по импорту и регистрации компонентов на VueМногоязычные приложения на Vue с i18nИнтеграция FLIR данных с Vue5 примеров использования filter во Vue для упрощения разработки3 примера реализации drag-and-drop во Vue
Управление переменными и реактивными свойствами во VueИспользование v for и slot в VueПрименение v-bind для динамической привязки атрибутов в VueУправление пользователями и их данными в Vue приложенияхСоздание и использование UI Kit для Vue приложенийТипизация и использование TypeScript в VuejsИспользование шаблонов в Vue js для построения интерфейсовИспользование Swiper для создания слайдеров в VueРабота со стилями и стилизацией в VueСтруктура и особенности Single File Components SFC в VueРабота со SCSS в проектах на Vue для стилизацииРабота со скроллингом и прокруткой в Vue приложенияхПрименение script setup синтаксиса в Vue 3 для упрощения компонентовИспользование scoped стилей для изоляции CSS в компонентах Vue3 способа улучшить навигацию Vue с push()Обработка запросов и асинхронных операций в VueПонимание и использование provide inject для передачи данных между компонентамиПередача и использование props в Vue 3 для взаимодействия компонентовПередача данных между компонентами с помощью props в Vue jsУправление property и функциями во Vue.jsРабота со свойствами компонентов VueУправление параметрами и динамическими данными во VueРабота с lifecycle-хуком onMounted во VueОсновы работы с объектами в VueПонимание жизненного цикла компонента Vue js на примере mountedИспользование модальных окон modal в Vue приложенияхИспользование методов в компонентах Vue для обработки логикиИспользование метода map в Vue для обработки массивовИспользование хуков жизненного цикла Vue для управления состоянием компонентаРабота с ключами key в списках и компонентах VueОбработка пользовательского ввода в Vue.jsРабота с изображениями и их оптимизация в VueИспользование хуков жизненного цикла в VueОрганизация сеток и гридов для верстки интерфейсов на VueСоздание и управление формами в VueОрганизация файлов и структура проекта Vue.jsКомпоненты Vue создание передача данных события и emitРабота с динамическими компонентами и данными в Vue3 способа манипулирования DOM на VueРуководство по div во VueИспользование директив в Vue и их расширенные возможностиОсновы и применение директив в VueИспользование директив и их особенности на Vue с помощью defineИспользование компонентов datepicker в Vue для выбора датОрганизация циклов и итераций во VueКак работает компиляция Vue CoreСоздание и использование компонентов в Vue JSОбработка кликов и пользовательских событий в VueИспользование классов в Vue для организации кода и компонентовИспользование директивы checked для управления состоянием чекбоксов в VueГайд на checkbox компонент во VueОтображение данных в виде графиков с помощью Vue ChartСоздание и настройка кнопок в VueСоздание и настройка кнопок в Vue приложенияхРабота с lifecycle-хуками beforeCreate и beforeMount во VueИспользование массивов и методов их обработки в VueИспользование массивов и их обработка в Vue
Использование Vuetify для создания современных интерфейсов на VueИспользование transition во VueТестирование компонентов и приложений на VueРабота с teleport для управления DOM во VueПять шагов по настройке SSR в VuejsИспользование Shadcn UI компонентов с Vue для продвинутых интерфейсовИспользование router-link для навигации в Vue RouterКак использовать require в Vue для динамического импорта модулейРабота с динамическим рендерингом и виртуальным DOM на Vue.jsИспользование ref для управления ссылками и реактивностью в Vue 3Использование Vue Pro и его преимущества для профессиональной разработкиРуководство по nextTick для работы с DOMСоздание и использование компонентов с помощью Vue js и CУправление состоянием и реактивностью через inject и provideДинамическое обновление компонентов и данных на VueГлубокое изучение документации Vue и как эффективно её использоватьИспользование Crystal с Vue для разработкиИспользование вычисляемых свойств для динамического отображения данных на Vue jsОптимизация производительности и предупреждения в Vue
Открыть базу знаний

Лучшие курсы по теме

изображение курса

Vue 3 и Pinia

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.9
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Next.js - с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий