Loading...
Loading...
(heropy) Use when migrating an existing Vite + React (TypeScript) project to Next.js (App Router, v16). Converts entry points, routing (React Router → App Router), environment variables, path aliases, static assets, and styling setup.
npx skill4agent add parkyoungwoong/skills react-vite-to-next-migration| 확인 대상 | 감지 방법 |
|---|---|
| Vite 프로젝트 | |
| TypeScript | |
| React Router | |
| TanStack Query | |
| Zustand | |
| Tailwind CSS | |
| 환경 변수 | |
| 정적 자산 | |
| 진입점 | |
| 패키지 매니저 | |
vite.config.*src/appVITE_NEXT_PUBLIC_'use client'index.htmlvite.config.*src/main.tsxsrc/vite-env.d.ts{pm} remove vite @vitejs/plugin-react @vitejs/plugin-react-swc vite-tsconfig-paths @tailwindcss/vite react-router react-router-dom
{pm} install next@latest react@latest react-dom@latest
{pm} install -D @types/node은 1단계에서 감지한 패키지 매니저로 대체한다. 존재하지 않는 패키지는{pm}대상에서 제외한다.remove
package.jsonscripts{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
}vite.config.tsvite.config.jsindex.htmlsrc/vite-env.d.tsnext.config.tsimport type { NextConfig } from 'next'
const nextConfig: NextConfig = {
reactStrictMode: true
}
export default nextConfigtsconfig.jsonpaths{
"compilerOptions": {
"target": "ES2022",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}기존,tsconfig.app.json은 삭제한다.tsconfig.node.json
src/app/layout.tsxindex.html<head>import type { Metadata } from 'next'
import './globals.css'
export const metadata: Metadata = {
title: 'App',
description: ''
}
export default function RootLayout({
children
}: Readonly<{
children: React.ReactNode
}>) {
return (
<html lang="ko">
<body>{children}</body>
</html>
)
}src/index.csssrc/app/globals.css@import 'tailwindcss';src/main.tsxsrc/App.tsxsrc/App.csscreateBrowserRouter<Routes>| React Router | App Router |
|---|---|
| |
| |
| |
| |
| 공통 레이아웃 컴포넌트 | |
useNavigateuseLocationuseParams<Link>useNavigate()useRouter()next/navigationuseParams()paramsasyncawait paramsuseLocation().pathnameusePathname()next/navigation<Link to="..."><Link href="...">next/linkuseStateuseEffect'use client'src/main.tsxsrc/App.tsxsrc/App.csssrc/routes/index.tsxsrc/app/**/page.tsx.env.env.local.env.development.env.production.env*VITE_FOO=barNEXT_PUBLIC_FOO=barimport.meta.env.VITE_FOOprocess.env.NEXT_PUBLIC_FOOimport.meta.env.MODEprocess.env.NODE_ENVimport.meta.env.DEVprocess.env.NODE_ENV !== 'production'import.meta.env.PRODprocess.env.NODE_ENV === 'production'import.meta.env.BASE_URLnext.config.tsbasePathpublic//vite.svgimport logo from './assets/logo.svg'public/next/image<Image src="/logo.svg" ... />@tailwindcss/vite{pm} install -D tailwindcss @tailwindcss/postcss postcsspostcss.config.mjsexport default {
plugins: {
'@tailwindcss/postcss': {}
}
}src/app/globals.css@import 'tailwindcss';QueryClientProviderreact-next-scaffold{pm} install @tanstack/react-query-next-experimentalsrc/providers/query.tsx'use client'QueryClientProviderReactQueryStreamedHydrationsrc/app/layout.tsx<body>children<QueryProvider>'use client'node_modulesrm -rf node_modules
{pm} install.gitignore.next/next-env.d.ts{pm} run build'use client'import.meta.env'use client'pnpm-lock.yamlpnpmyarn.lockyarnbun.lockbbun.lockbunpackage-lock.jsonnpmreact-next-scaffold