Настройка бандлера Vite для веб-проекта
Vite использует нативные ES-модули браузера в dev-режиме — файлы отдаются напрямую, без сборки. HMR работает точечно: изменился один файл — обновился один модуль. Для production сборки использует Rollup.
Результат: холодный старт dev-сервера за 300–500 мс вместо 30–60 секунд у Webpack для крупных проектов.
Что входит в работу
Настройка vite.config.ts для React/Vue/Svelte, TypeScript, CSS/PostCSS, алиасы путей, proxy на backend API, code splitting, переменные окружения, production-оптимизации.
Установка
# React + TypeScript
npm create vite@latest my-app -- --template react-ts
cd my-app && npm install
# или Vue
npm create vite@latest my-app -- --template vue-ts
# или Svelte
npm create vite@latest my-app -- --template svelte-ts
vite.config.ts — React-проект
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react-swc'
import path from 'path'
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), '')
return {
plugins: [
react(),
],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@utils': path.resolve(__dirname, './src/utils'),
'@assets': path.resolve(__dirname, './src/assets'),
},
},
server: {
port: 3000,
strictPort: true, // ошибка если порт занят, а не выбор другого
proxy: {
'/api': {
target: env.VITE_API_URL ?? 'http://localhost:8000',
changeOrigin: true,
rewrite: (p) => p.replace(/^\/api/, ''),
},
'/ws': {
target: env.VITE_WS_URL ?? 'ws://localhost:8000',
ws: true,
},
},
hmr: {
overlay: true,
},
},
preview: {
port: 4000,
strictPort: true,
},
css: {
modules: {
localsConvention: 'camelCaseOnly',
},
preprocessorOptions: {
scss: {
additionalData: `@import "@/styles/variables.scss";`,
},
},
},
build: {
target: 'es2020',
outDir: 'dist',
sourcemap: mode !== 'production',
minify: 'esbuild',
rollupOptions: {
output: {
manualChunks: {
'vendor-react': ['react', 'react-dom'],
'vendor-router': ['react-router-dom'],
'vendor-query': ['@tanstack/react-query'],
'vendor-ui': ['@radix-ui/react-dialog', '@radix-ui/react-dropdown-menu'],
},
chunkFileNames: 'assets/js/[name]-[hash].js',
entryFileNames: 'assets/js/[name]-[hash].js',
assetFileNames: 'assets/[ext]/[name]-[hash].[ext]',
},
},
// не выводить предупреждения о размере чанков в CI
chunkSizeWarningLimit: 600,
},
optimizeDeps: {
include: [
'react',
'react-dom',
'react-router-dom',
'@tanstack/react-query',
],
},
define: {
__APP_VERSION__: JSON.stringify(process.env.npm_package_version),
},
}
})
tsconfig.json — алиасы
Алиасы нужно описать и в vite.config.ts, и в tsconfig.json:
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"strict": true,
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@hooks/*": ["src/hooks/*"],
"@utils/*": ["src/utils/*"]
},
"types": ["vite/client"]
}
}
Переменные окружения
# .env.development
VITE_API_URL=http://localhost:8000
VITE_APP_NAME=MyApp Dev
# .env.production
VITE_API_URL=https://api.example.com
VITE_APP_NAME=MyApp
Только переменные с префиксом VITE_ попадают в браузерный код:
// автотипизация
/// <reference types="vite/client" />
interface ImportMetaEnv {
readonly VITE_API_URL: string
readonly VITE_APP_NAME: string
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
// использование
const apiUrl = import.meta.env.VITE_API_URL
Плагины под разные задачи
npm install -D vite-plugin-svgr # SVG → React-компоненты
npm install -D @vitejs/plugin-legacy # поддержка старых браузеров
npm install -D vite-plugin-pwa # Progressive Web App
npm install -D rollup-plugin-visualizer # анализ бандла
npm install -D vite-plugin-checker # TypeScript + ESLint в dev
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import svgr from 'vite-plugin-svgr'
import legacy from '@vitejs/plugin-legacy'
import { VitePWA } from 'vite-plugin-pwa'
import { visualizer } from 'rollup-plugin-visualizer'
import checker from 'vite-plugin-checker'
export default defineConfig({
plugins: [
react(),
svgr({
svgrOptions: { exportType: 'named', ref: true },
}),
checker({
typescript: true,
eslint: { lintCommand: 'eslint src --ext .ts,.tsx' },
}),
VitePWA({
registerType: 'autoUpdate',
manifest: {
name: 'My App',
short_name: 'App',
theme_color: '#1a1a2e',
icons: [
{ src: '/icon-192.png', sizes: '192x192', type: 'image/png' },
{ src: '/icon-512.png', sizes: '512x512', type: 'image/png' },
],
},
}),
process.env.ANALYZE && visualizer({
open: true,
gzipSize: true,
brotliSize: true,
filename: 'dist/bundle-stats.html',
}),
].filter(Boolean),
})
Code splitting через lazy
// src/router.tsx
import { lazy, Suspense } from 'react'
import { createBrowserRouter } from 'react-router-dom'
const ProductsPage = lazy(() =>
import('./pages/ProductsPage')
// подсказка Rollup по имени чанка
// import(/* rollupOptions: { name: "products" } */ './pages/ProductsPage')
)
export const router = createBrowserRouter([
{
path: '/',
element: <Layout />,
children: [
{
path: 'products',
element: (
<Suspense fallback={<PageSkeleton />}>
<ProductsPage />
</Suspense>
),
},
],
},
])
Статика и ассеты
// импорт с типизацией
import logoUrl from '@assets/logo.svg?url' // строка URL
import LogoComponent from '@assets/logo.svg?react' // React-компонент (svgr)
import rawSvg from '@assets/icon.svg?raw' // сырой SVG как строка
// URL для web worker
import MyWorker from './workers/heavy.worker?worker'
const worker = new MyWorker()
Многоцелевая сборка (lib mode)
Если проект — UI-библиотека или shared-пакет:
export default defineConfig({
build: {
lib: {
entry: path.resolve(__dirname, 'src/index.ts'),
name: 'MyLib',
formats: ['es', 'cjs'],
fileName: (format) => `index.${format}.js`,
},
rollupOptions: {
external: ['react', 'react-dom'],
output: {
globals: { react: 'React', 'react-dom': 'ReactDOM' },
},
},
},
})
Скрипты
{
"scripts": {
"dev": "vite",
"build": "tsc --noEmit && vite build",
"build:analyze": "ANALYZE=true vite build",
"preview": "vite preview",
"lint": "eslint src --ext .ts,.tsx --report-unused-disable-directives"
}
}
tsc --noEmit перед vite build — проверяем типы перед сборкой. Vite транспилирует TypeScript без проверки типов, поэтому это важно.
Что делаем
Настраиваем vite.config.ts под стек проекта (React/Vue/Svelte), алиасы, proxy на backend, CSS/SCSS, подключаем нужные плагины, оптимизируем manual chunks под характеристики приложения, настраиваем переменные окружения, добавляем bundle visualizer.
Срок: несколько часов для нового проекта, 1 день при переезде с webpack.







