Deploy e CI/CD Frontend: Guia Completo 2025

January 15, 2025 (1y ago)

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:

Estatísticas impressionantes:


🛠️ 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 }} --prod

2. 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 }} --prod

3. 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=false

2. 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 }} --prod

2. 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:

Pipeline:

Monitoramento:

Segurança:

Performance:


🎯 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:

Próximos passos:

  1. Configure CI/CD no seu projeto
  2. Automatize o máximo possível
  3. Monitore e meça resultados
  4. Evolua continuamente

Lembre-se: CI/CD é um processo, não um destino! 🚀

Allisson Lima
Desenvolvedor Frontend | Especialista em DevOps e Deploy