fe-migrate
SKILL.md
FE Migration Guide
$ARGUMENTS에서 마이그레이션 소스와 타겟을 파싱하여 단계별 가이드를 제공하고 실행한다.
지원 마이그레이션
| From | To | 키워드 |
|---|---|---|
| Pages Router | App Router | pages app-router |
| JavaScript | TypeScript | js typescript, js ts |
| CRA (Create React App) | Vite | cra vite |
| CSS/SCSS | Tailwind CSS | css tailwind |
| Class Components | Hooks | class hooks |
| Redux | Zustand | redux zustand |
| Jest | Vitest | jest vitest |
| Axios | Fetch | axios fetch |
| Moment.js | date-fns | moment date-fns |
인자가 없으면 사용자에게 어떤 마이그레이션을 원하는지 질문한다.
마이그레이션 공통 절차
- 현재 상태 분석: 프로젝트 구조, 의존성, 설정 파일을 파악한다
- 영향 범위 파악: 변경이 필요한 파일 목록을 Glob/Grep으로 추출한다
- 마이그레이션 계획 제시: 단계별 작업 목록을 사용자에게 보여준다
- 단계별 실행: 승인 후 순차적으로 변환을 진행한다
- 검증: 빌드 및 테스트 통과를 확인한다
Pages Router → App Router
단계별 가이드
1단계: 기반 설정
src/app/layout.tsx ← pages/_app.tsx 에서 이동
src/app/page.tsx ← pages/index.tsx 에서 이동
src/app/globals.css ← styles/globals.css 에서 이동
2단계: 페이지 변환 규칙
| Pages Router | App Router |
|---|---|
pages/about.tsx |
app/about/page.tsx |
pages/blog/[slug].tsx |
app/blog/[slug]/page.tsx |
pages/api/users.ts |
app/api/users/route.ts |
pages/_error.tsx |
app/error.tsx |
pages/404.tsx |
app/not-found.tsx |
3단계: 데이터 페칭 변환
// Before: getServerSideProps
export async function getServerSideProps() {
const data = await fetchData();
return { props: { data } };
}
export default function Page({ data }) { /* ... */ }
// After: Server Component async
export default async function Page() {
const data = await fetchData();
return /* ... */;
}
// Before: getStaticProps + getStaticPaths
export async function getStaticPaths() {
return { paths: [...], fallback: false };
}
export async function getStaticProps({ params }) {
const data = await fetchData(params.id);
return { props: { data }, revalidate: 60 };
}
// After: generateStaticParams + fetch with revalidate
export async function generateStaticParams() {
return [...];
}
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const data = await fetchData(id);
return /* ... */;
}
4단계: Hook/상태 사용 컴포넌트 → "use client"
useState,useEffect,useContext, 이벤트 핸들러가 있는 컴포넌트에"use client"추가- 가능한 Client Component를 작게 분리
5단계: Head → Metadata
// Before: next/head
import Head from "next/head";
<Head><title>Page</title></Head>
// After: Metadata export
export const metadata: Metadata = {
title: "Page",
};
JavaScript → TypeScript
단계별 가이드
1단계: TypeScript 설치 & 설정
pnpm add -D typescript @types/react @types/react-dom @types/node
npx tsc --init
2단계: 파일 확장자 변경
.js→.ts(로직 파일).jsx→.tsx(JSX 포함 파일)
3단계: 점진적 타입 추가
// tsconfig.json — 느슨하게 시작
{
"compilerOptions": {
"strict": false, // 점진적으로 true로 전환
"allowJs": true, // JS 파일 허용
"noImplicitAny": false // 나중에 true로
}
}
4단계: strict mode 순차 활성화
noImplicitAny: truestrictNullChecks: truestrict: true
CRA → Vite
변환 포인트
| CRA | Vite |
|---|---|
react-scripts |
vite + @vitejs/plugin-react |
public/index.html |
index.html (루트) |
REACT_APP_* 환경변수 |
VITE_* 환경변수 |
process.env.REACT_APP_* |
import.meta.env.VITE_* |
src/setupTests.ts |
vitest.config.ts + setup |
Jest → Vitest
변환 포인트
| Jest | Vitest |
|---|---|
jest.config.js |
vitest.config.ts |
jest.fn() |
vi.fn() |
jest.mock() |
vi.mock() |
jest.spyOn() |
vi.spyOn() |
@jest/globals |
vitest |
jest.useFakeTimers() |
vi.useFakeTimers() |
moduleNameMapper |
resolve.alias in vite config |
// vitest.config.ts
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import path from "path";
export default defineConfig({
plugins: [react()],
test: {
globals: true,
environment: "jsdom",
setupFiles: "./src/test/setup.ts",
css: true,
},
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
},
},
});
Redux → Zustand
변환 패턴
// Before: Redux Toolkit
const userSlice = createSlice({
name: "user",
initialState: { name: "", email: "" },
reducers: {
setUser: (state, action) => { Object.assign(state, action.payload); },
clearUser: () => ({ name: "", email: "" }),
},
});
// After: Zustand
interface UserState {
name: string;
email: string;
setUser: (user: { name: string; email: string }) => void;
clearUser: () => void;
}
const useUserStore = create<UserState>()((set) => ({
name: "",
email: "",
setUser: (user) => set(user),
clearUser: () => set({ name: "", email: "" }),
}));
실행 규칙
- 인자가 없으면 사용자에게 마이그레이션 종류를 질문한다
- 마이그레이션 전 현재 프로젝트 상태를 반드시 분석한다
- 대규모 변경은 단계별로 나눠서 진행하고, 각 단계 후 빌드/테스트를 확인한다
- 기존 코드를 삭제하기 전에 새 코드가 동작하는지 확인한다
package.json변경이 필요하면 명령어를 안내하고 사용자 승인 후 실행한다- 지원 목록에 없는 마이그레이션도 요청 시 분석 후 가이드를 제공한다
Weekly Installs
2
Repository
ingpdw/pdw-fe-dev-toolFirst Seen
Feb 7, 2026
Security Audits
Installed on
mcpjam2
openhands2
replit2
junie2
windsurf2
zencoder2