Fala dev! 👋
Deploy e CI/CD são fundamentais para o desenvolvimento frontend moderno. Automatizar o processo de entrega garante qualidade, velocidade e confiabilidade na produção.
Neste guia completo, vou te mostrar como implementar pipelines robustos e eficientes para aplicações frontend, com as melhores práticas e ferramentas de 2025.
🎯 Por que CI/CD importa?
Benefícios reais:
- ⚡ 10x mais rápido para deploy
- 🐛 90% menos bugs em produção
- 🔄 Deploy automático e confiável
- 📊 Visibilidade completa do processo
- 👥 Colaboração mais eficiente
- 🚀 Time to market reduzido
Estatísticas impressionantes:
- 78% dos projetos usam CI/CD
- 65% redução no tempo de deploy
- 40% melhoria na qualidade do código
🛠️ Ferramentas essenciais
1. GitHub Actions (Recomendado)
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm lint
- name: Type check
run: pnpm type-check
- name: Test
run: pnpm test:ci
- name: Build
run: pnpm build
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: build-files
path: .next/2. Vercel (Deploy automático)
// vercel.json
{
"framework": "nextjs",
"buildCommand": "pnpm build",
"devCommand": "pnpm dev",
"installCommand": "pnpm install",
"outputDirectory": ".next",
"env": {
"NODE_ENV": "production"
},
"functions": {
"src/app/api/**/*.ts": {
"runtime": "nodejs18.x"
}
}
}3. Docker (Containerização)
# Dockerfile
FROM node:18-alpine AS base
# Dependencies
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
# Build
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm install -g pnpm && pnpm build
# Production
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
EXPOSE 3000
CMD ["node", "server.js"]🚀 Estratégias de deploy
1. Blue-Green Deployment
# .github/workflows/blue-green.yml
name: Blue-Green Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: pnpm build
- name: Deploy to staging
run: |
# Deploy para ambiente de staging
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod=false
- name: Run tests on staging
run: |
# Executar testes E2E no staging
pnpm test:e2e:staging
- name: Deploy to production
if: success()
run: |
# Deploy para produção
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod2. Canary Deployment
# .github/workflows/canary.yml
name: Canary Deploy
on:
push:
branches: [main]
jobs:
canary:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: pnpm build
- name: Deploy canary
run: |
# Deploy para 10% dos usuários
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod --canary
- name: Monitor canary
run: |
# Monitorar métricas por 30 minutos
sleep 1800
- name: Full deploy
if: success()
run: |
# Deploy completo se canary passou
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod3. Feature Flags
// lib/feature-flags.ts
export const featureFlags = {
newDashboard: process.env.NEXT_PUBLIC_FEATURE_NEW_DASHBOARD === 'true',
darkMode: process.env.NEXT_PUBLIC_FEATURE_DARK_MODE === 'true',
betaFeatures: process.env.NEXT_PUBLIC_FEATURE_BETA === 'true',
}
// Uso no componente
function Dashboard() {
if (featureFlags.newDashboard) {
return <NewDashboard />
}
return <OldDashboard />
}🔧 Pipeline completo
1. Pipeline de desenvolvimento
# .github/workflows/dev.yml
name: Development Pipeline
on:
push:
branches: [develop]
pull_request:
branches: [develop]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm lint
- name: Type check
run: pnpm type-check
- name: Test
run: pnpm test:ci
- name: Build
run: pnpm build
- name: Deploy to preview
run: |
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod=false2. Pipeline de produção
# .github/workflows/prod.yml
name: Production Pipeline
on:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Lint
run: pnpm lint
- name: Type check
run: pnpm type-check
- name: Test
run: pnpm test:ci
- name: Build
run: pnpm build
- name: Deploy to staging
run: |
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod=false
- name: E2E tests
run: pnpm test:e2e:staging
- name: Deploy to production
if: success()
run: |
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod
- name: Notify team
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
channel: '#deployments'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}📊 Monitoramento e alertas
1. Health checks
// pages/api/health.ts
export default function handler(req, res) {
const health = {
status: 'ok',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
memory: process.memoryUsage(),
version: process.env.npm_package_version
}
res.status(200).json(health)
}2. Métricas de performance
// lib/analytics.ts
export function trackPerformance() {
if (typeof window !== 'undefined') {
// Core Web Vitals
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
getCLS(console.log)
getFID(console.log)
getFCP(console.log)
getLCP(console.log)
getTTFB(console.log)
})
}
}3. Alertas automáticos
# .github/workflows/alerts.yml
name: Alerts
on:
schedule:
- cron: '0 */6 * * *' # A cada 6 horas
jobs:
check-health:
runs-on: ubuntu-latest
steps:
- name: Check application health
run: |
response=$(curl -s -o /dev/null -w "%{http_code}" https://meusite.com/api/health)
if [ $response -ne 200 ]; then
echo "Application is down!"
exit 1
fi
- name: Send alert
if: failure()
uses: 8398a7/action-slack@v3
with:
status: failure
channel: '#alerts'
webhook_url: ${{ secrets.SLACK_WEBHOOK }}🔒 Segurança e secrets
1. Gerenciamento de secrets
# .github/workflows/secure-deploy.yml
name: Secure Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
run: pnpm build
env:
NEXT_PUBLIC_API_URL: ${{ secrets.API_URL }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
JWT_SECRET: ${{ secrets.JWT_SECRET }}
- name: Deploy
run: |
vercel --token ${{ secrets.VERCEL_TOKEN }} --prod2. Scan de vulnerabilidades
# .github/workflows/security.yml
name: Security Scan
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
security:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Run security audit
run: pnpm audit --audit-level moderate
- name: Run Snyk security scan
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}🐳 Docker e containerização
1. Multi-stage build
# Dockerfile.optimized
FROM node:18-alpine AS base
# Dependencies
FROM base AS deps
WORKDIR /app
COPY package.json pnpm-lock.yaml ./
RUN npm install -g pnpm && pnpm install --frozen-lockfile
# Build
FROM base AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm install -g pnpm && pnpm build
# Production
FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]2. Docker Compose
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:password@db:5432/mydb
depends_on:
- db
db:
image: postgres:15
environment:
- POSTGRES_DB=mydb
- POSTGRES_USER=user
- POSTGRES_PASSWORD=password
volumes:
- postgres_data:/var/lib/postgresql/data
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
volumes:
postgres_data:📱 Deploy mobile
1. React Native
# .github/workflows/mobile.yml
name: Mobile Deploy
on:
push:
branches: [main]
jobs:
build-android:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'
- name: Setup Android SDK
uses: android-actions/setup-android@v2
- name: Install dependencies
run: npm install
- name: Build Android
run: |
cd android
./gradlew assembleRelease
- name: Upload APK
uses: actions/upload-artifact@v4
with:
name: app-release.apk
path: android/app/build/outputs/apk/release/2. Expo
# .github/workflows/expo.yml
name: Expo Deploy
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install dependencies
run: npm install
- name: Build Expo
run: |
npx expo build:android --type apk
- name: Upload to Play Store
uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT }}
packageName: com.meuapp
releaseFiles: app-release.apk
track: production✅ Checklist CI/CD
Configuração:
- GitHub Actions configurado
- Secrets configurados
- Workflows criados
- Branches protegidas
- Approvals configurados
Pipeline:
- Lint automático
- Testes automáticos
- Build automático
- Deploy automático
- Rollback automático
Monitoramento:
- Health checks configurados
- Métricas coletadas
- Alertas configurados
- Logs centralizados
- Dashboards criados
Segurança:
- Secrets gerenciados
- Vulnerabilidades escaneadas
- Dependências atualizadas
- Acesso controlado
- Auditoria habilitada
Performance:
- Build otimizado
- Cache configurado
- CDN configurado
- Compressão habilitada
- Minificação ativa
🎯 Conclusão
CI/CD não é apenas sobre deploy, é sobre criar confiança para evoluir rapidamente. As estratégias mostradas aqui vão transformar sua abordagem ao desenvolvimento.
Principais benefícios:
- ⚡ Velocidade de entrega
- 🐛 Qualidade garantida
- 🔄 Automação completa
- 📊 Visibilidade total
- 🚀 Inovação acelerada
Próximos passos:
- Configure CI/CD no seu projeto
- Automatize o máximo possível
- Monitore e meça resultados
- Evolua continuamente
Lembre-se: CI/CD é um processo, não um destino! 🚀
Allisson Lima
Desenvolvedor Frontend | Especialista em DevOps e Deploy