Como acelerar builds no Node.js
1. Diagnóstico do gargalo no build
Antes de otimizar, é essencial entender onde o tempo está sendo perdido. Ferramentas de profiling ajudam a identificar os pontos críticos:
# Listar dependências com tamanhos
npm ls --depth=0
# Analisar tempo de execução de scripts
npm run build -- --timing
# Profiling detalhado com webpack
webpack --profile --json > stats.json
Para builds com webpack, utilize o webpack-bundle-analyzer para visualizar o tamanho de cada módulo:
npm install --save-dev webpack-bundle-analyzer
npx webpack-bundle-analyzer stats.json
Logs detalhados no webpack.config.js:
module.exports = {
stats: {
timings: true,
builtAt: true,
performance: true,
},
};
2. Otimização do gerenciador de pacotes
A escolha do gerenciador impacta diretamente a velocidade de instalação e cache:
# Substituir npm por pnpm (instalação paralela)
npm install -g pnpm
pnpm install
# Usar yarn com cache eficiente
yarn install --prefer-offline
# Configurar cache local no npm
npm config set cache /path/to/cache
npm install --prefer-offline
Lockfiles são cruciais para evitar redownloads:
# pnpm-lock.yaml garante instalações determinísticas
pnpm install --frozen-lockfile
# yarn.lock com yarn install --frozen-lockfile
yarn install --frozen-lockfile
3. Paralelização e concorrência no processo de build
Execute tarefas independentes simultaneamente com concurrently:
npm install --save-dev concurrently
Configuração no package.json:
{
"scripts": {
"lint": "eslint src/",
"test": "jest",
"build": "webpack --mode production",
"dev": "concurrently \"npm run lint\" \"npm run test\" \"npm run build\""
}
}
Para webpack, utilize thread-loader para paralelizar a transpilação:
npm install --save-dev thread-loader
Configuração no webpack.config.js:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: [
'thread-loader',
'babel-loader'
]
}
]
}
};
Com parallel-webpack, é possível executar múltiplas configurações em paralelo:
npm install --save-dev parallel-webpack
npx parallel-webpack --config webpack.config.js
4. Redução do escopo e do tamanho do bundle
Tree shaking elimina código morto automaticamente quando usado com módulos ES:
// webpack.config.js
module.exports = {
mode: 'production',
optimization: {
usedExports: true,
sideEffects: false,
},
};
Code splitting com importações dinâmicas:
// Em vez de importação estática
// import { heavyModule } from './heavy';
// Use importação dinâmica
const heavyModule = await import('./heavy');
Configuração de divisão de código no webpack:
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000,
maxSize: 70000,
},
},
};
5. Aproveitamento de ferramentas modernas e nativas
Substitua webpack por esbuild para compilação extremamente rápida:
npm install --save-dev esbuild
Script de build com esbuild:
{
"scripts": {
"build": "esbuild src/index.js --bundle --outfile=dist/bundle.js --minify"
}
}
Para desenvolvimento, Vite oferece HMR quase instantâneo:
npm create vite@latest my-app -- --template react
cd my-app
npm install
npm run dev
Para projetos Next.js, ative o turbopack:
# next.config.js
module.exports = {
experimental: {
turbo: true,
},
};
6. Configuração de cache inteligente e incremental
Ative cache persistente no webpack:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
};
Para monorepos, Turborepo oferece cache de tarefas:
npm install -g turbo
Configuração no turbo.json:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"],
"cache": true
}
}
}
Build incremental no TypeScript:
{
"compilerOptions": {
"incremental": true,
"tsBuildInfoFile": ".tsbuildinfo"
}
}
7. Boas práticas de dependências e ambiente
Remova dependências não utilizadas com depcheck:
npm install -g depcheck
depcheck --ignores=eslint,jest
No CI, instale apenas dependências de produção:
npm ci --production
# ou
npm install --production
Configure variáveis de ambiente para evitar recompilações:
# .env
NODE_ENV=production
API_URL=https://api.exemplo.com
# webpack.config.js
const webpack = require('webpack');
require('dotenv').config();
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
}),
],
};
Use --watch para builds incrementais durante desenvolvimento:
# webpack --watch
webpack --watch --mode development
# esbuild --watch
esbuild src/index.js --bundle --outfile=dist/bundle.js --watch
Conclusão
Acelerar builds no Node.js envolve uma combinação de diagnóstico preciso, escolha de ferramentas modernas e configurações inteligentes de cache e paralelização. Comece identificando os gargalos com profiling, substitua gerenciadores lentos por alternativas como pnpm, utilize ferramentas nativas como esbuild ou Vite, e configure caching incremental. Monorepos se beneficiam enormemente de ferramentas como Turborepo, enquanto projetos menores podem ver ganhos significativos apenas com tree shaking e code splitting.
Lembre-se de que cada projeto tem necessidades específicas; teste cada otimização em seu contexto antes de adotá-la em produção. A combinação correta pode reduzir o tempo de build de minutos para segundos.
Referências
- Documentação oficial do pnpm — Motivação e comparação de desempenho com npm e yarn
- Webpack Performance Guide — Guia oficial de otimização de performance de build
- esbuild Documentation — Documentação completa da ferramenta de bundling ultrarrápida
- Vite Documentation — Guia oficial do Vite para desenvolvimento rápido com HMR
- Turborepo Documentation — Documentação oficial para cache de tarefas em monorepos
- Webpack Bundle Analyzer — Ferramenta de análise visual do bundle
- Thread-loader webpack — Documentação oficial do loader de paralelização
- TypeScript Incremental Builds — Configuração de compilação incremental no TypeScript
- depcheck — Ferramenta para identificar dependências não utilizadas
- Concurrently — Pacote npm para execução paralela de scripts