Deploy no Vercel, Netlify ou Cloudflare Pages

1. Visão Geral das Plataformas e Casos de Uso

Escolher a plataforma certa para deploy é uma decisão estratégica que impacta performance, custos e experiência de desenvolvimento. Vamos analisar cada uma:

Vercel é a plataforma criada pelos desenvolvedores do Next.js. Ela oferece integração nativa com frameworks React, suporte a Serverless Functions e Edge Functions. Ideal para projetos que usam Next.js ou precisam de renderização híbrida (SSR + SSG).

Netlify se destaca pela flexibilidade com React puro (SPA), formulários nativos e funções serverless. Sua CLI é madura e o sistema de preview deployments é um dos melhores do mercado.

Cloudflare Pages foca em performance global máxima, aproveitando a rede edge da Cloudflare. Com Workers e Pages Functions, você executa lógica serverless em mais de 300 datacenters pelo mundo.

2. Preparação do Projeto React para Deploy

Antes do deploy, seu projeto precisa estar configurado corretamente:

// package.json - scripts essenciais
{
  "scripts": {
    "build": "react-scripts build",
    "start": "react-scripts start",
    "test": "react-scripts test"
  }
}

Para variáveis de ambiente, use o prefixo REACT_APP_:

// .env.production
REACT_APP_API_URL=https://api.exemplo.com
REACT_APP_ANALYTICS_ID=UA-XXXXX-Y

Para rotas SPA (Single Page Application), configure o fallback para index.html:

// vercel.json (Vercel)
{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
}
// _redirects (Netlify)
/*    /index.html   200
// _redirects (Cloudflare Pages)
/* /index.html 200

3. Deploy no Vercel com React/Next.js

O deploy via Vercel é extremamente simples. Primeiro, instale a CLI:

npm i -g vercel
vercel login
vercel --prod

Para funções serverless, crie uma pasta api/:

// api/hello.js
export default function handler(req, res) {
  res.status(200).json({ message: 'Hello from Vercel Serverless!' });
}

Configuração avançada com vercel.json:

{
  "headers": [
    {
      "source": "/api/(.*)",
      "headers": [
        { "key": "Access-Control-Allow-Origin", "value": "*" }
      ]
    }
  ],
  "crons": [
    {
      "path": "/api/cron",
      "schedule": "0 0 * * *"
    }
  ]
}

4. Deploy no Netlify com React

Conecte seu repositório GitHub/GitLab no dashboard do Netlify. Configure o build:

// Comandos de build no Netlify
Build command: npm run build
Publish directory: build

Netlify Functions (Node.js):

// netlify/functions/hello.js
exports.handler = async (event, context) => {
  return {
    statusCode: 200,
    body: JSON.stringify({ message: 'Hello from Netlify Lambda!' })
  };
};

Configuração com netlify.toml:

[build]
  command = "npm run build"
  functions = "netlify/functions"
  publish = "build"

[[redirects]]
  from = "/api/*"
  to = "/.netlify/functions/:splat"
  status = 200

[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "DENY"
    X-Content-Type-Options = "nosniff"

5. Deploy no Cloudflare Pages com React

Cloudflare Pages oferece integração com Workers para lógica serverless no edge:

// functions/hello.js (Pages Functions)
export async function onRequest(context) {
  return new Response(JSON.stringify({
    message: 'Hello from Cloudflare Edge!'
  }), {
    headers: { 'Content-Type': 'application/json' }
  });
}

Configuração de build via Wrangler CLI:

// wrangler.toml
name = "meu-app-react"
compatibility_date = "2024-01-01"

[site]
  bucket = "./build"
  entry-point = "functions"

Para cache e performance:

// functions/api/data.js
const cache = caches.default;

export async function onRequest(context) {
  const cachedResponse = await cache.match(context.request);
  if (cachedResponse) return cachedResponse;

  const data = await fetchDataFromAPI();
  const response = new Response(JSON.stringify(data), {
    headers: { 'Cache-Control': 'public, max-age=3600' }
  });

  context.waitUntil(cache.put(context.request, response.clone()));
  return response;
}

6. Comparação Prática: Qual Escolher?

Característica Vercel Netlify Cloudflare Pages
Plano gratuito 100GB bandwidth, 6000 build min/mês 100GB bandwidth, 300 build min/mês Ilimitado bandwidth, 500 build min/mês
Funções serverless 100h/mês 125k requisições/mês 100k requisições/dia
Edge computing Edge Functions (V8) Lambda@Edge Workers (V8)
Preview deployments Automático por branch Automático por branch Automático por branch
CLI vercel netlify-cli wrangler

Performance: Cloudflare Pages lidera em latência global devido à sua rede edge massiva. Vercel é excelente para Next.js. Netlify oferece o melhor equilíbrio entre features e facilidade de uso.

7. CI/CD e Automação de Deploy

GitHub Actions para deploy automático nas três plataformas:

// .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20

      - name: Install & Build
        run: |
          npm ci
          npm run build

      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v20
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.ORG_ID }}
          vercel-project-id: ${{ secrets.PROJECT_ID }}
          vercel-args: '--prod'

      - name: Deploy to Netlify
        uses: nwtgck/actions-netlify@v3.0
        with:
          publish-dir: './build'
          production-branch: main
          github-token: ${{ secrets.GITHUB_TOKEN }}
          deploy-message: "Deploy from GitHub Actions"
          netlify-config-path: ./netlify.toml
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

8. Boas Práticas e Troubleshooting

Erros comuns e soluções:

// Erro: Build fail por variável de ambiente ausente
// Solução: Verifique se as variáveis estão configuradas na plataforma

// Erro: 404 em rotas SPA
// Solução: Configure redirect para index.html (mostrado na seção 2)

// Erro: Função serverless timeout
// Solução: Aumente o timeout ou otimize a lógica

Segurança:

// Headers de segurança no vercel.json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Content-Security-Policy", "value": "default-src 'self'" },
        { "key": "Strict-Transport-Security", "value": "max-age=63072000" },
        { "key": "X-Content-Type-Options", "value": "nosniff" }
      ]
    }
  ]
}

Otimização de bundle:

// React.lazy para code splitting
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Carregando...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

Referências