Перейти к содержимому

2. Установка и Vite

Vite — это не просто сборщик, это машина времени для разработки! Пока Webpack запускается 30 секунд и пересобирает весь проект, Vite стартует за 300ms и обновляет только изменённые модули. Секрет? Нативные ES-модули в браузере! 🚀


Официальный способ создать Vue 3 проект — через create-vue, который использует Vite под капотом:

Окно терминала
npm create vue@latest my-app

Ты увидишь интерактивный wizard:

✔ Project name: … my-app
✔ Add TypeScript? … Yes ← обязательно!
✔ Add JSX Support? … No
✔ Add Vue Router for SPA? … Yes
✔ Add Pinia for state management? … Yes
✔ Add Vitest for Unit Testing? … Yes
✔ Add an End-to-End Testing Solution? … No
✔ Add ESLint for code quality? … Yes
✔ Add Prettier for code formatting? … Yes
✔ Add Vue DevTools 7 extension? … Yes
Scaffolding project in ./my-app...
Done. ✔

Затем:

Окно терминала
cd my-app
npm install
npm run dev

Открой http://localhost:5173 — проект живёт! 🎉


my-app/
├── public/ ← статичные файлы (favicon, robots.txt)
│ └── favicon.ico
├── src/ ← весь исходный код здесь
│ ├── assets/ ← изображения, шрифты, глобальные стили
│ │ └── main.css
│ │
│ ├── components/ ← переиспользуемые компоненты
│ │ ├── common/ ← общие: BaseButton, BaseInput, etc.
│ │ └── features/ ← фичевые: UserCard, ProductList, etc.
│ │
│ ├── views/ ← страницы (роуты)
│ │ ├── HomeView.vue
│ │ ├── AboutView.vue
│ │ └── UserView.vue
│ │
│ ├── router/ ← Vue Router конфигурация
│ │ └── index.ts
│ │
│ ├── stores/ ← Pinia сторы
│ │ ├── user.ts
│ │ └── cart.ts
│ │
│ ├── composables/ ← переиспользуемая логика
│ │ ├── useUser.ts
│ │ └── useFetch.ts
│ │
│ ├── types/ ← TypeScript типы и интерфейсы
│ │ └── index.ts
│ │
│ ├── utils/ ← вспомогательные функции
│ │ └── formatDate.ts
│ │
│ ├── App.vue ← корневой компонент
│ └── main.ts ← точка входа
├── index.html ← главный HTML (Vite точка входа)
├── vite.config.ts ← конфигурация Vite
├── tsconfig.json ← конфигурация TypeScript
├── env.d.ts ← типы для .vue файлов
└── package.json

vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import { fileURLToPath, URL } from 'node:url'
export default defineConfig({
plugins: [
vue(),
// vueDevTools() — раскомментируй для Vue DevTools
],
resolve: {
alias: {
// @ → src/ (очень удобно!)
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
port: 5173, // порт dev-сервера
open: true, // автоматически открывать браузер
proxy: { // проксирование API запросов
'/api': {
target: 'http://localhost:3000',
changeOrigin: true
}
}
},
build: {
outDir: 'dist', // папка для production сборки
minify: 'esbuild', // минификация (очень быстрая!)
rollupOptions: {
output: {
// разделение кода на чанки
manualChunks: {
vendor: ['vue', 'vue-router', 'pinia']
}
}
}
}
})
// ❌ Без алиасов — ужасно
import UserCard from '../../../components/UserCard.vue'
import { useUser } from '../../../composables/useUser'
// ✅ С алиасом @ → src/
import UserCard from '@/components/UserCard.vue'
import { useUser } from '@/composables/useUser'

.vue файл — это всё в одном: шаблон, логика, стили:

UserCard.vue
<!-- 1️⃣ ШАБЛОН — HTML с Vue директивами -->
<template>
<div class="user-card">
<img :src="user.avatar" :alt="user.name" />
<h2>{{ user.name }}</h2>
<p>{{ user.email }}</p>
<button @click="emit('follow', user.id)">
{{ isFollowing ? 'Отписаться' : 'Подписаться' }}
</button>
</div>
</template>
<!-- 2️⃣ СКРИПТ — TypeScript логика -->
<script setup lang="ts">
import { computed } from 'vue'
// TypeScript интерфейс
interface User {
id: number
name: string
email: string
avatar: string
}
// Определяем props с типами
const props = defineProps<{
user: User
following: number[]
}>()
// Определяем events
const emit = defineEmits<{
follow: [userId: number]
}>()
// Вычисляемое свойство
const isFollowing = computed(() =>
props.following.includes(props.user.id)
)
</script>
<!-- 3️⃣ СТИЛИ — CSS изолированный в компоненте -->
<style scoped>
.user-card {
border: 1px solid #e2e8f0;
border-radius: 12px;
padding: 16px;
text-align: center;
}
button {
background: #42b883;
color: white;
border: none;
padding: 8px 16px;
border-radius: 6px;
cursor: pointer;
/* :deep() пробивает scoped изоляцию в дочерних компонентах */
:deep(.child-class) {
color: red;
}
}
</style>

Есть два способа писать Composition API:

<!-- Способ 1: <script setup> — рекомендуемый синтаксис Vue 3.2+ -->
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
// Всё объявленное здесь автоматически доступно в шаблоне!
</script>
<!-- Способ 2: setup() функция — более явный, нужен для defineComponent -->
<script lang="ts">
import { ref, defineComponent } from 'vue'
export default defineComponent({
name: 'MyComponent',
setup() {
const count = ref(0)
// Нужно явно возвращать всё, что нужно в шаблоне
return { count }
}
})
</script>

<script setup> — это синтаксический сахар. Компилятор Vue превращает его в setup() функцию автоматически. Преимущества:

  • Меньше boilerplate
  • Лучший вывод типов TypeScript
  • Лучший runtime производительность (меньше замыканий)

<template>
<div class="card">
<p class="text">Текст в карточке</p>
</div>
</template>
<style scoped>
/* scoped: Vue добавляет уникальный атрибут к элементам: */
/* <div class="card" data-v-7ba5bd90> */
/* <p class="text" data-v-7ba5bd90> */
.card {
/* Компилируется в: .card[data-v-7ba5bd90] */
background: white;
}
/* :deep() — стилизация дочерних компонентов */
:deep(.child-button) {
/* .card[data-v-7ba5bd90] .child-button */
color: blue;
}
/* :slotted() — стилизация содержимого слота */
:slotted(p) {
color: gray;
}
/* :global() — глобальный стиль из scoped блока */
:global(body) {
margin: 0;
}
</style>

CSS Modules — альтернатива scoped:

<template>
<!-- $style.card — объект с уникальными классами -->
<div :class="$style.card">
<p :class="$style.text">Текст</p>
</div>
</template>
<style module>
/* Компилируется в уникальный класс: .card_abc123 */
.card { background: white; }
.text { color: black; }
</style>

/* src/assets/main.css — глобальные стили */
:root {
/* CSS переменные для темы */
--color-primary: #42b883;
--color-dark: #35495e;
--color-background: #ffffff;
--color-text: #213547;
--border-radius: 8px;
--font-size-base: 16px;
}
/* Тёмная тема */
@media (prefers-color-scheme: dark) {
:root {
--color-background: #0f172a;
--color-text: #e2e8f0;
}
}
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Inter, system-ui, sans-serif;
background: var(--color-background);
color: var(--color-text);
}
// main.ts — подключаем глобальные стили
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"moduleResolution": "bundler",
"strict": true, // строгий TypeScript
"jsx": "preserve",
"skipLibCheck": true,
"paths": {
"@/*": ["./src/*"] // алиасы для TypeScript
}
},
"include": ["src/**/*", "env.d.ts"],
"exclude": ["node_modules", "dist"]
}
// env.d.ts — типы для .vue файлов
/// <reference types="vite/client" />
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}

Окно терминала
npm run dev # запуск dev-сервера (http://localhost:5173)
# Сборка
npm run build # production сборка в dist/
npm run preview # превью production сборки
# Тесты
npm run test:unit # запуск unit тестов (Vitest)
npm run test:e2e # запуск e2e тестов (Playwright/Cypress)
# Линтинг
npm run lint # проверка ESLint
npm run format # форматирование Prettier
# Типы
npx vue-tsc --check # проверка TypeScript типов

.vscode/extensions.json
{
"recommendations": [
"Vue.volar", // Language Server (IntelliSense, автодополнение)
"Vue.vscode-typescript-vue-plugin", // TypeScript в .vue файлах
"esbenp.prettier-vscode", // форматирование
"dbaeumer.vscode-eslint", // линтинг
"bradlc.vscode-tailwindcss" // если используешь Tailwind
]
}
.vscode/settings.json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[vue]": {
"editor.defaultFormatter": "Vue.volar"
},
"typescript.tsdk": "node_modules/typescript/lib",
"vue.inlayHints.missingProps": true
}

Vite + Vue 3 — идеальная пара:

  • npm create vue@latest — один wizard создаёт полноценный проект
  • Структура src/components, src/views, src/stores — стандартная и понятная
  • SFC (.vue) — шаблон + скрипт + стили в одном файле
  • <script setup> — рекомендуемый синтаксис, меньше кода, лучше типы
  • <style scoped> — изоляция CSS без утечек

Следующий урок — Composition API! 🧩