2.6 — Performance e Tamanho do Bundle
Benchmarks reais e o impacto do compilador na performance.
Objetivos da Aula
- Comparar tamanho de bundle entre Svelte e React
- Entender métricas de performance (LCP, TTI, FCP)
- Ver benchmarks de operações DOM
- Analisar quando cada framework performa melhor
Tamanho do Bundle: A Grande Diferença
Hello World
Aplicação Real (TodoMVC)
Por Que Essa Diferença?
// React precisa enviar:
// 1. react (~2.5KB gzip)
// 2. react-dom (~40KB gzip)
// 3. scheduler (~5KB)
// 4. Seu código
// = 47.5KB + seu código
// Svelte envia:
// 1. Helpers mínimos (~2KB)
// 2. Seu código (compilado eficientemente)
// = 2KB + seu código Métricas de Performance
Core Web Vitals
LCP (Largest Contentful Paint)
→ Quando o maior conteudo aparece
→ Meta: < 2.5s
FID (First Input Delay) / INP (Interaction to Next Paint)
→ Tempo ate responder a interacao
→ Meta: < 100ms (FID) / < 200ms (INP)
CLS (Cumulative Layout Shift)
→ Quanto a pagina "pula" durante carregamento
→ Meta: < 0.1
Outras Métricas Importantes
TTFB (Time to First Byte)
→ Tempo até primeiro byte do servidor
→ Afetado por: servidor, rede, CDN
FCP (First Contentful Paint)
→ Quando primeiro conteúdo aparece
→ Afetado por: tamanho do HTML, CSS crítico
TTI (Time to Interactive)
→ Quando a página fica interativa
→ Afetado por: tamanho do JS, hidratação Benchmark: Operações DOM
js-framework-benchmark
Este benchmark testa operações comuns de UI:
Por Que Svelte é Mais Rápido?
// React: Cada atualização
// 1. Executa função do componente
// 2. Cria objetos Virtual DOM
// 3. Diff com árvore anterior
// 4. Aplica mudanças
// Svelte: Cada atualização
// 1. Atualiza DOM diretamente (código gerado sabe exatamente o que mudou)
// Exemplo: Atualizar um contador
// React: ~15 operações JavaScript
// Svelte: ~3 operações JavaScript Hidratação: O Custo Oculto
O Que é Hidratação?
- Servidor renderiza HTML
→ HTML estatico chega ao navegador (FCP rapido!) - JavaScript carrega
→ Tamanho do bundle importa aqui - Hidratacao acontece
→ Framework "assume" o HTML estatico
→ Adiciona event listeners
→ Reconstroi estado - Pagina fica interativa (TTI)
Custo da Hidratação
(precisa reconstruir Virtual DOM)
(so adiciona listeners)
Memória
Consumo de RAM
(Virtual DOM + Fiber nodes + closures)
(Proxy objects + dependency tracking)
(DOM nodes + minimal state)
Quando React Pode Ser Mais Rápido
Concurrent Mode e Suspense
// React pode pausar renderização para manter UI responsiva
function HeavyList({ items }) {
return (
<Suspense fallback={<Skeleton />}>
{items.map(item => (
<ExpensiveItem key={item.id} data={item} />
))}
</Suspense>
)
}
// Transitions para updates de baixa prioridade
function Search() {
const [query, setQuery] = useState('')
const [results, setResults] = useState([])
const [isPending, startTransition] = useTransition()
function handleChange(e) {
setQuery(e.target.value)
startTransition(() => {
setResults(searchItems(e.target.value))
})
}
return (
<>
<input value={query} onChange={handleChange} />
{isPending && <Spinner />}
<Results items={results} />
</>
)
} Quando Isso Importa
- Apps com interações muito pesadas
- Dashboards com muitos gráficos
- Editores de texto ricos
- Animações complexas durante updates
Svelte 5 está adicionando features similares com $effect.pre() e melhor scheduling.
Comparativo Prático
Cenário: Landing Page
Requisitos:
- Carregar rápido
- SEO importante
- Pouca interatividade
Vencedor: SVELTE
- Bundle muito menor
- TTI mais rápido
- FCP melhor Cenário: Dashboard Admin
Requisitos:
- Muita interatividade
- Muitos dados
- Usuário já autenticado (menos foco em TTI inicial)
Ambos funcionam bem, mas:
- Svelte: Updates mais rápidos, menor memória
- React: Ecossistema maior de componentes prontos Cenário: E-commerce
Requisitos:
- Performance crítica (conversão!)
- SEO essencial
- Carrinho interativo
Vencedor: SVELTE (ou qualquer um com SSR bem feito)
- Bundle menor = menos abandono em mobile
- TTI menor = mais conversão Medindo na Prática
Lighthouse
# Install
npm install -g lighthouse
# Run
lighthouse https://seu-site.com --view Web Vitals no Código
// Com a biblioteca web-vitals
import { getCLS, getFID, getLCP, getFCP, getTTFB } from 'web-vitals'
getCLS(console.log) // Cumulative Layout Shift
getFID(console.log) // First Input Delay
getLCP(console.log) // Largest Contentful Paint
getFCP(console.log) // First Contentful Paint
getTTFB(console.log) // Time to First Byte Bundle Analyzer
// vite.config.js
import { visualizer } from 'rollup-plugin-visualizer'
export default {
plugins: [
visualizer({
open: true,
gzipSize: true
})
]
} ✅ Desafio da Aula
Objetivo
Medir e comparar a performance de um componente em desenvolvimento.
Instruções
- Crie um componente que renderiza 500 itens
- Adicione um botão que atualiza todos os itens
- Meça o tempo de renderização inicial e de atualização
- Use
performance.now()para medir
Componente Base
<script>
let items = Array.from({ length: 500 }, (_, i) => ({
id: i,
value: Math.random()
}))
function updateAll() {
const start = performance.now()
items = items.map(item => ({
...item,
value: Math.random()
}))
// Como medir o tempo de renderização?
}
</script> Spec de Verificação
- 500 itens são renderizados
- Botão atualiza todos os itens
- Tempo de atualização é exibido na tela
- Tempo é < 50ms (se não, algo está errado!)
Solução
🔍 Clique para ver a solução
<script>
import { tick } from 'svelte'
let items = Array.from({ length: 500 }, (_, i) => ({
id: i,
value: Math.random()
}))
let renderTime = 0
let updateCount = 0
async function updateAll() {
const start = performance.now()
items = items.map(item => ({
...item,
value: Math.random()
}))
// tick() espera o Svelte completar a atualização do DOM
await tick()
renderTime = (performance.now() - start).toFixed(2)
updateCount++
}
// Medir renderização inicial
import { onMount } from 'svelte'
let initialRender = 0
onMount(async () => {
const start = performance.now()
await tick()
initialRender = (performance.now() - start).toFixed(2)
})
</script>
<div class="stats">
<p>Renderização inicial: {initialRender}ms</p>
<p>Última atualização: {renderTime}ms</p>
<p>Updates: {updateCount}</p>
<button on:click={updateAll}>Atualizar Todos</button>
</div>
<div class="grid">
{#each items as item (item.id)}
<div class="item">
{item.value.toFixed(4)}
</div>
{/each}
</div>
<style>
.stats {
position: sticky;
top: 0;
background: white;
padding: 1rem;
border-bottom: 1px solid #ccc;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 4px;
padding: 1rem;
}
.item {
padding: 8px;
background: #f0f0f0;
text-align: center;
font-size: 0.75rem;
}
</style>Próxima aula: 2.7 — Ecossistema e Mercado de Trabalho