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

Vite — React + TypeScript + MobX

Vite — современный build tool использующий нативные ES modules в development (почти мгновенный старт) и Rollup для production bundle. Разработан Evan You (автор Vue.js), но отлично работает с React.

Ключевые преимущества:

  • Dev server: старт за < 300ms (vs webpack 15-30 сек на большом проекте)
  • HMR (Hot Module Replacement): обновление < 50ms
  • Production: Rollup-based оптимизированный bundle
Окно терминала
npm create vite@latest my-react-app -- --template react-ts
cd my-react-app
npm install

Структура после создания:

my-react-app/
public/
vite.svg
src/
assets/
App.css
App.tsx
index.css
main.tsx
vite-env.d.ts
index.html
package.json
tsconfig.json
tsconfig.node.json
vite.config.ts
Окно терминала
# MobX + React интеграция
npm install mobx mobx-react-lite
# Роутер
npm install react-router-dom
# Dev зависимости
npm install -D @types/node
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import path from 'path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
'@components': path.resolve(__dirname, './src/components'),
'@stores': path.resolve(__dirname, './src/stores'),
'@hooks': path.resolve(__dirname, './src/hooks'),
'@types': path.resolve(__dirname, './src/types'),
},
},
server: {
port: 3000,
open: true,
proxy: {
// Проксирование API запросов
'/api': {
target: 'http://localhost:4000',
changeOrigin: true,
rewrite: path => path.replace(/^\/api/, ''),
},
},
},
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
// Разбивка на чанки
manualChunks: {
vendor: ['react', 'react-dom'],
mobx: ['mobx', 'mobx-react-lite'],
router: ['react-router-dom'],
},
},
},
},
});
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
/* Строгий режим */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
/* Path aliases */
"baseUrl": ".",
"paths": {
"@/*": ["src/*"],
"@components/*": ["src/components/*"],
"@stores/*": ["src/stores/*"],
"@hooks/*": ["src/hooks/*"]
},
/* MobX decorators */
"experimentalDecorators": true,
"useDefineForClassFields": false
},
"include": ["src"],
"references": [{ "path": "./tsconfig.node.json" }]
}
src/
components/
ui/ — кнопки, инпуты, спиннеры
layout/ — Header, Footer, Layout
features/ — компоненты функций приложения
stores/
AuthStore.ts
UserStore.ts
RootStore.ts
index.ts — export + Context Provider
hooks/
useStores.ts — хук для доступа к сторам
services/
api.ts — fetch wrapper
authService.ts
types/
index.ts
pages/
HomePage.tsx
ProfilePage.tsx
App.tsx
main.tsx
src/stores/RootStore.ts
import { AuthStore } from './AuthStore';
import { UserStore } from './UserStore';
export class RootStore {
auth: AuthStore;
users: UserStore;
constructor() {
this.auth = new AuthStore(this);
this.users = new UserStore(this);
}
}
// src/stores/index.ts
import React, { createContext, useContext, useState } from 'react';
import { RootStore } from './RootStore';
const StoreContext = createContext<RootStore | null>(null);
export function StoreProvider({ children }: React.PropsWithChildren) {
const [store] = useState(() => new RootStore());
return <StoreContext.Provider value={store}>{children}</StoreContext.Provider>;
}
export function useStores(): RootStore {
const store = useContext(StoreContext);
if (!store) throw new Error('useStores must be used within StoreProvider');
return store;
}
src/main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import { StoreProvider } from '@stores';
import App from './App';
import './index.css';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<BrowserRouter>
<StoreProvider>
<App />
</StoreProvider>
</BrowserRouter>
</React.StrictMode>
);
Окно терминала
npm run dev # dev server на localhost:3000
npm run build # production build в dist/
npm run preview # preview production build
npm run typecheck # только typecheck (без build)
{
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"typecheck": "tsc --noEmit"
}
}
.env
VITE_API_URL=http://localhost:4000
VITE_APP_TITLE=My App
# .env.production
VITE_API_URL=https://api.example.com
// Использование — только переменные с VITE_ prefix доступны в браузере
const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;
const isProd = import.meta.env.PROD;