CRA vs Vite - React 빌드 도구의 세대 교체
TL;DR
- CRA는 zero-config 표준이었지만 느린 번들링과 유지보수 한계가 드러났다.
- Vite는 ESM과 esbuild/Rollup으로 즉시성 높은 개발 서버를 제공한다.
- Turbopack 등 대안과 마이그레이션 관점의 비교를 다룬다.
1. 개념
CRA와 Vite는 React 프로젝트의 개발·빌드 환경을 구성하는 도구 체계다.
2. 배경
JavaScript Fatigue와 설정 복잡도가 CRA 탄생의 배경이 됐다.
3. 이유
더 빠른 DX와 현대적 ESM 워크플로를 확보하기 위한 전환이 필요했다.
4. 특징
Vite의 빠른 HMR, 플러그인 생태계, CRA의 eject 구조와 한계를 비교한다.
5. 상세 내용
CRA vs Vite - React 빌드 도구의 세대 교체
작성일: 2026-02-27 카테고리: Frontend / Build Tools 포함 내용: CRA, Create React App, Vite, webpack, esbuild, Rollup, Rolldown, ESM, HMR, Dan Abramov, Evan You, react-scripts, eject, Turbopack, 번들러, 빌드 도구
1. CRA란 무엇인가?
1.1 CRA = Create React App
┌─────────────────────────────────────────────────────────────────┐
│ Create React App (CRA) │
│ │
│ 정식 명칭: Create React App │
│ 약칭: CRA │
│ 창시자: Dan Abramov (Facebook/Meta 소속) │
│ 첫 릴리스: 2016년 7월 22일 │
│ GitHub: facebook/create-react-app │
│ 라이선스: MIT │
│ │
│ 핵심 철학: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ "Zero Configuration" │ │
│ │ 설정 없이 React 프로젝트를 바로 시작할 수 있게 하자 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 한 줄 요약: │
│ npx create-react-app my-app → 즉시 React 개발 시작 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.2 Dan Abramov과 JavaScript Fatigue
┌─────────────────────────────────────────────────────────────────┐
│ 2015-2016년: "JavaScript Fatigue" 시대 │
│ │
│ 상황: │
│ React로 프로젝트를 시작하려면 직접 설정해야 할 것들: │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ 1. webpack 설치 및 webpack.config.js 작성 │ │
│ │ 2. Babel 설치 및 .babelrc 작성 (JSX 변환) │ │
│ │ 3. ESLint 설치 및 .eslintrc 작성 │ │
│ │ 4. Jest 설치 및 테스트 설정 │ │
│ │ 5. CSS Loader, Style Loader 설정 │ │
│ │ 6. Dev Server 설정 │ │
│ │ 7. Hot Reload 설정 │ │
│ │ 8. 환경 변수 설정 │ │
│ │ 9. Production 빌드 최적화 설정 │ │
│ │ 10. Source Map 설정 │ │
│ │ ... 이 모든 것을 직접 조합해야 함 │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 결과: │
│ ├── "Hello World"를 찍기도 전에 2-3시간 설정에 소비 │
│ ├── 설정 파일만 수십 개 │
│ ├── 초보자는 진입 장벽에 좌절 │
│ ├── "JavaScript 생태계가 너무 복잡하다" 불만 폭주 │
│ └── 이 현상을 "JavaScript Fatigue"라고 부르기 시작 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Dan Abramov의 프로필: │ │
│ │ ├── Redux 창시자 (상태 관리 라이브러리) │ │
│ │ ├── react-hot-loader 만든 사람 │ │
│ │ ├── Facebook/Meta의 React 코어 팀 소속 │ │
│ │ ├── "JavaScript Fatigue"를 직접 목격하고 해결책 제시 │ │
│ │ └── CRA를 만들어 "설정 없는 React 개발" 구현 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
1.3 CRA의 작동 원리
┌─────────────────────────────────────────────────────────────────┐
│ CRA의 내부 구조 │
│ │
│ CRA의 핵심 = react-scripts 패키지 │
│ │
│ react-scripts가 숨기는 도구들: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ react-scripts │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ webpack │ │ Babel │ │ ESLint │ │ Jest │ │ │
│ │ │ (번들러) │ │(트랜스파 │ │ (린터) │ │ (테스트) │ │ │
│ │ │ │ │ 일러) │ │ │ │ │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │PostCSS │ │ webpack │ │ dotenv │ │ │
│ │ │(CSS처리) │ │DevServer │ │ (환경변수)│ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 모든 설정이 react-scripts 내부에 하드코딩되어 있음 │
│ 개발자는 이 설정을 직접 볼 수 없고, 수정할 수도 없음 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ CRA 명령어 흐름 │
│ │
│ 개발 모드: │
│ 개발자 → npm start │
│ │ │
│ ▼ │
│ react-scripts start │
│ │ │
│ ▼ │
│ webpack dev server 시작 │
│ │ │
│ ├── Babel로 JSX/ES6+ 변환 │
│ ├── webpack이 모든 모듈 번들링 │
│ ├── HMR (Hot Module Replacement) 활성화 │
│ └── localhost:3000에서 서빙 │
│ │
│ 프로덕션 빌드: │
│ 개발자 → npm run build │
│ │ │
│ ▼ │
│ react-scripts build │
│ │ │
│ ├── 코드 압축 (Terser) │
│ ├── CSS 추출 및 최적화 │
│ ├── 청크 분리 │
│ ├── 에셋 해싱 │
│ └── build/ 폴더에 정적 파일 생성 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.4 npm run eject: 되돌릴 수 없는 탈출
┌─────────────────────────────────────────────────────────────────┐
│ eject 메커니즘 상세 │
│ │
│ 문제 상황: │
│ CRA가 숨긴 설정을 커스터마이즈하고 싶을 때 │
│ 예: webpack에 특정 loader 추가, Babel 플러그인 변경 등 │
│ │
│ 해결책: npm run eject │
│ │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ eject 전: │ │
│ │ my-app/ │ │
│ │ ├── node_modules/ │ │
│ │ ├── public/ │ │
│ │ ├── src/ │ │
│ │ ├── package.json (scripts: react-scripts) │ │
│ │ └── 설정 파일 없음 (깔끔) │ │
│ │ │ │
│ │ eject 후: │ │
│ │ my-app/ │ │
│ │ ├── config/ │ │
│ │ │ ├── webpack.config.js ← 600줄+ 설정 파일 │ │
│ │ │ ├── webpackDevServer.config.js │ │
│ │ │ ├── paths.js │ │
│ │ │ ├── env.js │ │
│ │ │ └── jest/ │ │
│ │ ├── scripts/ │ │
│ │ │ ├── start.js │ │
│ │ │ ├── build.js │ │
│ │ │ └── test.js │ │
│ │ ├── node_modules/ │ │
│ │ ├── public/ │ │
│ │ ├── src/ │ │
│ │ └── package.json (의존성 30개+ 노출) │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ 경고: eject는 되돌릴 수 없다 (One-way operation) │
│ │
│ ├── react-scripts 의존성 제거됨 │
│ ├── 모든 내부 설정이 프로젝트에 복사됨 │
│ ├── 이후 CRA 업데이트 혜택을 받을 수 없음 │
│ ├── 30개 이상의 직접 의존성을 스스로 관리해야 함 │
│ └── git commit이 생성되지만 되돌려도 원상복구 어려움 │
│ │
│ 대안: react-app-rewired, CRACO (eject 없이 설정 오버라이드) │
│ → 하지만 이것도 불안정하고 CRA 버전 업데이트 시 깨지기 쉬움 │
│ │
└─────────────────────────────────────────────────────────────────┘
1.5 CRA가 역사적으로 중요한 이유
┌─────────────────────────────────────────────────────────────────┐
│ CRA의 역사적 기여 (2016-2022) │
│ │
│ 1. React 프로젝트의 사실상 표준 (5-6년간) │
│ ├── 2016년부터 2022년까지 React 입문의 정석 │
│ ├── React 공식 문서에서 첫 번째로 추천 │
│ └── 수백만 개의 프로젝트가 CRA로 생성됨 │
│ │
│ 2. 프로젝트 구조 표준화 │
│ ├── src/ 디렉토리: 소스 코드 │
│ ├── public/index.html: HTML 엔트리포인트 │
│ ├── src/index.js: JavaScript 엔트리포인트 │
│ ├── src/App.js: 루트 컴포넌트 │
│ └── 이 구조가 React 커뮤니티의 암묵적 표준이 됨 │
│ │
│ 3. 환경 변수 규범 확립 │
│ ├── REACT_APP_ 접두사 규범화 │
│ ├── .env, .env.local, .env.development 등 파일 계층 │
│ └── 이 패턴이 다른 도구들에도 영향을 줌 │
│ │
│ 4. 교육 생태계 형성 │
│ ├── 거의 모든 React 튜토리얼이 CRA 기반 │
│ ├── Udemy, Coursera, YouTube 강의 대부분 CRA 사용 │
│ ├── 면접 과제에서도 CRA가 기본 │
│ └── React 학습 = CRA 사용이라는 등식 성립 │
│ │
│ 5. "설정보다 관례" 문화 전파 │
│ ├── Convention over Configuration 철학의 JS 생태계 도입 │
│ ├── Next.js, Gatsby 등 후속 도구들이 이 철학을 계승 │
│ └── "일단 시작하고, 필요하면 커스터마이즈" 패턴 확립 │
│ │
└─────────────────────────────────────────────────────────────────┘
2. Vite란 무엇인가?
2.1 이름의 의미와 탄생
┌─────────────────────────────────────────────────────────────────┐
│ Vite │
│ │
│ 이름: Vite (프랑스어로 "빠르다") │
│ 발음: /vit/ ("비트", "바이트"가 아님) │
│ 창시자: Evan You (Vue.js 창시자) │
│ 첫 공개: 2020년 4월 │
│ v2.0 릴리스: 2021년 2월 16일 (프레임워크 무관 버전) │
│ GitHub: vitejs/vite │
│ 라이선스: MIT │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Evan You의 프로필: │ │
│ │ ├── Vue.js 창시자 및 메인테이너 │ │
│ │ ├── 전 Google Creative Lab 소속 │ │
│ │ ├── 독립 오픈소스 개발자 (후원 기반) │ │
│ │ ├── 2024년 VoidZero Inc. 설립 │ │
│ │ │ └── Vite/Rolldown/Oxc 등 차세대 JS 도구체인 전담 │ │
│ │ └── JavaScript 생태계에서 가장 영향력 있는 개발자 중 하나 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 중요한 사실: │
│ Vite는 React에만 국한되지 않음! │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 지원 프레임워크: │ │
│ │ ├── React │ │
│ │ ├── Vue │ │
│ │ ├── Svelte │ │
│ │ ├── Preact │ │
│ │ ├── Lit │ │
│ │ ├── SolidJS │ │
│ │ ├── Qwik │ │
│ │ └── Vanilla JS/TS │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2.2 왜 Vite가 탄생했는가 - 기술적 동기
┌─────────────────────────────────────────────────────────────────┐
│ 전통적 번들러 (webpack/CRA)의 문제 │
│ │
│ 개발 서버 시작 과정: │
│ │
│ ┌────────┐ ┌──────────────────────┐ ┌─────────┐ │
│ │ 소스 │ │ webpack이 전부 │ │ 하나의 │ │
│ │ 코드 │───▶│ 분석하고 번들링 │───▶│ 큰 번들 │──▶ 브라우저
│ │ 전체 │ │ (수천 개 모듈) │ │ │ │
│ └────────┘ └──────────────────────┘ └─────────┘ │
│ ▲ │
│ │ │
│ 여기가 느림! │
│ (15-30초 이상) │
│ │
│ 문제의 본질: │
│ webpack은 서버를 시작하기 전에 앱의 모든 모듈을 │
│ 찾아서 분석하고 하나로 합쳐야 함 │
│ → 앱이 커질수록 시작 시간이 비례해서 증가 │
│ → 대규모 프로젝트에서는 1분 이상 걸리기도 함 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Vite의 해결 방식 │
│ │
│ 개발 서버 시작 과정: │
│ │
│ ┌────────────┐ ┌───────────────────┐ │
│ │ 소스 코드 │ │ 변환 없이 ESM │ │
│ │ (내 코드) │───▶│ 형태로 그대로 │───▶ 브라우저가 │
│ │ │ │ 서빙 │ 필요할 때 import │
│ └────────────┘ └───────────────────┘ │
│ ▲ │
│ 거의 즉시! │
│ (170ms - 1.2초) │
│ │
│ ┌────────────┐ ┌───────────────────┐ │
│ │ node_ │ │ esbuild로 │ │
│ │ modules │───▶│ 사전 번들링 │───▶ ESM 형태로 변환 │
│ │ (의존성) │ │ (Go 언어 기반) │ │
│ └────────────┘ └───────────────────┘ │
│ ▲ │
│ 10-100x 빠름! │
│ │
│ 핵심 아이디어: │
│ "소스 코드는 번들링하지 말자. │
│ 브라우저가 이제 ES Modules를 직접 이해할 수 있으니까." │
│ │
└─────────────────────────────────────────────────────────────────┘
2.3 핵심 기술 1: 브라우저 네이티브 ESM
┌─────────────────────────────────────────────────────────────────┐
│ ES Modules (ESM) 네이티브 지원 │
│ │
│ 역사적 배경: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 2015년: ES6 표준에 import/export 문법 정의 │ │
│ │ 2017년: Chrome 61에서 <script type="module"> 지원 │ │
│ │ 2018년: Firefox 60, Safari 11에서 지원 │ │
│ │ 2020년: 모든 주요 브라우저에서 ESM 완벽 지원 │ │
│ │ → Vite의 전제 조건이 충족됨! │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 전통적 방식 (webpack): │
│ ┌─────────────────────────────────────────┐ │
│ │ <script src="bundle.js"></script> │ │
│ │ → webpack이 모든 모듈을 하나로 합침 │ │
│ │ → 브라우저는 하나의 큰 파일만 받음 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ Vite 방식 (ESM): │
│ ┌─────────────────────────────────────────┐ │
│ │ <script type="module" src="/main.js"> │ │
│ │ → 브라우저가 main.js를 로드 │ │
│ │ → import를 만나면 해당 모듈을 요청 │ │
│ │ → 브라우저가 직접 의존성 그래프 해석 │ │
│ │ → 필요한 모듈만 on-demand로 로드 │ │
│ └─────────────────────────────────────────┘ │
│ │
│ 동작 원리: │
│ // App.jsx │
│ import React from 'react' ← 사전 번들링된 의존성 │
│ import { Header } from './Header' ← ESM으로 직접 서빙 │
│ import './App.css' ← Vite가 변환하여 서빙 │
│ │
│ Vite 개발 서버가 하는 일: │
│ 1. 요청이 오면 해당 파일을 변환 (JSX → JS 등) │
│ 2. import 경로를 브라우저가 이해할 수 있는 URL로 변환 │
│ 3. 변환된 결과를 즉시 응답 │
│ → 전체 앱을 번들링하지 않으므로 즉시 시작 가능 │
│ │
└─────────────────────────────────────────────────────────────────┘
2.4 핵심 기술 2: esbuild 사전 번들링
┌─────────────────────────────────────────────────────────────────┐
│ esbuild 사전 번들링 (Pre-bundling) │
│ │
│ 문제: 왜 node_modules는 ESM으로 그대로 서빙할 수 없는가? │
│ │
│ 이유 1: CommonJS 형식 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 대부분의 npm 패키지는 CommonJS로 작성됨 │ │
│ │ const lodash = require('lodash') ← CommonJS │ │
│ │ import lodash from 'lodash' ← ESM │ │
│ │ → 브라우저는 require()를 이해하지 못함 │ │
│ │ → ESM 형태로 변환이 필요 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 이유 2: HTTP 요청 폭주 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 예: lodash-es 패키지 │ │
│ │ └── 내부에 600개 이상의 개별 모듈 파일 │ │
│ │ │ │
│ │ ESM으로 그대로 서빙하면: │ │
│ │ import { debounce } from 'lodash-es' │ │
│ │ → 브라우저가 600개 HTTP 요청을 보냄 │ │
│ │ → 네트워크 병목으로 매우 느림 │ │
│ │ │ │
│ │ esbuild로 사전 번들링하면: │ │
│ │ 600개 모듈 → 1개 ESM 번들로 합침 │ │
│ │ → 단 1번의 HTTP 요청으로 해결 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ esbuild가 빠른 이유: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ esbuild: Go 언어로 작성된 번들러 │ │
│ │ │ │
│ │ webpack/Rollup: JavaScript로 작성 │ │
│ │ └── 싱글 스레드, 인터프리터 언어 │ │
│ │ │ │
│ │ esbuild: Go로 작성 │ │
│ │ ├── 네이티브 코드로 컴파일 │ │
│ │ ├── 멀티스레드 병렬 처리 │ │
│ │ ├── 메모리 효율적 설계 │ │
│ │ └── 결과: 10-100배 빠름 │ │
│ │ │ │
│ │ 실제 비교: │ │
│ │ Rollup으로 30초 걸리는 작업 → esbuild로 1.5초 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
2.5 HMR (Hot Module Replacement) 속도 차이
┌─────────────────────────────────────────────────────────────────┐
│ HMR 속도 비교: CRA vs Vite │
│ │
│ HMR이란? │
│ = 코드를 수정하면 페이지를 새로고침하지 않고 │
│ 변경된 부분만 즉시 반영하는 기능 │
│ = 개발 중 가장 자주 발생하는 동작 │
│ │
│ ────────────────────────────────────────────────────────────── │
│ │
│ CRA (webpack) HMR 과정: │
│ │
│ 파일 변경 │
│ │ │
│ ▼ │
│ webpack이 의존성 그래프 재평가 │
│ │ │
│ ▼ │
│ 영향받는 모듈들의 번들 재생성 │
│ │ │
│ ▼ │
│ 브라우저로 업데이트 전송 │
│ │ │
│ ▼ │
│ 화면 업데이트 │
│ │
│ 소요 시간: 500ms - 1.6초 │
│ 문제: 앱이 커질수록 점점 느려짐 (의존성 그래프가 커지니까) │
│ │
│ ────────────────────────────────────────────────────────────── │
│ │
│ Vite HMR 과정: │
│ │
│ 파일 변경 │
│ │ │
│ ▼ │
│ 해당 모듈만 무효화 (invalidate) │
│ │ │
│ ▼ │
│ 브라우저가 해당 모듈 하나만 다시 fetch │
│ │ │
│ ▼ │
│ 화면 업데이트 │
│ │
│ 소요 시간: 10 - 20ms │
│ 장점: 앱 크기에 관계없이 일정하게 빠름! │
│ │
│ ────────────────────────────────────────────────────────────── │
│ │
│ 왜 Vite HMR이 앱 크기에 영향받지 않는가? │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ webpack: 변경 시 관련 모듈 체인을 다시 번들링 │ │
│ │ → 앱이 크면 체인이 길어짐 → 느려짐 │ │
│ │ │ │
│ │ Vite: 변경된 파일 하나만 다시 변환 │ │
│ │ → 브라우저에게 "이 파일만 다시 가져가" │ │
│ │ → 다른 모듈은 건드리지 않음 │ │
│ │ → 앱이 1,000개 모듈이든 10,000개든 무관 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
3. CRA vs Vite 기술 비교
3.1 아키텍처 비교
┌─────────────────────────────────────────────────────────────────┐
│ 아키텍처 비교표 │
│ │
│ ┌──────────────┬──────────────────┬──────────────────────┐ │
│ │ 항목 │ CRA │ Vite │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ Dev 번들러 │ webpack │ 없음 (ESM 직접 서빙) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ Dev 전략 │ 전체 앱 번들링 │ On-demand 변환 │ │
│ │ │ 후 서빙 │ (요청 시 변환) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 의존성 처리 │ webpack이 함께 │ esbuild 사전 번들링 │ │
│ │ │ 번들링 │ (별도 단계) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ Prod 번들러 │ webpack │ Rollup │ │
│ │ │ │ (Vite 7: Rolldown) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 트랜스파일러 │ Babel │ esbuild (개발) │ │
│ │ │ │ SWC (프로덕션, 옵션) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 설정 방식 │ 숨김 (Zero- │ vite.config.js │ │
│ │ │ config / eject) │ (투명하고 간단) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 플러그인 │ webpack 플러그인 │ Rollup 호환 + │ │
│ │ 시스템 │ (복잡) │ Vite 전용 (간단) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 프레임워크 │ React 전용 │ 프레임워크 무관 │ │
│ │ 결합도 │ │ (React, Vue, Svelte │ │
│ │ │ │ 등 모두 지원) │ │
│ └──────────────┴──────────────────┴──────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
3.2 성능 비교 (실측 데이터 기반)
┌─────────────────────────────────────────────────────────────────┐
│ 성능 비교 (실측 데이터) │
│ │
│ ┌──────────────┬──────────────────┬────────────┬──────────┐ │
│ │ 측정 항목 │ CRA (webpack) │ Vite │ 개선율 │ │
│ ├──────────────┼──────────────────┼────────────┼──────────┤ │
│ │ Cold Start │ 15 - 30초 이상 │ 170ms - │ 10-20x │ │
│ │ (첫 시작) │ │ 1.2초 │ │ │
│ ├──────────────┼──────────────────┼────────────┼──────────┤ │
│ │ HMR │ 500ms - 1.6초 │ 10 - 20ms │ 50-80x │ │
│ │ (파일 변경) │ │ │ │ │
│ ├──────────────┼──────────────────┼────────────┼──────────┤ │
│ │ Production │ ~20초 │ ~6초 │ ~3x │ │
│ │ Build │ │ │ │ │
│ ├──────────────┼──────────────────┼────────────┼──────────┤ │
│ │ node_modules │ ~205MB │ ~34MB │ 6x 작음 │ │
│ │ 크기 │ │ │ │ │
│ ├──────────────┼──────────────────┼────────────┼──────────┤ │
│ │ 번들 크기 │ 기준 │ ~27.5% │ │ │
│ │ (prod) │ │ 더 작음 │ │ │
│ └──────────────┴──────────────────┴────────────┴──────────┘ │
│ │
│ 실제 마이그레이션 사례 (중규모 프로젝트): │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Cold Start: 15.469초 → 1.202초 (12.9배 개선) │ │
│ │ Build: 1분 34초 → 29.2초 (3.2배 개선) │ │
│ │ HMR: 1.2초 → 15ms (80배 개선) │ │
│ │ Install: 45초 → 12초 (3.75배 개선) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 개발자 체감 차이: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CRA: 코드 수정 → 커피 한 모금 → 화면 업데이트 │ │
│ │ Vite: 코드 수정 → 즉시 화면 업데이트 (타이핑 따라감) │ │
│ │ │ │
│ │ CRA: npm start → "오늘 날씨 어떨까..." → 서버 준비 │ │
│ │ Vite: npm run dev → 이미 브라우저에 떠있음 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
3.3 TypeScript 지원 비교
┌─────────────────────────────────────────────────────────────────┐
│ TypeScript 지원 비교 │
│ │
│ CRA의 TypeScript 처리: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 프로젝트 생성: │ │
│ │ npx create-react-app my-app --template typescript │ │
│ │ │ │
│ │ 처리 방식: │ │
│ │ .tsx 파일 → Babel (@babel/preset-typescript) │ │
│ │ → 타입 구문만 제거 (strip types) │ │
│ │ → JavaScript 출력 │ │
│ │ │ │
│ │ 주의점: │ │
│ │ ├── Babel은 타입 체크를 하지 않음! │ │
│ │ ├── 타입 에러가 있어도 빌드가 성공함 │ │
│ │ ├── 타입 체크는 별도로 tsc --noEmit 실행 필요 │ │
│ │ └── fork-ts-checker-webpack-plugin으로 부분 보완 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Vite의 TypeScript 처리: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 프로젝트 생성: │ │
│ │ npm create vite@latest my-app -- --template react-ts │ │
│ │ │ │
│ │ 처리 방식: │ │
│ │ .tsx 파일 → esbuild (Go 네이티브) │ │
│ │ → 타입 구문 제거 (tsc보다 20-30배 빠름) │ │
│ │ → JavaScript 출력 │ │
│ │ │ │
│ │ 네이티브 .ts/.tsx 지원: │ │
│ │ ├── 별도 설정 없이 TypeScript 파일 바로 사용 가능 │ │
│ │ ├── tsconfig.json의 일부 옵션 자동 인식 │ │
│ │ ├── 타입 체크는 역시 IDE 또는 tsc에 위임 │ │
│ │ └── vite-plugin-checker로 개발 중 타입 체크 가능 │ │
│ │ │ │
│ │ 속도: │ │
│ │ esbuild의 TS 변환: tsc보다 20-30배 빠름 │ │
│ │ (Go 네이티브 컴파일 + 타입 체크 생략 덕분) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
3.4 CSS / PostCSS / Tailwind 지원 비교
┌─────────────────────────────────────────────────────────────────┐
│ CSS / PostCSS / Tailwind 지원 비교 │
│ │
│ ┌──────────────┬──────────────────────┬─────────────────────┐ │
│ │ 기능 │ CRA │ Vite │ │
│ ├──────────────┼──────────────────────┼─────────────────────┤ │
│ │ CSS 임포트 │ css-loader + │ 네이티브 지원 │ │
│ │ │ style-loader │ (설정 불필요) │ │
│ ├──────────────┼──────────────────────┼─────────────────────┤ │
│ │ CSS Modules │ .module.css 규칙 │ .module.css 규칙 │ │
│ │ │ (내장) │ (내장) │ │
│ ├──────────────┼──────────────────────┼─────────────────────┤ │
│ │ Sass/SCSS │ node-sass 또는 │ sass 설치만 하면 │ │
│ │ │ sass 설치 필요 │ 자동 인식 │ │
│ ├──────────────┼──────────────────────┼─────────────────────┤ │
│ │ PostCSS │ 내장 (autoprefixer │ postcss.config.js │ │
│ │ │ 포함) │ 감지 시 자동 적용 │ │
│ ├──────────────┼──────────────────────┼─────────────────────┤ │
│ │ Tailwind CSS │ craco 또는 eject │ postcss.config.js │ │
│ │ │ 필요 (번거로움) │ 에 추가만 하면 끝 │ │
│ ├──────────────┼──────────────────────┼─────────────────────┤ │
│ │ CSS-in-JS │ 기본 지원 │ 플러그인으로 지원 │ │
│ └──────────────┴──────────────────────┴─────────────────────┘ │
│ │
│ Tailwind CSS 설정 비교: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CRA + Tailwind: │ │
│ │ 1. craco 설치 (CRA 설정 오버라이드 도구) │ │
│ │ 2. craco.config.js 작성 │ │
│ │ 3. package.json scripts 수정 (react-scripts → craco) │ │
│ │ 4. tailwind.config.js 작성 │ │
│ │ 5. postcss.config.js 작성 │ │
│ │ → 5단계, CRA 버전 업데이트 시 craco 호환성 문제 │ │
│ │ │ │
│ │ Vite + Tailwind: │ │
│ │ 1. tailwindcss, postcss, autoprefixer 설치 │ │
│ │ 2. tailwind.config.js 생성 (npx tailwindcss init -p) │ │
│ │ → 2단계, 안정적 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
4. 각각의 장단점
4.1 CRA 장점
┌─────────────────────────────────────────────────────────────────┐
│ CRA 장점 │
│ │
│ 1. 완전한 Zero Configuration │
│ ├── npx create-react-app my-app 한 줄로 시작 │
│ ├── webpack, Babel, ESLint, Jest 모두 사전 설정 │
│ └── 초보자가 빌드 도구를 전혀 몰라도 사용 가능 │
│ │
│ 2. 검증된 안정성 (레거시) │
│ ├── 5년 이상 수백만 프로젝트에서 사용됨 │
│ ├── 대부분의 에지 케이스가 이미 해결됨 │
│ └── Stack Overflow 답변이 풍부 │
│ │
│ 3. 풍부한 학습 자료 │
│ ├── 모든 React 튜토리얼/강의가 CRA 기반 │
│ ├── 책, 블로그, 영상 자료 압도적 │
│ └── React 학습 시 추가 학습 부담 없음 │
│ │
│ 4. 통합 테스트 환경 │
│ ├── Jest가 내장되어 있음 │
│ ├── React Testing Library 기본 포함 │
│ └── npm test로 즉시 테스트 실행 │
│ │
│ 5. 일관된 팀 환경 │
│ ├── 모든 개발자가 동일한 설정 사용 │
│ ├── "내 컴퓨터에서는 되는데..." 문제 감소 │
│ └── 설정 관련 논쟁 없음 │
│ │
└─────────────────────────────────────────────────────────────────┘
4.2 CRA 단점
┌─────────────────────────────────────────────────────────────────┐
│ CRA 단점 │
│ │
│ 1. 심각한 성능 문제 │
│ ├── Cold Start: 15-30초 이상 (대규모 프로젝트) │
│ ├── HMR: 500ms-1.6초 (앱 커질수록 악화) │
│ ├── 빌드: 수 분 소요 가능 │
│ └── 개발 생산성에 직접적 영향 │
│ │
│ 2. 거대한 의존성 트리 │
│ ├── node_modules 약 205MB │
│ ├── 설치 시간 오래 걸림 │
│ ├── 보안 취약점 노출 면적 넓음 │
│ └── CI/CD 파이프라인 느려짐 │
│ │
│ 3. 커스터마이즈 불가능 (eject 없이) │
│ ├── webpack 설정 변경 불가 │
│ ├── Babel 플러그인 추가 어려움 │
│ ├── 해결책: eject (되돌릴 수 없음) 또는 craco (불안정) │
│ └── 프로젝트 성장 시 설정 한계에 부딪힘 │
│ │
│ 4. 프로덕션 필수 기능 부재 │
│ ├── 라우팅 미포함 (react-router 별도 설치) │
│ ├── 데이터 페칭 지원 없음 │
│ ├── 코드 스플리팅 수동 설정 │
│ ├── SSR/SSG 미지원 │
│ └── 상태 관리 미포함 │
│ │
│ 5. 유지보수 중단 │
│ ├── 2023년부터 사실상 방치 │
│ ├── React 19 호환성 문제 │
│ ├── 보안 패치 지연 │
│ ├── 2025년 2월 공식 Deprecated │
│ └── 새 프로젝트에 사용하면 기술 부채 시작 │
│ │
└─────────────────────────────────────────────────────────────────┘
4.3 Vite 장점
┌─────────────────────────────────────────────────────────────────┐
│ Vite 장점 │
│ │
│ 1. 압도적인 개발 서버 속도 │
│ ├── Cold Start: 170ms - 1.2초 (CRA 대비 10-20배) │
│ ├── HMR: 10-20ms (CRA 대비 50-80배) │
│ ├── 앱 크기에 관계없이 일정한 속도 │
│ └── 코드 저장 → 즉시 반영 (실시간 느낌) │
│ │
│ 2. 가벼운 의존성 │
│ ├── node_modules 약 34MB (CRA의 1/6) │
│ ├── 빠른 설치 │
│ ├── 적은 보안 취약점 노출 │
│ └── CI/CD 파이프라인 효율적 │
│ │
│ 3. 투명하고 간단한 설정 │
│ ├── vite.config.js 한 파일로 모든 설정 │
│ ├── Rollup 플러그인 호환 (방대한 에코시스템) │
│ ├── eject 같은 파괴적 선택 불필요 │
│ └── 필요한 만큼만 설정, 나머지는 합리적 기본값 │
│ │
│ 4. 프레임워크 무관 (Framework Agnostic) │
│ ├── React, Vue, Svelte, SolidJS 등 지원 │
│ ├── 팀이 여러 프레임워크 사용 시 빌드 도구 통일 가능 │
│ └── 한 번 배우면 어디서든 사용 │
│ │
│ 5. 활발한 개발과 커뮤니티 │
│ ├── Evan You + VoidZero 팀 적극 개발 │
│ ├── 주간 npm 다운로드 31M+ (Vite 7 기준) │
│ ├── State of JS 2024: #1 Build Tool │
│ ├── 98% Retention Rate, 95% 만족도 │
│ └── React, Vue, Svelte 공식 문서에서 추천 │
│ │
│ 6. 최신 웹 표준 기반 │
│ ├── ES Modules 네이티브 활용 │
│ ├── 최신 브라우저 기능 적극 활용 │
│ └── 미래 지향적 아키텍처 │
│ │
└─────────────────────────────────────────────────────────────────┘
4.4 Vite 단점
┌─────────────────────────────────────────────────────────────────┐
│ Vite 단점 │
│ │
│ 1. Dev/Prod 번들러 불일치 (Vite 6 이하) │
│ ├── 개발: esbuild (변환) + ESM 직접 서빙 │
│ ├── 프로덕션: Rollup (번들링) │
│ ├── 드물지만 개발에서 되고 프로덕션에서 안 되는 경우 발생 │
│ └── Vite 7의 Rolldown이 이 문제를 해결 예정 │
│ │
│ 2. CRA 대비 적은 레거시 자료 │
│ ├── 오래된 튜토리얼은 CRA 기반이 많음 │
│ ├── 2023년 이후 자료는 Vite가 대부분 │
│ └── 빠르게 개선 중이며 이제 대부분의 새 자료는 Vite 기반 │
│ │
│ 3. 초대형 프로젝트에서 ESM 요청 과다 (극단적 경우) │
│ ├── 수천 개 모듈 시 초기 로드 시 HTTP 요청이 많아질 수 있음 │
│ ├── 사전 번들링으로 대부분 해결 │
│ └── HTTP/2 환경에서는 큰 문제 아님 │
│ │
│ 4. 테스트 러너 별도 설정 필요 │
│ ├── Jest 대신 Vitest 사용 권장 │
│ ├── Vitest는 Vite 생태계와 완벽 통합 │
│ ├── 하지만 Jest에서 마이그레이션 필요 │
│ └── Vitest가 Jest보다 빠르고 Vite 설정 재사용 가능 │
│ │
│ 5. IE11 미지원 │
│ ├── ES Modules를 지원하지 않는 브라우저 불가 │
│ ├── 2022년 IE11 EOL 이후 사실상 문제 아님 │
│ └── @vitejs/plugin-legacy로 부분 지원 가능 │
│ │
└─────────────────────────────────────────────────────────────────┘
4.5 장단점 요약 비교
┌─────────────────────────────────────────────────────────────────┐
│ 장단점 요약 비교 │
│ │
│ ┌────────────────────────────┬────────────────────────────┐ │
│ │ CRA │ Vite │ │
│ ├────────────────────────────┼────────────────────────────┤ │
│ │ [+] Zero Config 완벽 │ [+] 압도적 속도 │ │
│ │ [+] 풍부한 레거시 자료 │ [+] 가벼운 의존성 │ │
│ │ [+] Jest 내장 │ [+] 투명한 설정 │ │
│ │ [+] 검증된 안정성 │ [+] 프레임워크 무관 │ │
│ │ │ [+] 활발한 커뮤니티 │ │
│ │ [-] 느린 Cold Start │ [+] 최신 웹 표준 기반 │ │
│ │ [-] 느린 HMR │ │ │
│ │ [-] 거대한 node_modules │ [-] Dev/Prod 불일치 가능 │ │
│ │ [-] 커스터마이즈 어려움 │ [-] 레거시 자료 적음 │ │
│ │ [-] 유지보수 중단됨 │ [-] 테스트 별도 설정 │ │
│ │ [-] React 19 비호환 │ [-] IE11 미지원 │ │
│ ├────────────────────────────┼────────────────────────────┤ │
│ │ 결론: 새 프로젝트 비추천 │ 결론: 새 프로젝트 강력추천 │ │
│ │ (Deprecated, 2025.02) │ (React 공식 권장) │ │
│ └────────────────────────────┴────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
5. CRA의 쇠퇴와 공식 Deprecation
5.1 타임라인
┌─────────────────────────────────────────────────────────────────┐
│ CRA의 역사 타임라인 (2016-2025) │
│ │
│ 2016.07.22 ─── CRA v1.0 출시 │
│ │ Dan Abramov, Facebook │
│ │ "JavaScript Fatigue" 해결 │
│ │ │
│ 2016-2022 ──── React 프로젝트의 사실상 표준 │
│ │ 모든 튜토리얼, 강의에서 사용 │
│ │ 수백만 프로젝트 생성 │
│ │ │
│ 2020.04 ────── Vite 첫 공개 (Evan You) │
│ │ 아직 Vue 전용에 가까움 │
│ │ │
│ 2021.02 ────── Vite v2.0 릴리스 │
│ │ 프레임워크 무관(agnostic)으로 전환 │
│ │ React 지원 시작 → CRA 대안으로 급부상 │
│ │ │
│ 2021-2022 ──── Vite 급성장 │
│ │ 커뮤니티가 "CRA 대신 Vite 쓰세요" 추천 시작 │
│ │ SvelteKit, Nuxt 3 등이 Vite 채택 │
│ │ │
│ 2023.03.16 ─── React 팀 새 공식 문서(react.dev) 발표 │
│ │ CRA 추천 중단! │
│ │ "프레임워크 사용을 권장합니다" │
│ │ │
│ 2023-2024 ──── CRA GitHub 사실상 방치 │
│ │ 이슈 미응답, PR 미리뷰 │
│ │ 활발한 메인테이너 없음 │
│ │ 보안 취약점 누적 │
│ │ │
│ 2025.02.14 ─── React 팀 공식 블로그 포스트 │
│ "Sunsetting Create React App" │
│ CRA 공식 Deprecated 선언 │
│ Vite를 SPA 대안으로 명시적 추천 │
│ │
└─────────────────────────────────────────────────────────────────┘
5.2 Sunsetting 이유 5가지
┌─────────────────────────────────────────────────────────────────┐
│ CRA Deprecated의 5가지 이유 (React 팀 공식) │
│ │
│ 1. 활발한 메인테이너 없음 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Dan Abramov: React 코어 팀 작업으로 이동 │ │
│ │ (이후 2024년 Bluesky로 이직) │ │
│ │ 마지막 의미 있는 릴리스: 2022년 │ │
│ │ GitHub Issues: 1,700+ 미해결 │ │
│ │ PR: 수백 개 방치 │ │
│ │ → 사실상 유지보수 불가능 상태 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 2. 프로덕션 필수 기능 부재 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CRA가 제공하지 않는 것들: │ │
│ │ ├── 라우팅 (클라이언트 사이드/서버 사이드) │ │
│ │ ├── 데이터 페칭 및 캐싱 │ │
│ │ ├── 효율적 코드 스플리팅 │ │
│ │ ├── SSR (Server-Side Rendering) │ │
│ │ ├── SSG (Static Site Generation) │ │
│ │ └── 이미지/폰트 최적화 │ │
│ │ │ │
│ │ → 모든 것을 개발자가 직접 조합해야 함 │ │
│ │ → 2025년 기준으로는 너무 원시적 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 3. 거대한 의존성 트리 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CRA: ~205MB node_modules │ │
│ │ Vite: ~34MB node_modules │ │
│ │ │ │
│ │ → 6배 차이 │ │
│ │ → 설치 시간, CI/CD 시간, 보안 취약점 면적 모두 증가 │ │
│ │ → react-scripts가 내부에 숨긴 의존성이 너무 많음 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 4. React 19 호환성 문제 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ React 19에서 도입된 변경사항들을 CRA가 지원하지 못함 │ │
│ │ ├── 유지보수 인력 부재로 업데이트 불가 │ │
│ │ ├── 내부 webpack/Babel 설정이 구버전에 고정 │ │
│ │ └── 새 React 기능을 사용할 수 없는 상황 발생 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 5. 프레임워크가 더 잘 해결 │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ React 팀의 현재 입장: │ │
│ │ "CRA가 해결하려던 문제들을 이제 프레임워크들이 │ │
│ │ 더 잘 해결합니다." │ │
│ │ │ │
│ │ Next.js: 라우팅 + SSR + SSG + API + 최적화 │ │
│ │ Remix: 라우팅 + 데이터 로딩 + 폼 처리 │ │
│ │ Vite: 빠른 빌드 + 유연한 설정 + SPA 최적 │ │
│ │ │ │
│ │ → 빌드 도구만으로는 부족, 통합 솔루션이 필요한 시대 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
5.3 React 팀의 현재 권장사항 (2025)
┌─────────────────────────────────────────────────────────────────┐
│ React 팀 공식 권장사항 (2025년 기준) │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Full-stack 웹 애플리케이션: │ │
│ │ ├── Next.js (Vercel) ← 가장 많이 추천 │ │
│ │ │ ├── SSR, SSG, ISR 지원 │ │
│ │ │ ├── App Router (React Server Components) │ │
│ │ │ ├── API Routes │ │
│ │ │ └── 이미지/폰트 최적화 내장 │ │
│ │ │ │ │
│ │ └── Remix (Shopify) ← React Router 기반 │ │
│ │ ├── 중첩 라우팅 + 데이터 로딩 │ │
│ │ ├── 점진적 향상 (Progressive Enhancement) │ │
│ │ └── 폼 처리 최적화 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Client-side SPA (Single Page Application): │ │
│ │ └── Vite ← CRA의 직접적 대체 │ │
│ │ ├── 서버 렌더링이 필요 없는 경우 │ │
│ │ ├── 사내 도구, 대시보드, 관리자 페이지 │ │
│ │ └── 기존 CRA 프로젝트 마이그레이션 대상 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ 정적 사이트 / 콘텐츠 중심 사이트: │ │
│ │ ├── Astro ← 콘텐츠 중심, 멀티 프레임워크 │ │
│ │ └── Gatsby ← GraphQL 기반 정적 사이트 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
6. 언제 무엇을 사용해야 하는가?
6.1 CRA가 적합한 경우 (2025 관점)
┌─────────────────────────────────────────────────────────────────┐
│ CRA를 계속 사용해도 되는 경우 (극히 제한적) │
│ │
│ 1. 레거시 프로젝트 유지보수 │
│ ├── 이미 CRA로 운영 중인 프로젝트 │
│ ├── 마이그레이션 ROI가 부족한 경우 │
│ │ (예: 6개월 내 종료 예정인 프로젝트) │
│ └── 팀 리소스가 마이그레이션에 할당 불가한 경우 │
│ │
│ 2. 교육/학습 목적 (webpack + Babel 이해) │
│ ├── "번들러가 뭔지, 왜 필요한지" 이해하려는 학습자 │
│ ├── eject 후 내부 구조를 들여다보며 학습 │
│ └── 하지만 Vite로 시작하는 것이 2025년 기준 표준 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 중요: 새 프로젝트에는 절대 CRA를 사용하지 마세요 │ │
│ │ │ │
│ │ 이유: │ │
│ │ ├── React 팀이 공식적으로 Deprecated 선언 │ │
│ │ ├── 보안 패치 없음 │ │
│ │ ├── React 19 호환 문제 │ │
│ │ ├── 성능이 현대 도구 대비 10-80배 느림 │ │
│ │ └── 시작부터 기술 부채를 안고 가는 것 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
6.2 Vite가 적합한 경우
┌─────────────────────────────────────────────────────────────────┐
│ Vite를 선택해야 하는 경우 │
│ │
│ 1. 모든 새 React SPA 프로젝트 │
│ └── React 팀 공식 권장. 이유가 필요 없음 │
│ │
│ 2. CRA에서 마이그레이션 │
│ ├── CRA → Vite 마이그레이션은 비교적 간단 (몇 시간) │
│ ├── 즉각적인 성능 향상 체감 │
│ └── 기술 부채 해소 │
│ │
│ 3. 성능이 중요한 대규모 팀 │
│ ├── 개발자 수십 명이 동시 작업하는 프로젝트 │
│ ├── HMR 속도가 생산성에 직결 │
│ ├── CI/CD 빌드 시간 단축 = 비용 절감 │
│ └── Cold Start 속도가 개발자 경험에 큰 영향 │
│ │
│ 4. 멀티 프레임워크 팀 │
│ ├── React + Vue 동시 사용 팀 │
│ ├── 마이크로 프론트엔드 아키텍처 │
│ └── 하나의 빌드 도구로 통일 가능 │
│ │
│ 5. 커스텀 빌드 설정이 필요한 경우 │
│ ├── 특수 loader/plugin 필요 │
│ ├── vite.config.js에서 직관적으로 설정 가능 │
│ └── eject 같은 파괴적 선택 불필요 │
│ │
│ 6. 라이브러리/패키지 개발 │
│ ├── Vite의 Library Mode 활용 │
│ └── 라이브러리 빌드 설정이 간단 │
│ │
└─────────────────────────────────────────────────────────────────┘
6.3 풀스택 프레임워크를 선택해야 하는 경우
┌─────────────────────────────────────────────────────────────────┐
│ 풀스택 프레임워크 선택 가이드 │
│ │
│ ┌──────────────┬──────────────────────────────────────────┐ │
│ │ 프레임워크 │ 적합한 경우 │ │
│ ├──────────────┼──────────────────────────────────────────┤ │
│ │ │ ├── SEO가 중요한 공개 웹사이트 │ │
│ │ Next.js │ ├── SSR/SSG가 필요한 경우 │ │
│ │ (Vercel) │ ├── React Server Components 활용 │ │
│ │ │ ├── API 라우트가 필요한 풀스택 앱 │ │
│ │ │ └── Vercel 배포 시 최적 경험 │ │
│ ├──────────────┼──────────────────────────────────────────┤ │
│ │ │ ├── 웹 표준 중심 개발 선호 │ │
│ │ Remix │ ├── 점진적 향상(Progressive Enhancement) │ │
│ │ (Shopify) │ ├── 중첩 라우팅이 복잡한 앱 │ │
│ │ │ └── 폼 처리가 많은 애플리케이션 │ │
│ ├──────────────┼──────────────────────────────────────────┤ │
│ │ │ ├── 콘텐츠/마케팅 중심 사이트 │ │
│ │ Astro │ ├── 여러 프레임워크를 섞어 쓰고 싶을 때 │ │
│ │ │ ├── 최소한의 JavaScript가 목표일 때 │ │
│ │ │ └── 블로그, 문서 사이트, 포트폴리오 │ │
│ ├──────────────┼──────────────────────────────────────────┤ │
│ │ │ ├── GraphQL 데이터 레이어 활용 │ │
│ │ Gatsby │ ├── CMS 연동이 많은 사이트 │ │
│ │ │ └── 정적 사이트 (다만 Astro가 더 현대적) │ │
│ └──────────────┴──────────────────────────────────────────┘ │
│ │
│ 판단 기준: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ "서버 렌더링/SEO 필요?" ──── Yes → Next.js / Remix │ │
│ │ └── No │ │
│ │ │ │ │
│ │ "순수 SPA / 사내 도구?" ────── Yes → Vite │ │
│ │ └── No │ │
│ │ │ │ │
│ │ "콘텐츠 중심 정적 사이트?" ── Yes → Astro │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
7. CRA에서 Vite로 마이그레이션
7.1 마이그레이션 개요
┌─────────────────────────────────────────────────────────────────┐
│ CRA → Vite 마이그레이션 개요 │
│ │
│ 난이도: 중간 (경험자 2-4시간, 초보자 반나절) │
│ 위험도: 낮음 (대부분의 코드 변경 없이 가능) │
│ │
│ 마이그레이션 단계 요약: │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Step 1: react-scripts 제거 │ │
│ │ Step 2: vite + @vitejs/plugin-react 설치 │ │
│ │ Step 3: index.html 위치 이동 (public/ → 루트) │ │
│ │ Step 4: .js → .jsx 확장자 변경 │ │
│ │ Step 5: vite.config.js 생성 │ │
│ │ Step 6: package.json scripts 수정 │ │
│ │ Step 7: 환경변수 접두사 변경 │ │
│ │ Step 8: Jest → Vitest 마이그레이션 (선택) │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
7.2 마이그레이션 상세 단계
┌─────────────────────────────────────────────────────────────────┐
│ Step 1: react-scripts 및 관련 의존성 제거 │
│ │
│ npm uninstall react-scripts │
│ │
│ react-scripts가 가져오는 ~205MB의 의존성이 함께 제거됨 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 2: Vite 및 플러그인 설치 │
│ │
│ npm install --save-dev vite @vitejs/plugin-react │
│ │
│ 설치 후 node_modules: ~34MB (기존 대비 6배 감소) │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 3: index.html 위치 이동 │
│ │
│ CRA 구조: Vite 구조: │
│ my-app/ my-app/ │
│ ├── public/ ├── index.html ← 루트로 이동 │
│ │ └── index.html ├── public/ │
│ ├── src/ │ └── (정적 에셋만) │
│ └── ... ├── src/ │
│ └── ... │
│ │
│ index.html 수정사항: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 변경 전 (CRA): │ │
│ │ <div id="root"></div> │ │
│ │ <!-- react-scripts가 자동으로 bundle.js 주입 --> │ │
│ │ │ │
│ │ 변경 후 (Vite): │ │
│ │ <div id="root"></div> │ │
│ │ <script type="module" src="/src/main.jsx"></script> │ │
│ │ <!-- ESM 엔트리포인트를 직접 명시 --> │ │
│ │ │ │
│ │ 또한 %PUBLIC_URL% 접두사 모두 제거: │ │
│ │ 변경 전: <link rel="icon" href="%PUBLIC_URL%/favicon.ico"> │ │
│ │ 변경 후: <link rel="icon" href="/favicon.ico"> │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 4: .js → .jsx 확장자 변경 │
│ │
│ CRA: JSX를 포함한 파일이라도 .js 확장자 허용 │
│ Vite: JSX를 포함한 파일은 반드시 .jsx 또는 .tsx 확장자 필요 │
│ │
│ 변경 대상: │
│ ├── src/index.js → src/main.jsx (엔트리포인트명도 변경) │
│ ├── src/App.js → src/App.jsx │
│ ├── 모든 JSX 포함 .js 파일 → .jsx로 변경 │
│ └── import 경로도 함께 수정 │
│ │
│ 팁: 일괄 변경 명령어 │
│ find src -name "*.js" -exec bash -c │
│ 'mv "$0" "${0%.js}.jsx"' {} \; │
│ │
│ 주의: JSX가 없는 순수 JS 유틸리티 파일은 .js 유지 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 5: vite.config.js 생성 │
│ │
│ 프로젝트 루트에 vite.config.js 파일 생성: │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ import { defineConfig } from 'vite' │ │
│ │ import react from '@vitejs/plugin-react' │ │
│ │ │ │
│ │ export default defineConfig({ │ │
│ │ plugins: [react()], │ │
│ │ server: { │ │
│ │ port: 3000, // CRA와 같은 포트 유지 │ │
│ │ open: true, // 브라우저 자동 열기 │ │
│ │ }, │ │
│ │ build: { │ │
│ │ outDir: 'build', // CRA와 같은 출력 디렉토리 │ │
│ │ }, │ │
│ │ }) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 이것이 CRA의 600줄+ webpack.config.js를 대체하는 전부 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 6: package.json scripts 수정 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 변경 전 (CRA): │ │
│ │ "scripts": { │ │
│ │ "start": "react-scripts start", │ │
│ │ "build": "react-scripts build", │ │
│ │ "test": "react-scripts test", │ │
│ │ "eject": "react-scripts eject" │ │
│ │ } │ │
│ │ │ │
│ │ 변경 후 (Vite): │ │
│ │ "scripts": { │ │
│ │ "dev": "vite", │ │
│ │ "build": "vite build", │ │
│ │ "preview": "vite preview", │ │
│ │ "test": "vitest" │ │
│ │ } │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 참고: │
│ ├── npm start → npm run dev (관례 변경) │
│ ├── eject 스크립트 제거 (더 이상 필요 없음!) │
│ └── preview: 프로덕션 빌드를 로컬에서 미리보기 │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 7: 환경변수 접두사 변경 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CRA: REACT_APP_ 접두사 │ │
│ │ Vite: VITE_ 접두사 │ │
│ │ │ │
│ │ .env 파일 변경: │ │
│ │ 변경 전: REACT_APP_API_URL=https://api.example.com │ │
│ │ 변경 후: VITE_API_URL=https://api.example.com │ │
│ │ │ │
│ │ 코드 변경: │ │
│ │ 변경 전: process.env.REACT_APP_API_URL │ │
│ │ 변경 후: import.meta.env.VITE_API_URL │ │
│ │ │ │
│ │ 차이점: │ │
│ │ CRA: process.env 사용 (Node.js 스타일) │ │
│ │ Vite: import.meta.env 사용 (ESM 표준) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 검색-치환으로 일괄 변경: │
│ 1. REACT_APP_ → VITE_ (모든 .env 파일) │
│ 2. process.env.REACT_APP_ → import.meta.env.VITE_ (모든 소스) │
│ │
└─────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────┐
│ Step 8: Jest → Vitest 마이그레이션 (선택) │
│ │
│ Vitest를 권장하는 이유: │
│ ├── Vite의 설정(vite.config.js)을 그대로 재사용 │
│ ├── Jest 호환 API (대부분의 테스트 코드 변경 불필요) │
│ ├── ESM 네이티브 지원 │
│ ├── Jest보다 빠른 실행 속도 │
│ └── HMR 기반 watch 모드 (변경된 테스트만 재실행) │
│ │
│ 설치: │
│ npm install --save-dev vitest @testing-library/react │
│ npm install --save-dev @testing-library/jest-dom │
│ npm install --save-dev jsdom │
│ │
│ vite.config.js에 테스트 설정 추가: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ export default defineConfig({ │ │
│ │ plugins: [react()], │ │
│ │ test: { │ │
│ │ globals: true, │ │
│ │ environment: 'jsdom', │ │
│ │ setupFiles: './src/setupTests.js', │ │
│ │ }, │ │
│ │ }) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 코드 변경: │
│ 대부분의 Jest 테스트 코드는 변경 없이 Vitest에서 동작 │
│ globals: true 설정으로 describe, it, expect 자동 import │
│ │
└─────────────────────────────────────────────────────────────────┘
8. 현재 생태계 현황 (2025-2026)
8.1 Vite의 지배적 위치
┌─────────────────────────────────────────────────────────────────┐
│ Vite의 현재 위상 (2025-2026) │
│ │
│ State of JS 2024 설문 결과: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Most Loved Library: Vite (#1) │ │
│ │ Build Tool 순위: Vite (#1) │ │
│ │ Retention Rate: 98% │ │
│ │ 만족도: 95% │ │
│ │ │ │
│ │ 의미: "한 번 사용한 사람의 98%가 다시 사용하겠다" │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ npm 다운로드 (Vite 7 기준): │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 주간 다운로드: 31,000,000+ (3,100만+) │ │
│ │ 전체 다운로드: 수십억 회 │ │
│ │ │ │
│ │ 비교: │ │
│ │ Vite: 31M+ /week │ │
│ │ create-react-app: 계속 감소 중 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Vite를 공식 채택한 프레임워크/도구: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ ├── SvelteKit (Svelte의 공식 프레임워크) │ │
│ │ ├── Nuxt 3 (Vue의 공식 프레임워크) │ │
│ │ ├── SolidStart (SolidJS의 공식 프레임워크) │ │
│ │ ├── Remix (v2부터 Vite 사용) │ │
│ │ ├── Vitest (Vite 기반 테스트 러너) │ │
│ │ ├── Storybook (v7부터 Vite 지원) │ │
│ │ ├── Analog (Angular 메타 프레임워크) │ │
│ │ └── Laravel (PHP 프레임워크의 프론트엔드) │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
8.2 Vite 8과 Rolldown
┌─────────────────────────────────────────────────────────────────┐
│ Vite의 미래: Rolldown 통합 │
│ │
│ 현재 Vite의 아키텍처 (Vite 6 이하): │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 개발 서버: esbuild (Go) + ESM 서빙 │ │
│ │ 프로덕션: Rollup (JavaScript) │ │
│ │ │ │
│ │ 문제: 두 개의 다른 도구를 사용 │ │
│ │ → Dev와 Prod 동작이 미세하게 다를 수 있음 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Rolldown이란? │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Rolldown = Rust 기반 통합 번들러 │ │
│ │ │ │
│ │ 목표: esbuild + Rollup을 하나로 대체 │ │
│ │ │ │
│ │ ┌───────────┐ │ │
│ │ │ esbuild │──┐ │ │
│ │ │ (Go) │ │ ┌──────────────┐ │ │
│ │ └───────────┘ ├───▶ │ Rolldown │ │ │
│ │ ┌───────────┐ │ │ (Rust) │ │ │
│ │ │ Rollup │──┘ └──────────────┘ │ │
│ │ │ (JS) │ │ │
│ │ └───────────┘ │ │
│ │ │ │
│ │ Rolldown의 장점: │ │
│ │ ├── Dev/Prod 통합: 하나의 도구로 일관된 동작 │ │
│ │ ├── 성능: 3-16배 빠른 프로덕션 빌드 │ │
│ │ ├── 메모리: 100배 메모리 절감 │ │
│ │ ├── Rollup 호환: 기존 플러그인 그대로 사용 │ │
│ │ └── Rust 기반: 안전하고 빠른 네이티브 코드 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ VoidZero Inc. (2024년 설립): │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Evan You가 설립한 회사 │ │
│ │ ├── Vite │ │
│ │ ├── Rolldown (Rust 번들러) │ │
│ │ ├── Oxc (Rust 기반 JavaScript 도구체인) │ │
│ │ │ ├── Oxlint (ESLint보다 50-100x 빠른 린터) │ │
│ │ │ ├── 파서, 트랜스포머 등 │ │
│ │ │ └── 미래: Oxc가 esbuild/Babel/ESLint 모두 대체 │ │
│ │ └── 미션: JavaScript 도구체인의 통합 및 현대화 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 미래 Vite 아키텍처 (Vite 7/8): │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 개발 서버: Rolldown (Rust) │ │
│ │ 프로덕션: Rolldown (Rust) │ │
│ │ │ │
│ │ → 동일한 도구! Dev/Prod 불일치 문제 완전 해결 │ │
│ │ → 더 빠른 빌드 + 더 적은 메모리 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
8.3 Turbopack과의 경쟁
┌─────────────────────────────────────────────────────────────────┐
│ Turbopack: Vercel의 대안 │
│ │
│ Turbopack이란? │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ 개발: Vercel (Next.js를 만든 회사) │ │
│ │ 언어: Rust │ │
│ │ 창시자: Tobias Koppers (webpack 창시자!) │ │
│ │ 발표: 2022년 10월 │ │
│ │ │ │
│ │ 흥미로운 점: │ │
│ │ webpack을 만든 사람이 webpack의 후속작을 만들고 있음 │ │
│ │ "webpack의 정신적 후계자" │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ Turbopack vs Vite: │
│ ┌──────────────┬──────────────────┬──────────────────────┐ │
│ │ 항목 │ Turbopack │ Vite │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 언어 │ Rust │ JS + Go + Rust │ │
│ │ │ │ (Rolldown 전환 중) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 프레임워크 │ Next.js 전용 │ 프레임워크 무관 │ │
│ │ 지원 │ │ (모두 지원) │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 상태 │ Dev: 안정 │ 안정 (v7) │ │
│ │ (2025 기준) │ Prod: 베타 │ │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 생태계 │ Next.js에 묶임 │ 방대한 플러그인 │ │
│ │ │ │ 생태계 │ │
│ ├──────────────┼──────────────────┼──────────────────────┤ │
│ │ 사용 가능 │ Next.js 15+ │ 모든 프로젝트 │ │
│ │ 환경 │ │ │ │
│ └──────────────┴──────────────────┴──────────────────────┘ │
│ │
│ 현실적 비교: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Turbopack: Next.js를 쓴다면 자동으로 사용하게 됨 │ │
│ │ Next.js 밖에서는 사용 불가 │ │
│ │ │ │
│ │ Vite: Next.js를 제외한 거의 모든 프로젝트에서 사용 │ │
│ │ 범용 빌드 도구의 왕좌 │ │
│ │ │ │
│ │ → 경쟁이라기보다 용도가 다름 │ │
│ │ → Next.js = Turbopack, 그 외 = Vite │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
9. 정리
┌─────────────────────────────────────────────────────────────────┐
│ 최종 정리 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ CRA (2016-2025) │ │
│ │ ════════════════ │ │
│ │ 역할: JavaScript Fatigue 해결, React 대중화 공헌 │ │
│ │ 상태: Deprecated (2025.02.14 공식 선언) │ │
│ │ 교훈: 한 시대를 정의한 도구도 기술 발전에 따라 은퇴한다 │ │
│ │ │ │
│ │ Vite (2020-현재) │ │
│ │ ═══════════════ │ │
│ │ 역할: 차세대 빌드 도구의 표준 │ │
│ │ 상태: 활발한 개발 중 (v7, Rolldown 통합 진행) │ │
│ │ 미래: JavaScript 빌드 도구체인의 통합 플랫폼 │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 핵심 메시지: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 1. 새 React 프로젝트 = Vite (이견 없음) │ │
│ │ │ │
│ │ 2. 기존 CRA 프로젝트 = Vite로 마이그레이션 권장 │ │
│ │ (비교적 간단, 즉각적 성능 향상) │ │
│ │ │ │
│ │ 3. Full-stack 앱 = Next.js 또는 Remix 고려 │ │
│ │ (SSR/SEO 필요 시) │ │
│ │ │ │
│ │ 4. CRA는 역사적 유산으로 존중하되, 더 이상 사용하지 않음 │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 빌드 도구 진화의 흐름: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ Grunt/Gulp (2012-2015) │ │
│ │ │ 태스크 러너 시대 │ │
│ │ ▼ │ │
│ │ webpack (2014-현재) │ │
│ │ │ 모듈 번들러 시대 │ │
│ │ ▼ │ │
│ │ CRA (2016-2025) │ │
│ │ │ Zero-config 시대 (webpack 래핑) │ │
│ │ ▼ │ │
│ │ Vite (2020-현재) │ │
│ │ │ ESM + 네이티브 도구 시대 │ │
│ │ ▼ │ │
│ │ Rolldown/Oxc (2024-미래) │ │
│ │ Rust 기반 통합 도구체인 시대 │ │
│ │ │ │
│ │ 트렌드: JavaScript → Go → Rust │ │
│ │ (도구 자체의 구현 언어가 점점 저수준으로 이동) │ │
│ │ (더 빠르고, 더 메모리 효율적으로) │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
│ 개발자를 위한 한 줄 결론: │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ npm create vite@latest my-app -- --template react-ts │ │
│ │ │ │
│ │ 이 한 줄이면 됩니다. CRA는 잊으세요. │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
관련 키워드
CRA, Create React App, Vite, webpack, esbuild, Rollup, Rolldown, Dan Abramov, Evan You, JavaScript Fatigue, ESM, ES Modules, HMR, Hot Module Replacement, react-scripts, eject, Turbopack, VoidZero, State of JS, 번들러, 빌드 도구, 프론트엔드 도구체인