# React+Vite에서 Next.js 15로의 마이그레이션 보고서

## 1. 개요

본 문서는 React+Vite로 개발된 ESG GenAI 프로젝트를 Next.js 15로 마이그레이션하는 과정을 기록하고 있습니다. 마이그레이션 작업은 성능 개선, 서버 사이드 렌더링, 코드 스플리팅 등 Next.js의 고급 기능을 활용하기 위해 진행되었습니다. 단계적 접근법을 통해 기존 기능을 유지하면서 점진적으로 Next.js로 전환하였습니다.

**마이그레이션 기간**: 2025년 5월 21일

**마이그레이션 목표**:
- React 19 및 Next.js 15로의 업그레이드
- 기존 기능의 완전한 유지
- 클라이언트 사이드 렌더링(SPA) 방식 유지
- 향후 서버 사이드 렌더링으로의 점진적 전환 기반 마련

## 2. 마이그레이션 세부 단계

### 2.1 환경 준비 및 의존성 설치

```bash
npm install next@latest react@latest react-dom@latest

수정 내용:

2.2 Next.js 설정 파일 생성

Next.js 구성을 위한 next.config.mjs 파일을 생성했습니다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'export', // SPA로 출력하여 기존 동작 방식 유지
  distDir: './dist', // 기존 빌드 출력 디렉토리와 일치시킴
  images: {
    unoptimized: true, // SPA 모드에서 필요
  },
  transpilePackages: [], // 필요한 패키지 추가
}

export default nextConfig

설정 포인트:

2.3 App Router 디렉토리 구조 구성

Next.js App Router에 필요한 기본 구조를 src/app 디렉토리에 생성했습니다.

주요 파일:

기능별 라우팅 구조:

2.4 서버/클라이언트 컴포넌트 분리

Next.js의 서버 컴포넌트와 클라이언트 컴포넌트 아키텍처를 적용했습니다.

수정 내용:

// src/components/providers.tsx
'use client';

import React from "react";
import { Toaster } from "./ui/toaster";
import { Toaster as Sonner } from "./ui/sonner";
import { TooltipProvider } from "./ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";

const queryClient = new QueryClient();

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <QueryClientProvider client={queryClient}>
      <TooltipProvider>
        <Toaster />
        <Sonner />
        {children}
      </TooltipProvider>
    </QueryClientProvider>
  );
}

2.5 라우팅 시스템 마이그레이션

React Router DOM에서 Next.js App Router로의 점진적 마이그레이션을 진행했습니다.

수정 내용:

// src/components/ESGSidebar.tsx 수정
import Link from 'next/link';
import { usePathname } from 'next/navigation';

// 기존 onClick 이벤트 기반 네비게이션에서 href 기반 링크로 변경
const NavItem = ({ icon: Icon, label, active = false, collapsed = false, href }: NavItemProps) => {
  return (
    <Link href={href}>
      <Button
        variant="ghost"
        className={cn(
          'w-full justify-start gap-3 px-3 py-2 text-sm font-medium',
          collapsed ? 'justify-center' : '',
          active ? 'bg-sidebar-accent text-sidebar-accent-foreground' : 'text-sidebar-foreground'
        )}
      >
        <Icon className="h-5 w-5" />
        {!collapsed && <span>{label}</span>}
      </Button>
    </Link>
  );
};

2.6 스크립트 및 설정 업데이트

package.json의 스크립트와 관련 설정 파일들을 수정했습니다.

수정 내용:

"scripts": {
  "dev": "next dev -p 3000",
  "build": "next build",
  "start": "next start -p 3000"
}

.gitignore 파일에 Next.js 관련 항목을 추가했습니다:

.next
next-env.d.ts

2.7 TypeScript 설정 업데이트

TypeScript 설정을 Next.js에 맞게 조정했습니다.

// tsconfig.json
{
  "compilerOptions": {
    // ...기존 설정...
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    // ...기타 설정...
  },
  "include": [
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    "next-env.d.ts",
    "./dist/types/**/*.ts"
  ]
}

2.8 Vite 관련 파일 정리

Vite 관련 파일 및 설정을 제거하였습니다.

삭제된 파일:

3. 발생한 문제 및 해결 방법

3.1 무한 리디렉션 문제

문제 상황:

원인:

해결 방법:

'use client';

import React from "react";
import Dashboard from "@/components/Dashboard";
import SiteLayout from "@/components/SiteLayout";

export default function Home() {
  return (
    <SiteLayout>
      <Dashboard />
    </SiteLayout>
  );
}

3.2 클라이언트/서버 컴포넌트 호환성 문제

문제 상황:

해결 방법:

3.3 설정 파일 경고

문제 상황:

해결 방법:

4. 결론 및 개선 사항

4.1 마이그레이션 결과

4.2 향후 개선 방향

  1. 서버 컴포넌트 활용 확대

  2. 이미지 최적화

  3. 폰트 최적화

  4. 정적 생성과 동적 렌더링 혼합

  5. API 라우트 활용

이번 마이그레이션을 통해 React+Vite 기반의 SPA를 Next.js 기반의 애플리케이션으로 성공적으로 전환하였으며, 향후 Next.js의 다양한 고급 기능을 점진적으로 도입할 수 있는 기반을 마련하였습니다.