Rain Lag

От React-приложения к боевому Next.js: практическое руководство по первой миграции

Практическое пошаговое руководство по миграции с Create React App (CRA) на готовый к продакшену Next.js в 2025 году — почему стоит перейти, как спланировать миграцию и какие подводные камни учесть.

От React-приложения к боевому Next.js: практическое руководство по первой миграции

Если вы создавали своё приложение с помощью Create React App (CRA) несколько лет назад, вы далеко не одиноки — и вы точно не одни, если эта конфигурация начала ощущаться ограничивающей.

В 2025 году Next.js стал де-факто стандартом для продакшен‑приложений на React, особенно если вам важны:

  • Производительность
  • SEO и удобно шарящиеся страницы
  • Масштабируемость и сопровождаемость
  • Современные full‑stack‑возможности

Хорошая новость: миграция с CRA на Next.js — это уже хорошо проторенная, практическая дорожка. Многие команды уже прошли этот путь — иногда с крупными и сложными кодовыми базами — и общие паттерны хорошо понятны. В этом посте мы разберём вашу первую миграцию с CRA к боевому приложению на Next.js, делая упор на практические шаги, а не теорию.


Зачем мигрировать с CRA на Next.js в 2025 году?

Прежде чем переходить к «как», важно чётко понимать «зачем».

1. Next.js — это уже full‑stack‑платформа, а не «просто React‑фреймворк»

Next.js начинался как фреймворк для серверного рендеринга React. Сегодня это полноценная full‑stack‑платформа, которая даёт вам:

  • Маршрутизацию на основе файловой системы (без ручной настройки react-router)
  • Получение данных на сервере (SSR, SSG, ISR)
  • API‑роуты, server actions и edge‑функции
  • Встроенную оптимизацию изображений, шрифтов и аналитику
  • Первоклассную поддержку TypeScript и современных бандлеров

Для многих команд это означает единую платформу вместо «склейки» CRA + Express + кастомный SSR + конфигурации Webpack.

2. Лучшая производительность и SEO «из коробки»

CRA собирает Single Page Application (SPA), где всё рендерится на клиенте после загрузки JavaScript. Это может ухудшать:

  • First Contentful Paint и Core Web Vitals
  • SEO, поскольку краулеры без JS могут почти ничего не увидеть в HTML

Next.js предоставляет:

  • Server-Side Rendering (SSR) для динамического контента
  • Static Site Generation (SSG) для быстрых, кешируемых страниц
  • Incremental Static Regeneration (ISR) для гибридных сценариев

Во многих реальных миграциях сразу заметны улучшения скорости страниц, показателей Lighthouse и позиций в поиске.

3. Проверен на крупных проектах

Крупные open source и коммерческие приложения уже мигрировали с «ванильного» React на Next.js, показав:

  • Реализуемость миграции даже для больших кодовых баз
  • Сопровождаемость конвенций Next.js на длительном горизонте
  • Возможность постепенного перехода на Next.js без тотального переписывания

Вы идёте не в неизвестность — вы следуете по пути, который уже прошли многие.


Стратегия миграции: не переписывать с нуля, а внедрять по шагам

Самый быстрый способ провалить миграцию — воспринимать её как полный рефакторинг «с нуля». Вместо этого думайте о ней как о пошаговом процессе.

Практичный подход:

  1. Создать новый проект на Next.js
  2. Отзеркалить структуру CRA в app или pages
  3. Сначала перенести общий код (компоненты, хуки, утилиты)
  4. Постепенно переносить маршруты/страницы
  5. Вводить серверные возможности (SSR/SSG, API‑роуты), когда всё стабилизируется
  6. Подготовить приложение к продакшену (окружения, CI/CD, мониторинг)

Разберём по шагам.


Шаг 1: Настройте новый проект на Next.js

В корне репозитория (или в новом репо) выполните:

npx create-next-app@latest

Вам зададут несколько вопросов. Типичные продакшен‑настройки для 2025 года:

  • TypeScript: Yes
  • ESLint: Yes
  • App Router (по умолчанию): Yes — это современная система роутинга Next.js
  • Tailwind (опционально): Yes, если вы уже его используете или хотите utility‑CSS

В итоге вы получите полностью настроенное приложение на Next.js с адекватными настройками по умолчанию.

Совет: создайте проект в соседней папке (например, my-app-next), чтобы во время миграции удобно ссылаться на существующий код CRA.


Шаг 2: Поймите ключевые отличия

Перед переносом файлов важно согласовать основные концептуальные изменения.

1. Маршрутизация

  • CRA: обычно использует react-router с кастомной конфигурацией Routes.
  • Next.js: роутинг основан на файловой структуре.
    • В App Router маршруты живут в app/<route>/page.tsx.
    • Вложенные папки соответствуют вложенным маршрутам.

Пример:

app/ page.tsx -> / dashboard/ page.tsx -> /dashboard blog/ [slug]/ page.tsx -> /blog/:slug

2. Точка входа

  • CRA: src/index.tsx монтирует <App /> в корневой div.
  • Next.js: вы не вызываете ReactDOM.render вручную. Next делает это сам. Вы описываете страницы и layout’ы.

3. Получение данных

  • CRA: всё получение данных происходит на клиенте (например, в useEffect).
  • Next.js: вы можете получать данные на сервере (в page.tsx, layout.tsx или server actions) или на клиенте.

Это серьёзный сдвиг и ключевая причина, почему улучшаются производительность и SEO.


Шаг 3: Сначала перенесите общий код

Начните с частей, которые не завязаны на роутинг или особенности получения данных.

Перенесите из src/ в CRA в app/ или верхнеуровневый src/ в Next.js:

  • UI‑компоненты (кнопки, формы, модалки)
  • Хуки (useAuth, useTheme и т.п.)
  • Утилитарные функции (форматтеры, API‑клиенты)
  • Стили (CSS‑модули, конфигурация Tailwind, глобальные стили)

Старайтесь сохранить пути импорта максимально похожими. Если вы использовали абсолютные импорты в CRA, настройте их в jsconfig.json или tsconfig.json в Next.js.

Пример tsconfig.json с alias‑путями:

{ "compilerOptions": { "baseUrl": ".", "paths": { "@/components/*": ["./components/*"], "@/lib/*": ["./lib/*"] } } }

Шаг 4: Перенесите маршруты в страницы Next.js

Теперь можно мигрировать сами представления.

Отразите роуты CRA в структуре Next.js

Если ваш App.tsx в CRA выглядит так:

<Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> <Route path="/products/:id" element={<ProductDetail />} /> </Routes>

В App Router Next.js вы можете создать такую структуру:

app/ page.tsx -> Home about/ page.tsx -> About products/ [id]/ page.tsx -> ProductDetail

Скопируйте каждый компонент страницы из CRA в соответствующий page.tsx. При необходимости поправьте импорты.

Используйте layout’ы для общего UI

Если в CRA ваш App.tsx оборачивает все страницы в общий layout (navbar, footer и т.п.), перенесите эту логику в app/layout.tsx.

// app/layout.tsx import "./globals.css"; import { ReactNode } from "react"; export default function RootLayout({ children }: { children: ReactNode }) { return ( <html lang="en"> <body> <Header /> <main>{children}</main> <Footer /> </body> </html> ); }

Так вы уменьшите дублирование и централизуете все кросс‑страничные вещи.


Шаг 5: Постепенно внедряйте SSR и SSG

На первых этапах вы можете оставить клиентский фетчинг данных, чтобы минимизировать поведение, отличающееся от CRA. Для страниц или компонентов, использующих хуки вроде useState или useEffect, в App Router добавьте директиву "use client" в самом верху файла.

"use client"; export default function DashboardPage() { // client-side hooks and effects here }

После того как всё стабилизируется, начинайте переносить получение данных на сервер там, где это оправдано.

Пример: перевод «тяжёлой» по данным страницы на серверный рендеринг

Версия в CRA:

function BlogPost() { const { slug } = useParams(); const [post, setPost] = useState<Post | null>(null); useEffect(() => { fetch(`/api/posts/${slug}`) .then(res => res.json()) .then(setPost); }, [slug]); // render }

Server‑rendered‑страница в Next.js (App Router):

// app/blog/[slug]/page.tsx async function getPost(slug: string) { const res = await fetch(`${process.env.API_URL}/posts/${slug}`, { cache: "no-store", }); if (!res.ok) throw new Error("Failed to fetch post"); return res.json(); } export default async function BlogPostPage({ params, }: { params: { slug: string }; }) { const post = await getPost(params.slug); return ( <article> <h1>{post.title}</h1> <div dangerouslySetInnerHTML={{ __html: post.content }} /> </article> ); }

Теперь HTML статьи генерируется на сервере, что улучшает SEO и первоначальную скорость загрузки.


Шаг 6: Используйте Next.js для backend‑логики (API‑роуты и Server Actions)

Next.js — это не только рендеринг; это full‑stack‑платформа.

Если раньше у вас были:

  • Отдельный сервер на Node/Express
  • Или «самодельный» API прямо внутри проекта CRA

Во многих случаях можно перенести эндпоинты в API‑роуты Next.js или server actions.

Пример API‑роута:

// app/api/posts/[id]/route.ts import { NextResponse } from "next/server"; export async function GET(_: Request, { params }: { params: { id: string } }) { const post = await db.posts.find(params.id); return NextResponse.json(post); }

Так фронтенд‑ и бэкенд‑логика оказываются в одном, цельном кодовом базе.


Шаг 7: Подготовьте приложение к продакшену

Продакшен‑готовое приложение на Next.js — это больше, чем просто «всё работает локально».

Переменные окружения

Используйте .env.local, .env.production и т.п., обращайтесь к ним через process.env.MY_KEY. Настройте переменные в платформе деплоя (Vercel, AWS, Netlify и др.).

Сборка и деплой

  • Настройте CI‑пайплайн (npm run lint, npm run test, npm run build).
  • Убедитесь, что ваш хостинг поддерживает используемые фичи Next.js (SSR, edge‑функции и т.п.).
  • Следите за размером бандла и производительностью (вывод next build, Lighthouse).

Обозримость и наблюдаемость

  • Добавьте логирование и отслеживание ошибок (Sentry, LogRocket и др.).
  • Используйте встроенную аналитику Next или свои инструменты.

На этом этапе реальные миграции особенно окупаются: команды часто отмечают упрощение пайплайна деплоя и более предсказуемую производительность после перехода на Next.js.


Частые ловушки и как их избежать

  • Смешивание клиентских и серверных концепций: в App Router чётко разделяйте серверные компоненты (по умолчанию) и клиентские ("use client").
  • Чрезмерное использование клиентских компонентов: помечайте компонент как клиентский только если ему нужны хуки, браузерные API или обработчики событий; всё остальное оставляйте серверным ради производительности.
  • Игнорирование SEO и метаданных: используйте metadata API Next или аналоги <Head> для настройки title, description и Open Graph‑данных для каждой страницы.
  • «Большой взрыв» (big-bang) переписывания: мигрируйте постепенно. Доставляйте маленькие части, проверяйте, затем двигайтесь дальше.

Итог: первая миграция — только начало

Переход с Create React App на Next.js больше не выглядит рискованным экспериментом; это проверенный путь модернизации, который выравнивает ваше приложение с тем, как в 2025 году принято создавать и развёртывать React‑проекты.

Если следовать структурированному, поэтапному подходу:

  1. Создать приложение на Next.js
  2. Перенести общие компоненты и утилиты
  3. Перевести роуты в файловые страницы
  4. Постепенно внедрять серверный рендеринг и статическую генерацию
  5. Консолидировать backend‑логику в API‑роутах и серверных фичах
  6. Подготовить инфраструктуру к реальному продакшен‑трафику

В итоге вы получите не просто «React‑приложение, которое работает», а боевую full‑stack‑платформу: быстрее, масштабируемее и гораздо лучше оптимизированную под SEO и современные ожидания пользователей.

Первая миграция научит вас основным паттернам. После неё Next.js станет не просто ещё одним инструментом, а дефолтным способом думать о создании веб‑приложений на React.

От React-приложения к боевому Next.js: практическое руководство по первой миграции | Rain Lag