Frontend
Vite
Build tool moderno e rápido para desenvolvimento frontend
O que é Vite?
Vite é um build tool moderno que oferece desenvolvimento extremamente rápido com Hot Module Replacement (HMR) instantâneo e builds otimizados para produção. Criado pelo mesmo autor do Vue.js, mas funciona perfeitamente com React, TypeScript e outras tecnologias.
Por que utilizamos Vite na IngenioLab?
- Velocidade extrema: Cold start em milissegundos
- HMR instantâneo: Updates imediatos durante desenvolvimento
- ESM nativo: Aproveita ES modules nativos do browser
- TypeScript built-in: Suporte nativo sem configuração
- Plugin ecosystem: Vasto ecossistema de plugins
- Build otimizado: Rollup para builds de produção
Instalação e Setup
1. Criar novo projeto:
# React + TypeScriptnpm create vite@latest meu-projeto -- --template react-tscd meu-projetonpm installnpm run dev# Outros templates disponíveisnpm create vite@latest meu-projeto -- --template reactnpm create vite@latest meu-projeto -- --template vue-tsnpm create vite@latest meu-projeto -- --template vanilla-ts
2. Estrutura de projeto gerada:
meu-projeto/├── public/│ └── vite.svg├── src/│ ├── assets/│ ├── App.tsx│ ├── App.css│ ├── index.css│ ├── main.tsx│ └── vite-env.d.ts├── index.html # Entry point (não na pasta public!)├── package.json├── tsconfig.json├── tsconfig.node.json└── vite.config.ts # Configuração do Vite
3. Scripts padrão:
{"scripts": {"dev": "vite", # Servidor de desenvolvimento"build": "tsc && vite build", # Build para produção"preview": "vite preview", # Preview do build"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"}}
Configuração IngenioLab
1. vite.config.ts básico:
// vite.config.tsimport { defineConfig } from 'vite'import react from '@vitejs/plugin-react'import path from 'path'export default defineConfig({plugins: [react()],// Alias para imports limposresolve: {alias: {'@': path.resolve(__dirname, './src'),'@/components': path.resolve(__dirname, './src/components'),'@/hooks': path.resolve(__dirname, './src/hooks'),'@/services': path.resolve(__dirname, './src/services'),'@/types': path.resolve(__dirname, './src/types'),'@/utils': path.resolve(__dirname, './src/utils'),}},// Servidor de desenvolvimentoserver: {port: 3000,open: true, // Abrir browser automaticamentehost: true, // Permitir acesso externocors: true},// Build settingsbuild: {outDir: 'dist',sourcemap: true,// Chunk splitting para melhor cachingrollupOptions: {output: {manualChunks: {vendor: ['react', 'react-dom'],router: ['@tanstack/react-router'],query: ['@tanstack/react-query']}}}},// Variáveis de ambientedefine: {__APP_VERSION__: JSON.stringify(process.env.npm_package_version),},// Preview settingspreview: {port: 4173,open: true}})
2. Configuração avançada:
// vite.config.ts - Configuração avançada IngenioLabimport { defineConfig, loadEnv } from 'vite'import react from '@vitejs/plugin-react'import { resolve } from 'path'export default defineConfig(({ command, mode }) => {// Carregar env baseado no modeconst env = loadEnv(mode, process.cwd(), '')return {plugins: [react({// Fast Refresh com melhor performancefastRefresh: true,// Incluir .js files para Fast Refreshinclude: "**/*.{jsx,tsx,js,ts}"})],resolve: {alias: {'@': resolve(__dirname, 'src'),'@/components': resolve(__dirname, 'src/components'),'@/pages': resolve(__dirname, 'src/pages'),'@/hooks': resolve(__dirname, 'src/hooks'),'@/services': resolve(__dirname, 'src/services'),'@/types': resolve(__dirname, 'src/types'),'@/utils': resolve(__dirname, 'src/utils'),'@/assets': resolve(__dirname, 'src/assets'),'@/styles': resolve(__dirname, 'src/styles'),}},// CSS configurationcss: {modules: {localsConvention: 'camelCaseOnly'},preprocessorOptions: {scss: {additionalData: `@import "@/styles/variables.scss";`}}},server: {port: Number(env.VITE_PORT) || 3000,host: env.VITE_HOST || 'localhost',open: env.VITE_OPEN_BROWSER !== 'false',// Proxy para API durante desenvolvimentoproxy: {'/api': {target: env.VITE_API_URL || 'http://localhost:3001',changeOrigin: true,secure: false,}},// Configurações de HMRhmr: {overlay: true}},build: {target: 'esnext',outDir: 'dist',assetsDir: 'assets',sourcemap: mode === 'development',// Otimizaçõesminify: 'terser',terserOptions: {compress: {drop_console: mode === 'production',drop_debugger: true}},rollupOptions: {output: {// Chunk strategymanualChunks: (id) => {if (id.includes('node_modules')) {if (id.includes('react')) {return 'react-vendor'}if (id.includes('@tanstack')) {return 'tanstack-vendor'}return 'vendor'}},// Asset namingchunkFileNames: 'assets/js/[name]-[hash].js',entryFileNames: 'assets/js/[name]-[hash].js',assetFileNames: 'assets/[ext]/[name]-[hash].[ext]'}}},// Otimizações de dependênciasoptimizeDeps: {include: ['react','react-dom','@tanstack/react-query','@tanstack/react-router'],exclude: ['@vite/client', '@vite/env']},// Variáveis de ambiente personalizadasdefine: {__APP_VERSION__: JSON.stringify(env.npm_package_version || '1.0.0'),__BUILD_TIME__: JSON.stringify(new Date().toISOString()),__DEV__: command === 'serve'}}})
Plugins Essenciais
1. Plugin React com SWC (mais rápido):
npm install -D @vitejs/plugin-react-swc
// vite.config.tsimport { defineConfig } from 'vite'import react from '@vitejs/plugin-react-swc'export default defineConfig({plugins: [react({// Configurações do SWCjsxImportSource: '@emotion/react',plugins: [// Plugin para styled-components['@swc/plugin-styled-components', {}]]})]})
2. PWA Plugin:
npm install -D vite-plugin-pwa
// vite.config.tsimport { VitePWA } from 'vite-plugin-pwa'export default defineConfig({plugins: [react(),VitePWA({registerType: 'autoUpdate',workbox: {globPatterns: ['**/*.{js,css,html,ico,png,svg}']},manifest: {name: 'IngenioLab App',short_name: 'IngenioLab',description: 'Aplicação IngenioLab',theme_color: '#ffffff',icons: [{src: 'pwa-192x192.png',sizes: '192x192',type: 'image/png'}]}})]})
3. ESLint Plugin:
npm install -D vite-plugin-eslint
// vite.config.tsimport eslint from 'vite-plugin-eslint'export default defineConfig({plugins: [react(),eslint({cache: false,include: ['./src/**/*.js', './src/**/*.jsx', './src/**/*.ts', './src/**/*.tsx']})]})
Variáveis de Ambiente
1. Configuração de .env:
# .env.developmentVITE_APP_TITLE=IngenioLab DevVITE_API_URL=http://localhost:3001VITE_ENABLE_DEVTOOLS=true# .env.productionVITE_APP_TITLE=IngenioLabVITE_API_URL=https://api.ingeniolab.comVITE_ENABLE_DEVTOOLS=false
2. Tipos TypeScript para env:
// src/vite-env.d.ts/// <reference types="vite/client" />interface ImportMetaEnv {readonly VITE_APP_TITLE: stringreadonly VITE_API_URL: stringreadonly VITE_ENABLE_DEVTOOLS: string}interface ImportMeta {readonly env: ImportMetaEnv}
3. Uso nas aplicações:
// src/config/env.tsexport const env = {appTitle: import.meta.env.VITE_APP_TITLE,apiUrl: import.meta.env.VITE_API_URL,enableDevtools: import.meta.env.VITE_ENABLE_DEVTOOLS === 'true',isDevelopment: import.meta.env.DEV,isProduction: import.meta.env.PROD}// src/services/api.tsimport { env } from '../config/env'export const apiClient = axios.create({baseURL: env.apiUrl,timeout: 10000})
Asset Handling
1. Importação de assets:
// src/components/Logo.tsx// Assets estáticosimport logoUrl from '@/assets/logo.png'import iconUrl from '@/assets/icon.svg?url'// Inline como base64import iconInline from '@/assets/small-icon.png?inline'// Como string (para SVGs)import iconSvg from '@/assets/icon.svg?raw'export const Logo = () => {return (<div><img src={logoUrl} alt="Logo" /><img src={iconUrl} alt="Icon" /><img src={iconInline} alt="Inline Icon" /><div dangerouslySetInnerHTML={{ __html: iconSvg }} /></div>)}
2. Assets dinâmicos:
// src/utils/assets.tsexport const getAssetUrl = (path: string) => {return new URL(`../assets/${path}`, import.meta.url).href}// Uso dinâmicoconst imagePath = getAssetUrl(`images/${imageName}.jpg`)
3. Public assets:
<!-- public/index.html --><link rel="icon" href="/favicon.ico" /><!-- src/components/Component.tsx --><img src="/images/logo.png" alt="Logo público" />
Performance e Otimizações
1. Code Splitting:
// src/pages/LazyPage.tsximport { lazy, Suspense } from 'react'// Lazy loading de componentesconst HeavyComponent = lazy(() => import('@/components/HeavyComponent'))const Dashboard = lazy(() => import('./Dashboard'))export const LazyPage = () => (<div><Suspense fallback={<div>Carregando...</div>}><HeavyComponent /></Suspense><Suspense fallback={<div>Carregando dashboard...</div>}><Dashboard /></Suspense></div>)
2. Bundle Analysis:
# Instalar bundle analyzernpm install -D rollup-plugin-visualizer# Adicionar ao vite.config.tsimport { visualizer } from 'rollup-plugin-visualizer'export default defineConfig({plugins: [react(),visualizer({filename: 'dist/stats.html',open: true,gzipSize: true})]})
3. Preloading e Prefetching:
<!-- index.html --><head><link rel="modulepreload" href="/src/main.tsx" /><link rel="dns-prefetch" href="https://api.ingeniolab.com" /></head>
Modo de Desenvolvimento
1. Hot Module Replacement (HMR):
// src/main.tsximport { createRoot } from 'react-dom/client'import App from './App'const container = document.getElementById('root')!const root = createRoot(container)root.render(<App />)// HMR para desenvolvimentoif (import.meta.hot) {import.meta.hot.accept('./App', () => {// Re-render quando App.tsx mudarroot.render(<App />)})}
2. Configurações de debug:
// vite.config.tsexport default defineConfig({server: {hmr: {overlay: true, // Mostrar erros na telaclientPort: 3000}},// Source maps detalhados em devbuild: {sourcemap: process.env.NODE_ENV === 'development' ? 'inline' : false}})
Build para Produção
1. Otimizações automáticas:
# Build otimizadonpm run build# Visualizar resultadonpm run preview
2. Configurações de build:
// vite.config.tsexport default defineConfig({build: {// Target moderno para melhor performancetarget: 'esnext',// Minificaçãominify: 'terser',terserOptions: {compress: {drop_console: true, // Remover console.logsdrop_debugger: true // Remover debuggers}},// Chunk size limitsrollupOptions: {output: {manualChunks: (id) => {if (id.includes('node_modules')) {// Separar vendors grandesif (id.includes('react') || id.includes('react-dom')) {return 'react-vendor'}return 'vendor'}}}},// Asset inline thresholdassetsInlineLimit: 4096, // 4kb}})
3. Análise de build:
{"scripts": {"build:analyze": "vite build --mode analyze","build:report": "npm run build && npx serve dist"}}
Integração com TypeScript
1. tsconfig.json otimizado:
{"compilerOptions": {"target": "ESNext","lib": ["DOM", "DOM.Iterable", "ESNext"],"allowJs": false,"skipLibCheck": true,"esModuleInterop": false,"allowSyntheticDefaultImports": true,"strict": true,"forceConsistentCasingInFileNames": true,"module": "ESNext","moduleResolution": "Node","resolveJsonModule": true,"isolatedModules": true,"noEmit": true,"jsx": "react-jsx","baseUrl": ".","paths": {"@/*": ["src/*"]}},"include": ["src/**/*","vite.config.ts"],"exclude": ["node_modules","dist"]}
Deploy e CI/CD
1. Build para diferentes ambientes:
{"scripts": {"build:dev": "vite build --mode development","build:staging": "vite build --mode staging","build:prod": "vite build --mode production"}}
2. Dockerfile otimizado:
# DockerfileFROM node:18-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ci --only=productionCOPY . .RUN npm run buildFROM nginx:alpineCOPY --from=builder /app/dist /usr/share/nginx/htmlCOPY nginx.conf /etc/nginx/nginx.confEXPOSE 80CMD ["nginx", "-g", "daemon off;"]
3. GitHub Actions:
# .github/workflows/deploy.ymlname: Deployon:push:branches: [main]jobs:build:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v3- name: Setup Node.jsuses: actions/setup-node@v3with:node-version: '18'cache: 'npm'- name: Install dependenciesrun: npm ci- name: Buildrun: npm run buildenv:VITE_API_URL: ${{ secrets.API_URL }}- name: Deployrun: echo "Deploy to production"