Bundle Size e Code Splitting
Analisar bundle, lazy loading de rotas e componentes, e tree shaking. JS que o usuário nunca vê.
Definição
Bundle size impacta diretamente o tempo de carregamento inicial. Cada KB extra de JS = mais download + parse + compile antes de qualquer interação. As principais estratégias: code splitting por rota (lazy + Suspense), dynamic imports para componentes pesados, tree shaking (eliminar código não usado), e análise de bundle para identificar os maiores culpados.
Problema → Solução
Problema
Bundle inicial com todo o código da app: páginas que o usuário pode nunca visitar, bibliotecas inteiras importadas quando só um método é usado (`import _ from 'lodash'` = 70KB), e componentes pesados (editores, gráficos) carregados na home.Solução
React.lazy + Suspense para code splitting por rota e componente. Dynamic import para carregar sob demanda. Importações granulares: `import { debounce } from lodash-es` em vez de `import _ from lodash`. Analisar com @next/bundle-analyzer ou rollup-plugin-visualizer.Dica de entrevista
Tip
Metrica importante: First Load JS do Next.js (mostrado no build). Objetivo: < 100KB para rota inicial. Inspecione com `next build` — rotas marcadas com ○ (static) têm menor bundle. Dependências > 10KB sem uso crítico na home são candidatas a dynamic import.Código
// ✅ Code splitting por rota
import { lazy, Suspense } from 'react'
import { Routes, Route } from 'react-router-dom'
const Dashboard = lazy(() => import('./pages/Dashboard'))
const Settings = lazy(() => import('./pages/Settings'))
function App() {
return (
<Suspense fallback={<PageSkeleton />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
)
}
// ✅ Dynamic import de componente pesado
function Editor() {
const [MonacoEditor, setMonaco] = useState(null)
const loadEditor = async () => {
const { default: Monaco } = await import('@monaco-editor/react')
setMonaco(() => Monaco)
}
return MonacoEditor
? <MonacoEditor value={code} />
: <button onClick={loadEditor}>Abrir editor</button>
}
// ✅ Importação granular (tree-shakeable)
import { debounce } from 'lodash-es' // ✅ só debounce
// import _ from 'lodash' // ❌ 70KB inteirosPerguntas de entrevista
Q.Como funciona tree shaking?▾
A.Bundlers (Webpack, Rollup, Vite) analisam imports estáticos e eliminam código não referenciado. Funciona com ES modules (import/export). Não funciona com CommonJS (require). Por isso `import { debounce } from 'lodash-es'` (ES module) é tree-shakeable, mas `import _ from 'lodash'` (CJS) importa tudo. Verificar se a lib tem sideEffects: false no package.json.
Q.Qual a diferença entre lazy loading de rota e de componente?▾
A.Rota: `const Dashboard = lazy(() => import('./Dashboard'))` — carrega o chunk da rota só quando o usuário navega para ela. Componente: mesmo padrão mas para componentes pesados dentro de uma rota (ex: editor de texto, mapa, gráfico complexo). Ambos precisam de `<Suspense fallback={<Loading />}>` em volta.
Q.Como identificar o que está aumentando o bundle?▾
A.Next.js: `ANALYZE=true next build` com @next/bundle-analyzer — gera treemap visual. Vite: rollup-plugin-visualizer. Procurar: dependências grandes importadas inteiras, duplicação (mesma lib em versões diferentes), código de desenvolvimento incluído em prod. Ferramentas: bundlephobia.com para checar tamanho antes de instalar.
Termos relacionados
80/122← →