2.1 — Filosofia: Compilador vs Runtime
A diferença fundamental que define tudo o mais.
Objetivos da Aula
- Entender a diferença entre abordagem de compilador e runtime
- Compreender o que significa “Svelte desaparece”
- Analisar o impacto no tamanho do bundle e performance
A Grande Divisão
A diferença mais fundamental entre Svelte e React está na quando o trabalho é feito:
Quando o Trabalho Acontece
React (Runtime)
Trabalho:
Svelte (Compilador)
Trabalho:
React: O Caminho do Runtime
Como React Funciona
- Você escreve JSX (uma extensão de sintaxe)
- Babel transforma JSX em chamadas
React.createElement() - O React Runtime (biblioteca) é enviado ao navegador
- O runtime gerencia o Virtual DOM
- A cada mudança de estado, o runtime:
- Re-executa a função do componente
- Gera nova árvore Virtual DOM
- Compara com a anterior (diffing)
- Aplica mudanças mínimas ao DOM real
// O que você escreve
function Counter() {
const [count, setCount] = useState(0)
return <button onClick={() => setCount(c => c + 1)}>
{count}
</button>
}
// O que vai para o navegador (simplificado)
function Counter() {
const [count, setCount] = React.useState(0);
return React.createElement(
"button",
{ onClick: () => setCount(c => c + 1) },
count
);
}
// + 40KB+ do React Runtime
// + 10KB+ do ReactDOM
// = 50KB+ antes do seu código O Custo do Runtime
// React Runtime precisa:
// 1. Sistema de Virtual DOM
// 2. Algoritmo de Reconciliação (diffing)
// 3. Sistema de Hooks
// 4. Scheduler (Concurrent Mode)
// 5. Sistema de Eventos Sintéticos
// Tudo isso: ~50KB+ gzipped Svelte: O Caminho do Compilador
Como Svelte Funciona
- Você escreve código
.svelte - O Compilador Svelte analisa seu código no build
- Gera JavaScript vanilla otimizado
- Nenhum runtime é enviado ao navegador
- O código gerado manipula o DOM diretamente
<!-- O que você escreve -->
<script>
let count = 0
</script>
<button on:click={() => count++}>
{count}
</button> // O que o compilador gera (simplificado)
function create_fragment(ctx) {
let button;
let t;
return {
c() {
button = element("button");
t = text(ctx[0]); // count
},
m(target, anchor) {
insert(target, button, anchor);
append(button, t);
// Event listener direto, sem sistema de eventos sintéticos
button.addEventListener("click", ctx[1]);
},
p(ctx, [dirty]) {
// Atualização cirúrgica - só muda o texto se count mudou
if (dirty & 1) set_data(t, ctx[0]);
},
d(detaching) {
if (detaching) detach(button);
button.removeEventListener("click", ctx[1]);
}
};
}
// Helpers mínimos: ~2KB
// Seu componente: ~0.5KB
// Total: ~2.5KB O que “Svelte Desaparece” Significa
Svelte Desaparece
Tempo de Build:
Runtime (navegador):
Apenas o JS gerado executa
Nao existe "Svelte" rodando
So JavaScript vanilla manipulando DOM
"Svelte desaparece" = O framework nao existe em runtime
Comparação Visual: Virtual DOM vs DOM Direto
React (Virtual DOM)
Estado muda: count = 1 → count = 2
Re-executa toda a funcao do componente
Cria NOVA arvore Virtual DOM
{ type: 'button', props: { children: 2 } }
COMPARA com arvore anterior (diffing)
{ type: 'button', props: { children: 1 } }
→ Encontra diferenca: children mudou
Aplica mudanca minima ao DOM real
textNode.textContent = 2
Svelte (DOM Direto)
Estado muda: count = 1 → count = 2
Compilador JA SABE que count afeta o textNode
(analise estatica em tempo de build)
Codigo gerado atualiza DIRETAMENTE
if (dirty & 1) textNode.data = count
Nao existe:
✗ Re-execucao de funcao
✗ Criacao de objetos Virtual DOM
✗ Algoritmo de diff
O Poder da Análise Estática
O compilador Svelte faz análise estática do seu código:
<script>
let name = 'mundo' // ← Variável reativa
let count = 0 // ← Variável reativa
const PI = 3.14159 // ← Constante (não precisa rastrear)
function increment() {
count += 1 // ← Compilador sabe que isso muda `count`
}
</script>
<h1>Olá, {name}!</h1> <!-- Depende de `name` -->
<p>Contagem: {count}</p> <!-- Depende de `count` -->
<p>Pi: {PI}</p> <!-- Depende de `PI` (constante) -->
<button on:click={increment}>+</button> O compilador sabe em tempo de build:
- Quais variáveis são reativas
- Quais partes do DOM dependem de cada variável
- Quais atualizações são necessárias quando algo muda
// Código gerado (simplificado)
p(ctx, [dirty]) {
// `dirty` é um bitmask indicando O QUE mudou
// Se `name` mudou (bit 0)
if (dirty & 1) set_data(t0, ctx[0]); // Atualiza "Olá, {name}!"
// Se `count` mudou (bit 1)
if (dirty & 2) set_data(t1, ctx[1]); // Atualiza "Contagem: {count}"
// PI nunca muda, então não há código para atualizá-lo!
} Implicações Práticas
Tamanho do Bundle
Aplicacao "Hello World" com contador
React
Svelte
Svelte e ~12x menor!
Escalabilidade do Bundle
Conforme sua aplicação cresce:
React:
Base: ~43 KB (runtime fixo)
+ Componentes: cresce linearmente
+ Bibliotecas (Redux, etc): +30-50 KB
Svelte:
Base: ~2 KB (helpers mínimos)
+ Componentes: cresce linearmente (mas código mais eficiente)
+ Stores nativos: 0 KB adicional
Em apps grandes, a diferença diminui proporcionalmente,
mas Svelte sempre começa menor. Performance de Atualização
// Benchmark: Atualizar 1000 itens em uma lista
// React (Virtual DOM)
// 1. Cria 1000 objetos Virtual DOM novos
// 2. Compara com 1000 objetos anteriores
// 3. Identifica mudanças
// 4. Aplica ao DOM
// Tempo: ~15-25ms
// Svelte (DOM Direto)
// 1. Atualiza diretamente os elementos que mudaram
// Tempo: ~3-8ms Quando Cada Abordagem Brilha
React (Runtime) é Melhor Quando:
- 🏢 Ecossistema é prioridade — milhares de bibliotecas
- 👥 Time grande — mais fácil encontrar desenvolvedores
- 🔄 Mudanças dinâmicas intensas — Virtual DOM amortiza custo
- 🧪 Padrões estabelecidos — arquiteturas bem documentadas
Svelte (Compilador) é Melhor Quando:
- ⚡ Performance é crítica — apps que precisam ser rápidos
- 📱 Mobile/Low-end devices — menos JS = mais rápido
- 📦 Bundle size importa — landing pages, widgets, embeds
- 🎯 DX é prioridade — menos boilerplate, código mais limpo
- 🆕 Projeto novo — sem bagagem de código legado
Exemplo Comparativo Completo
React
// Counter.jsx
import { useState, useCallback, useMemo } from 'react'
import './Counter.css'
export function Counter({ initialValue = 0, step = 1 }) {
const [count, setCount] = useState(initialValue)
const increment = useCallback(() => {
setCount(c => c + step)
}, [step])
const decrement = useCallback(() => {
setCount(c => c - step)
}, [step])
const isEven = useMemo(() => count % 2 === 0, [count])
return (
<div className="counter">
<span className={isEven ? 'even' : 'odd'}>
{count}
</span>
<button onClick={decrement}>-{step}</button>
<button onClick={increment}>+{step}</button>
</div>
)
}
// Linhas: 24
// Imports: 3 hooks
// Bundle: +43KB base + código Svelte
<!-- Counter.svelte -->
<script>
export let initialValue = 0
export let step = 1
let count = initialValue
function increment() {
count += step
}
function decrement() {
count -= step
}
$: isEven = count % 2 === 0
</script>
<div class="counter">
<span class:even={isEven} class:odd={!isEven}>
{count}
</span>
<button on:click={decrement}>-{step}</button>
<button on:click={increment}>+{step}</button>
</div>
<style>
.counter { /* estilos */ }
.even { color: green; }
.odd { color: blue; }
</style>
<!-- Linhas: 28 (incluindo CSS!)
Imports: 0
Bundle: ~3KB base + código --> ✅ Desafio da Aula
Objetivo
Analisar o output do compilador Svelte para entender o que ele gera.
Instruções
- Vá para svelte.dev/repl
- Escreva um componente simples com uma variável e um botão
- Clique na aba “JS output” para ver o código gerado
- Identifique:
- Onde o elemento é criado
- Onde o evento é adicionado
- Onde a atualização acontece
Spec de Verificação
- Você consegue identificar a função
create_fragment - Você encontrou onde o
addEventListeneré chamado - Você encontrou a função de update (
p) - Você entende que não há Virtual DOM no código gerado
Reflexão
Responda mentalmente:
- O código gerado usa
document.createElementou React.createElement? - Existe algum “diff” sendo feito?
- Onde está o “Svelte” no código gerado?
📚 Recursos Adicionais
- Svelte: Rethinking Reactivity (Rich Harris)
- Virtual DOM is pure overhead
- Svelte REPL — veja o output do compilador
Próxima aula: 2.2 — Reatividade: atribuição vs hooks