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

Работа с модулями и пакетами в Vue

Автор

Олег Марков

Введение

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

В экосистеме Vue модулями принято называть, в первую очередь, отдельные компоненты, Vuex-модули, а также самостоятельные пакеты с логикой и утилитами, которые можно подключать в различные проекты. Пакеты же чаще всего ассоциируются с внешними (или внутренними) npm-библиотеками, которые предоставляют те или иные возможности для вашего приложения.

В этой статье я расскажу:

  • Как устроена модульная архитектура в Vue
  • Как создавать и использовать модули на разных уровнях (от компонентов до Vuex)
  • Как подключать npm-пакеты и управлять зависимостями
  • Как организовать собственный пакет для переиспользования в различных проектах
  • Лучшие практики — что стоит применять в крупных и небольших приложениях, чтобы ваш код был поддерживаемым

Поддержку модулей и пакетов обеспечивает не только сам Vue, но и экосистема вокруг — Node.js, npm, Vite, webpack и др. Давайте разбираться по порядку.


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

Почему важна модульность

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

Vue изначально проектируется как фреймворк, ориентированный на компонентность. Каждый компонент можно воспринимать как модуль — он выделяет отдельный фрагмент функционала (кнопку, форму, страницу, диалог и др.).

Что считается модулем в Vue

В контексте Vue модулем часто называют:

  • Vue-компонент — файл .vue с шаблоном, скриптом и стилями
  • Vuex-модуль — часть хранилища приложения, изолирующая логику работы с определенными сущностями (например, users, cart, products)
  • Модуль роутера — группа маршрутов, вынесенная в отдельный файл
  • Логическая утилита или сервис — JS/TS-модуль, предоставляющий функции, классы или константы

Всё это структурируется внутри каталогов проекта.

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

Вот пример типичной структуры каталога для Vue проекта (предположим, это проект на Vue CLI или Vite):

src/
├── assets/
├── components/
│   ├── BaseButton.vue
│   ├── UserCard.vue
│   └── ...
├── views/
│   ├── HomePage.vue
│   ├── UserProfile.vue
│   └── ...
├── store/
│   ├── index.js
│   ├── modules/
│   │   ├── user.js
│   │   └── products.js
│   └── ...
├── router/
│   └── index.js
├── utils/
│   └── api.js
├── App.vue
└── main.js

Комментарии к структуре:

  • components/ — здесь размещаются переиспользуемые компоненты
  • views/ — страницы или крупные логические блоки (view-level компоненты)
  • store/ — хранилище данных, разделённое на модули
  • router/ — маршрутизация, можно делить конфиги на части
  • utils/ — вспомогательные функции, сервисы, API-слои

Благодаря модульности, вы легко можете передавать отдельные директории в другие проекты, упрощая разработку.

Импорт компонентов (модулей)

Компоненты можно импортировать как в корневой компонент App.vue, так и друг в друга:

// Импорт компонента в другом компоненте
import BaseButton from '@/components/BaseButton.vue'

export default {
  components: {
    BaseButton,
  },
  // ...
}

// @ — сокращение для src (работает только при соответствующей настройке в сборщике)

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


Использование Vuex-модулей

Vuex (до Vue 3 Pinia, в новых проектах используют чаще именно Pinia) — хранилище состояний, поддерживает модульную организацию.

Зачем нужны Vuex-модули

В реальной задаче у вас может быть десятки сущностей: пользователи, товары, заказы, настройки, фильтры. Хранить все состояние и логику в общем объекте store нерационально.

Модули позволяют отделить логику работы с каждой сущностью в отдельный файл:

// store/modules/user.js
export default {
  namespaced: true, // Включаем пространство имён для изоляции
  state: {
    profile: null,
  },
  mutations: {
    setProfile(state, profile) {
      state.profile = profile
    },
  },
  actions: {
    fetchProfile({ commit }) {
      // Имитация запроса данных
      commit('setProfile', { name: 'Ivan', age: 28 })
    },
  },
}

// store/modules/products.js
export default {
  namespaced: true,
  state: {
    list: [],
  },
  mutations: {
    setProducts(state, products) {
      state.list = products
    },
  },
  actions: {
    fetchProducts({ commit }) {
      // Имитация запроса товаров
      commit('setProducts', [
        { id: 1, title: 'Телефон' },
        { id: 2, title: 'ПК' },
      ])
    },
  },
}

Подключение модулей в store

Для подключения модулей достаточно описать их в store/index.js:

import Vue from 'vue'
import Vuex from 'vuex'

import user from './modules/user'
import products from './modules/products'

Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    user,
    products,
  },
})

Теперь обращение к данным идет по схеме: store.state.user.profile, store.dispatch('user/fetchProfile').

В чем польза модульности

  • Облегчает тестирование и сопровождение
  • Позволяет нескольким разработчикам работать над отдельными областями приложения
  • Модули могут быть динамически подключены или отключены

Работа с пакетами npm в проекте Vue

Что такое пакет

Пакет (npm-пакет) — это библиотека с определённой логикой (готовые компоненты, хелперы, стили), которую можно ставить как зависимость через npm или yarn.

Как добавить внешний пакет в проект

Допустим, вам нужна библиотека UI-компонентов element-plus:

npm install element-plus

или

yarn add element-plus

Затем подключаете её в коде:

import { createApp } from 'vue'
import App from './App.vue'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

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

Теперь все компоненты из Element Plus становятся доступны. Часто сторонние пакеты предоставляют инструкции по интеграции в документации.

Импорт собственных модулей и утилит

Вы можете без npm создавать свои JS/TS-модули и подключать их с помощью относительных путей:

// utils/math.js
export function sum(a, b) {
  return a + b
}

// components/SomeComponent.vue
import { sum } from '@/utils/math.js'

export default {
  mounted() {
    const result = sum(2, 3) // 5
    // ...
  }
}

Создание собственных npm-пакетов для Vue

Иногда возникает задача — вынести часть функционала или компоненты в переиспользуемый npm-пакет, чтобы подключать его в несколько проектов или делиться им с другими разработчиками.

Простейшая структура собственного пакета

Допустим, вы хотите сделать свой набор компонентов.

my-vue-lib/
├── src/
│   ├── MyButton.vue
│   └── index.js
├── package.json
├── README.md
└── ...

пример src/index.js:

// src/index.js
import MyButton from './MyButton.vue'

export { MyButton } // Named export

export default {
  install(app) {
    // Регистрация компонента глобально
    app.component('MyButton', MyButton)
  },
}

package.json

{
  "name": "my-vue-lib",
  "version": "1.0.0",
  "main": "src/index.js",
  "peerDependencies": {
    "vue": "^3.0.0"
  }
}

Локальное подключение собственного пакета

Чтобы попробовать использование пакета в реальном проекте (до публикации на npm), воспользуйтесь npm link или укажите путь напрямую:

npm install ../my-vue-lib

Теперь компоненты пакета доступны как обычные npm-зависимости.

Публикация пакета в npm

Публиковать пакет можно с помощью нескольких шагов:

  1. Зарегистрируйтесь на https://npmjs.com
  2. В терминале: npm login npm publish
  3. После публикации ваш пакет становится доступен для установки (npm install my-vue-lib)

Упаковка модулей: ESM и CommonJS

Обратите внимание: если вы разрабатываете npm-пакет для Vue 3+, используйте формат ESM (ECMAScript Modules). Пример экспорта:

// src/index.js
export { default as MyButton } from './MyButton.vue'
export { default as MyInput } from './MyInput.vue'

Сборку пакета для публикации проще делать с помощью инструментов вроде Vite, Rollup или webpack.


Ленивая загрузка модулей

Чем больше приложение, тем дольше загружается первая страница. В Vue (при сборке с использованием webpack или Vite) многие модули или компоненты можно загружать «лениво», то есть только тогда, когда действительно требуется.

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

export default {
  components: {
    // Компонент подгружается только когда реально нужен
    UserCard: () => import('@/components/UserCard.vue'),
  },
}

Если вы используете роутер Vue Router 3+ (или 4+ для Vue 3), ленивая загрузка маршрутов выглядит так:

// router/index.js
const UserProfile = () => import('@/views/UserProfile.vue')

const routes = [
  {
    path: '/user',
    component: UserProfile
  },
  // ...
]

Что это даёт

  • Улучшает время старта (первая страница быстрее)
  • Разделяет ваш код на чанки и загружает их по требованию

Автоматизация организации модулей и импортов

В крупных командах часто используют плагины и инструменты, которые помогают автоматизировать импорт компонентов и других модулей:

  • unplugin-vue-components — автогенерация импортов компонентов. Не нужно писать import вручную.
  • vite-plugin-pages — автогенерация маршрутов на основе структуры файлов.

Пример автоимпорта:

npm install -D unplugin-vue-components

Конфиг для Vite (vite.config.js):

import Components from 'unplugin-vue-components/vite'

export default {
  plugins: [
    Components({
      dirs: ['src/components'],
      // можно указать резолверы для ElementUI, Vuetify и др.
    }),
  ]
}

Стилизация и разделение CSS по модулям

Каждый компонент Vue может содержать секцию <style>. Добавляя атрибут scoped, вы делаете стили применимыми только к данному модулю-компоненту:

<template>
  <button class="my-button">Кликни меня</button>
</template>

<style scoped>
.my-button {
  background: green;
  color: white;
}
</style>

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


Лучшие практики модульной архитектуры в Vue

  1. Один компонент — одно назначение
    Компонент или модуль должен отвечать за одну задачу.

  2. Изоляция зависимостей
    Используйте scoped модули там, где возможно (Vuex, стили, утилиты).

  3. Плоская структура и короткие пути
    Не помещайте слишком много уровней вложенности: иерархия должна быть понятной.

  4. Переиспользование — через пакеты
    Если вы видите, что компоненты повторяются в разных проектах — оформляйте их в npm-пакеты.

  5. Динамические импорты для ленивой загрузки
    Используйте ленивая загрузка маршрутов, компонентов, чтобы оптимизировать производительность.

  6. Инкапсуляция логики
    Выносите “грязную” работу (API-запросы, манипуляции с данными) в отдельные service-модули.

  7. Ведите документацию по каждому пакету/модулю
    Это упростит работу вашей команды и ускорит онбординг новых участников.


Модули и пакеты — основа любой современной архитектуры на Vue. Такой подход не только делает ваш проект чище, но и позволяет уверенно работать как в небольших, так и в очень крупных приложениях.


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

Как организовать переиспользуемый модуль API запросов?

Создайте файл api.js в директории utils/ или services/:

// utils/api.js
import axios from 'axios'

const apiClient = axios.create({
  baseURL: '/api',
  timeout: 5000,
})

export default {
  getUser(id) {
    return apiClient.get(`/user/${id}`)
  },
  getProducts() {
    return apiClient.get('/products')
  },
  // …
}

Импортировать и использовать можно в любом компоненте.

Как импортировать модуль только когда реально нужен?

Воспользуйтесь динамическим импортом:

const MyDialog = () => import('@/components/MyDialog.vue')
// или в методе: const module = await import('@/utils/heavy.js')

Как подключать приватные npm-пакеты внутри компании?

Опубликуйте пакет с нужным флагом или настройте приватный npm-реестр (например, с помощью Verdaccio или GitHub Packages), затем добавьте ссылку на реестр в .npmrc и ставьте пакет по названию.

Как сделать алиасы (например, @/ для папки src) в Vite/webpack?

В vite.config.js:

import { defineConfig } from 'vite'
import path from 'path'

export default defineConfig({
  resolve: {
    alias: { '@': path.resolve(__dirname, 'src') },
  },
})

Для webpack — похожее свойство resolve.alias в конфиге.

Как протестировать модуль или компонент из пакета локально до публикации?

Используйте npm link (или yarn link) в папке пакета, а затем — в вашем проекте. Это создаст символическую ссылку. После любого изменения в пакете перезапустите сборку зависимого проекта, чтобы он увидел обновления.

Стрелочка влево5 правил использования Inertia с Vue и LaravelИнструкция по работе с grid на VueСтрелочка вправо

Все гайды по Vue

Руководство по валидации форм во Vue.jsИнтеграция Tiptap для создания редакторов на VueРабота с таблицами во Vue через TanStackИнструкция по установке и компонентам Vue sliderУправление пакетами Vue js с помощью npmУправление пакетами и node modules в Vue проектахКак использовать meta для улучшения SEO на VueПолный гайд по компоненту messages во Vuejs5 правил использования Inertia с Vue и LaravelРабота с модулями и пакетами в VueИнструкция по работе с grid на VueGithub для Vue проектов - подробная инструкция по хранению и совместной работеНастройка ESLint для Vue проектов и поддержка качества кодаОбработка ошибок и отладка в Vue.jsРабота с конфигурационными файлами и скриптами VueИспользование Vue Devtools для отладки и мониторинга приложенийСоздание и настройка проектов Vue с помощью Vue CLI3 способа интеграции Chart.js с Vue для создания графиковРабота с Canvas во VueИнструкция по реализации календаря во VueРабота с Ant Design Vue для создания UI на Vue
Обзор и использование утилит Vue для удобной разработкиРабота с обновлениями компонента и жизненным циклом updateРазрешение конфликтов и ошибок с помощью Vue resolveИспользование 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 для современных интерфейсовКак обрабатывать async операции с Promise во VueИнтеграция Vue с серверной частью и HTTPS настройкамиИнтеграция 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
Открыть базу знаний