Capítulo 58 de 456

Create React App

Core Idea

Step-by-step migration of an existing Create React App (CRA) codebase into Next.js, starting as a client-only SPA and adopting Next.js features incrementally afterward.

Key Concepts

  • SPA-first migration strategy: keep the existing router/app logic client-side first (output: 'export'), then adopt App Router features incrementally — minimizes merge conflicts.
  • output: 'export': next.config.ts option that produces a static export; no SSR/API routes available while set.
  • Optional catch-all route ([[...slug]]): catches every path so a single page can serve the whole CRA app as an SPA during transition.
  • Client-only entrypoint via next/dynamic: wraps the old CRA root <App /> with dynamic(() => import(...), { ssr: false }) to fully disable server rendering for it.
  • Environment variable prefix change: REACT_APP_NEXT_PUBLIC_ for client-exposed env vars.
  • Static image imports: CRA returns a string URL; Next.js returns an object with a .src property (use <img src={logo.src} /> or the <Image> component).
  • Turbopack default: Next.js dev defaults to Turbopack instead of CRA's webpack; next dev --webpack restores webpack behavior for custom configs.

Code Examples

// app/[[...slug]]/client.tsx — client-only entrypoint wrapping the CRA app
'use client'

import dynamic from 'next/dynamic'

const App = dynamic(() => import('../../App'), { ssr: false })

export function ClientOnly() {
  return <App />
}
  • O que demonstra: como desabilitar SSR para reaproveitar o app CRA inteiro como client-only durante a transição.
// next.config.ts — initial SPA-mode config
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  output: 'export', // Outputs a Single-Page Application (SPA)
  distDir: 'build', // Changes the build output directory to `build`
}

export default nextConfig
  • O que demonstra: configuração mínima para rodar como SPA equivalente ao build do CRA.

Reference Tables

CRANext.js equivalente
public/index.htmlapp/layout.tsx
src/index.tsxapp/[[...slug]]/page.tsx (+ client.tsx)
REACT_APP_* env varsNEXT_PUBLIC_*
homepage em package.jsonbasePath em next.config.ts
proxy em package.jsonrewrites() em next.config.ts
service worker CRAnavigator.serviceWorker.register(new URL(...))
custom webpack/Babelwebpack() em next.config.ts (requer --webpack)

Anti-patterns

  • Migrar o router (React Router) junto com a infraestrutura: aumenta o risco de conflitos; a recomendação é primeiro rodar como SPA com Next.js e só depois trocar para o App Router.
  • Manter output: 'export' esperando usar useParams ou SSR: static export não suporta esses recursos; remover a flag para liberar recursos de servidor.
  • Deixar <img> sem .src ao trocar imports de imagem: import estático no Next.js retorna objeto, não string.

Key Takeaways

  1. A migração recomendada é em duas fases: primeiro virar SPA rodando em Next.js, depois adotar App Router/SSR incrementalmente.
  2. [[...slug]] + generateStaticParams retornando [{ slug: [''] }] é o padrão para capturar todas as rotas durante a fase SPA.
  3. next-env.d.ts precisa entrar no include do tsconfig.json para resolver erros de tipo em .src de imagens.
  4. react-scripts e artefatos específicos do CRA (reportWebVitals, react-app-env.d.ts) devem ser removidos ao final.
  5. Depois da migração, otimizações nativas (<Image>, next/font, <Script>) substituem soluções manuais do CRA.

Connects To

  • Vite (ch059): guia irmão com passos quase idênticos para quem vem de Vite em vez de CRA.
  • App Router (ch057): próximo passo depois de rodar como SPA, para adotar rotas de arquivo e Server Components.