# 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
수정 내용:
Next.js 구성을 위한 next.config.mjs
파일을 생성했습니다.
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export', // SPA로 출력하여 기존 동작 방식 유지
distDir: './dist', // 기존 빌드 출력 디렉토리와 일치시킴
images: {
unoptimized: true, // SPA 모드에서 필요
},
transpilePackages: [], // 필요한 패키지 추가
}
export default nextConfig
설정 포인트:
output: 'export'
: 기존 SPA 방식 유지distDir: './dist'
: 기존 빌드 디렉토리 유지images.unoptimized: true
: 정적 내보내기 모드에서 이미지 최적화 비활성화Next.js App Router에 필요한 기본 구조를 src/app
디렉토리에 생성했습니다.
주요 파일:
layout.tsx
: 전체 애플리케이션의 레이아웃 정의page.tsx
: 루트 경로 페이지 구성not-found.tsx
: 404 오류 페이지globals.css
: 전역 스타일기능별 라우팅 구조:
(dashboard)/esg-report/page.tsx
: ESG 보고서 생성 페이지(dashboard)/risk-monitoring/page.tsx
: 리스크 모니터링 페이지(dashboard)/report-history/page.tsx
: 보고서 히스토리 페이지(dashboard)/settings/page.tsx
: 설정 페이지Next.js의 서버 컴포넌트와 클라이언트 컴포넌트 아키텍처를 적용했습니다.
수정 내용:
'use client'
지시어 추가
src/components/ui/toaster.tsx
src/components/ui/sonner.tsx
src/components/ui/tooltip.tsx
src/hooks/use-toast.ts
src/components/providers.tsx
생성// 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>
);
}
React Router DOM에서 Next.js App Router로의 점진적 마이그레이션을 진행했습니다.
수정 내용:
src/components/SiteLayout.tsx
생성Link
컴포넌트로 변환// 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>
);
};
package.json
의 스크립트와 관련 설정 파일들을 수정했습니다.
수정 내용:
"scripts": {
"dev": "next dev -p 3000",
"build": "next build",
"start": "next start -p 3000"
}
.gitignore
파일에 Next.js 관련 항목을 추가했습니다:
.next
next-env.d.ts
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"
]
}
Vite 관련 파일 및 설정을 제거하였습니다.
삭제된 파일:
main.tsx
index.html
vite-env.d.ts
tsconfig.node.json
vite.config.ts
문제 상황:
/
)에 접속 시 무한 리디렉션(307) 루프 발생원인:
src/app/page.tsx
에서 redirect('/')
호출 시 자기 자신으로 리디렉션이 발생해결 방법:
'use client';
import React from "react";
import Dashboard from "@/components/Dashboard";
import SiteLayout from "@/components/SiteLayout";
export default function Home() {
return (
<SiteLayout>
<Dashboard />
</SiteLayout>
);
}
문제 상황:
useState only works in Client Components
오류useTheme() from the server but useTheme is on the client
오류해결 방법:
'use client'
지시어 추가providers.tsx
로 분리하여 관리문제 상황:
next.config.mjs
에서 experimental.appDir
옵션에 대한 경고 발생해결 방법:
서버 컴포넌트 활용 확대
이미지 최적화
next/image
컴포넌트를 활용한 이미지 최적화폰트 최적화
next/font
모듈을 활용한 폰트 최적화정적 생성과 동적 렌더링 혼합
API 라우트 활용
/api
라우트를 활용한 서버리스 함수 구현이번 마이그레이션을 통해 React+Vite 기반의 SPA를 Next.js 기반의 애플리케이션으로 성공적으로 전환하였으며, 향후 Next.js의 다양한 고급 기능을 점진적으로 도입할 수 있는 기반을 마련하였습니다.