1.2 — Arquitetura do Vite
Entenda como o Vite funciona internamente: servidor de desenvolvimento, pré-bundling e o papel do esbuild e Rollup.
Objetivos da Aula
- Compreender a arquitetura interna do servidor de desenvolvimento
- Entender o processo de pré-bundling de dependências com esbuild
- Conhecer o fluxo de transformação de arquivos
- Diferenciar o funcionamento em desenvolvimento vs produção
Visão Geral da Arquitetura
O Vite possui duas arquiteturas distintas que trabalham em conjunto:
ARQUITETURA DO VITE
- Servidor ESM
- + esbuild
- + HMR nativo
- Rollup Bundler
- + Plugins
- + Otimizações
O Servidor de Desenvolvimento
Fluxo de uma Requisição
Quando você acessa http://localhost:5173, acontece o seguinte:
FLUXO DE REQUISIÇÃO
<script type="module" src="/src/main.js">import './app.js'Código Exemplo: Vendo na Prática
Crie estes arquivos no seu projeto:
// src/main.js
import { saudacao } from './utils/saudacao.js'
import { formataData } from './utils/data.js'
console.log(saudacao('Mundo'))
console.log(formataData(new Date())) // src/utils/saudacao.js
export function saudacao(nome) {
return `Olá, ${nome}!`
} // src/utils/data.js
export function formataData(data) {
return data.toLocaleDateString('pt-BR')
} Abra o DevTools do navegador → Network e observe:
Request 1: /src/main.js (200 OK)
Request 2: /src/utils/saudacao.js (200 OK)
Request 3: /src/utils/data.js (200 OK) Cada arquivo é uma requisição separada! O navegador resolve os imports.
Pré-bundling de Dependências
O Problema com node_modules
Nem todas as dependências funcionam bem com ESModules nativos:
// lodash tem centenas de módulos internos
import { debounce } from 'lodash-es'
// Isso causaria CENTENAS de requisições HTTP!
// react usa CommonJS internamente
import React from 'react'
// CommonJS não funciona direto no navegador! A Solução: esbuild
O Vite usa o esbuild para pré-compilar dependências no primeiro start:
PRÉ-BUNDLING
Primeiro npm run dev:
Vendo o Cache
Após rodar npm run dev, observe a pasta criada:
ls node_modules/.vite/deps/ Você verá arquivos como:
_metadata.json
lodash-es.js
lodash-es.js.map
react.js
react.js.map Reescrita de Imports
O Vite reescreve seus imports automaticamente:
// Seu código (o que você escreve):
import { debounce } from 'lodash-es'
// O que o navegador recebe:
import { debounce } from '/node_modules/.vite/deps/lodash-es.js?v=abc123' Hot Module Replacement (HMR)
Como Funciona
O HMR do Vite usa WebSockets para comunicação instantânea:
HMR FLOW
src/components/Button.jspath: '/src/components/Button.js',
timestamp: 1699123456789
}] }
- Recebe a mensagem
- Faz
import()dinâmico do módulo atualizado - Substitui o módulo antigo pelo novo
- Estado da aplicação é PRESERVADO!
Exemplo: Observando o HMR
Abra o DevTools → Console e observe as mensagens:
[vite] connecting...
[vite] connected.
# Quando você edita um arquivo:
[vite] hot updated: /src/main.js API do HMR
Você pode interagir com o HMR programaticamente:
// main.js
import { contador } from './contador.js'
console.log('Contagem:', contador)
// API de HMR do Vite
if (import.meta.hot) {
// Aceita atualizações deste módulo
import.meta.hot.accept()
// Executa quando o módulo é substituído
import.meta.hot.dispose(() => {
console.log('Módulo antigo sendo descartado')
})
} Transformação de Arquivos
Pipeline de Transformação
PIPELINE DE TRANSFORMAÇÃO
Exemplo: TypeScript
// src/utils/math.ts
export function soma(a: number, b: number): number {
return a + b
} O Vite transforma para:
// O que o navegador recebe:
export function soma(a, b) {
return a + b
} A transformação acontece sob demanda, não antecipadamente!
Arquitetura de Produção
No build de produção, o Vite usa Rollup:
BUILD DE PRODUÇÃO
npm run build
Por que Rollup e não esbuild para produção?
esbuild:
✓ Extremamente rápido
✗ Code splitting ainda não é ideal
✗ Plugins menos flexíveis
Rollup:
✓ Code splitting maduro
✓ Ecossistema de plugins robusto
✓ Otimizações avançadas
✗ Mais lento (mas OK para builds ocasionais) Exemplo Prático: Observando a Arquitetura
1. Veja o pré-bundling acontecendo
# Delete o cache
rm -rf node_modules/.vite
# Rode o dev server e observe o terminal
npm run dev Você verá:
Optimizing dependencies:
lodash-es, react, react-dom
Pre-bundling them to speed up dev server page load... 2. Compare dev vs build
# Em desenvolvimento
npm run dev
# Abra DevTools → Network → observe dezenas de arquivos .js
# Para build
npm run build
# Observe a pasta dist/ → poucos arquivos otimizados 3. Inspecione o output do build
npm run build
cat dist/assets/index-*.js | head -20
# Código minificado e otimizado! 🎯 Mini-Projeto: Continuação
Vamos adicionar monitoramento de HMR ao nosso Dashboard:
Arquivo: src/hmr-monitor.js
// src/hmr-monitor.js
// Monitor de atualizações HMR
const atualizacoes = []
export function registrarAtualizacao(path) {
atualizacoes.push({
path,
timestamp: new Date().toLocaleTimeString('pt-BR')
})
}
export function getAtualizacoes() {
return [...atualizacoes]
}
export function getUltimaAtualizacao() {
return atualizacoes[atualizacoes.length - 1] || null
}
// Configura listener de HMR
if (import.meta.hot) {
// Quando QUALQUER módulo for atualizado
import.meta.hot.on('vite:beforeUpdate', (payload) => {
payload.updates.forEach(update => {
registrarAtualizacao(update.path)
console.log(`🔄 HMR: ${update.path}`)
})
})
} Atualize o main.js
// main.js
import './style.css'
import { setupCounter } from './counter.js'
import { getAtualizacoes, getUltimaAtualizacao } from './hmr-monitor.js'
const inicioCarregamento = performance.now()
function renderApp() {
const atualizacoes = getAtualizacoes()
const ultima = getUltimaAtualizacao()
document.querySelector('#app').innerHTML = `
<div>
<a href="https://vitejs.dev" target="_blank">
<img src="/vite.svg" class="logo" alt="Vite logo" />
</a>
<h1>Dashboard Vite</h1>
<div class="card">
<button id="counter" type="button"></button>
</div>
<div class="stats">
<p id="tempo-carregamento">Calculando...</p>
<p id="hmr-stats">
📊 HMR Updates: ${atualizacoes.length}
${ultima ? `<br>Último: ${ultima.path} às ${ultima.timestamp}` : ''}
</p>
</div>
</div>
`
setupCounter(document.querySelector('#counter'))
requestAnimationFrame(() => {
const fimCarregamento = performance.now()
const tempoTotal = (fimCarregamento - inicioCarregamento).toFixed(2)
document.querySelector('#tempo-carregamento').textContent =
`⚡ Carregado em ${tempoTotal}ms`
})
}
renderApp()
// Aceita HMR e re-renderiza
if (import.meta.hot) {
import.meta.hot.accept(() => {
renderApp()
})
} Teste o HMR
- Rode
npm run dev - Abra o navegador em
http://localhost:5173 - Edite qualquer arquivo e salve
- Observe o contador de HMR aumentar!
✅ Desafio da Aula
Objetivo
Criar um componente que mostra o tempo de cada atualização HMR.
Instruções
- Modifique
hmr-monitor.jspara também registrar quanto tempo cada HMR levou - Use
performance.now()para medir o tempo entre o início e fim do HMR - Exiba a média de tempo de HMR no dashboard
Dica
// Você pode usar estes eventos do HMR:
import.meta.hot.on('vite:beforeUpdate', () => { /* antes */ })
import.meta.hot.on('vite:afterUpdate', () => { /* depois */ }) Spec de Verificação
- O dashboard mostra quantas atualizações HMR ocorreram
- O dashboard mostra o tempo médio das atualizações
- Ao editar um arquivo, os números atualizam automaticamente
Solução
🔍 Clique para ver a solução
// src/hmr-monitor.js
const atualizacoes = []
let hmrInicio = null
export function registrarInicio() {
hmrInicio = performance.now()
}
export function registrarFim(path) {
if (hmrInicio) {
const duracao = performance.now() - hmrInicio
atualizacoes.push({
path,
timestamp: new Date().toLocaleTimeString('pt-BR'),
duracao: duracao.toFixed(2)
})
hmrInicio = null
}
}
export function getAtualizacoes() {
return [...atualizacoes]
}
export function getMediaTempo() {
if (atualizacoes.length === 0) return 0
const soma = atualizacoes.reduce((acc, a) => acc + parseFloat(a.duracao), 0)
return (soma / atualizacoes.length).toFixed(2)
}
if (import.meta.hot) {
import.meta.hot.on('vite:beforeUpdate', () => {
registrarInicio()
})
import.meta.hot.on('vite:afterUpdate', (payload) => {
payload.updates.forEach(update => {
registrarFim(update.path)
console.log(`🔄 HMR: ${update.path}`)
})
})
}📚 Recursos Adicionais
Próxima aula: 1.3 — Criando e Explorando um Projeto Vite