
React를 처음 배울 때 우리는 보통 npx create-react-app my-app 한 줄로 프로젝트를 시작합니다. 그런데 요즘 React 생태계의 분위기는 확실히 달라졌습니다. 다들 “이제 CRA 말고 Vite 쓰세요”라고 말하죠.
그러다 보면 자연스럽게 이런 질문이 떠오릅니다.
왜 요즘은 CRA가 아니라 Vite일까? 그리고 CRA, Vite, Webpack, Babel은 각각 무슨 역할을 할까?
사실 이 두 질문은 연결되어 있습니다. 왜 Vite로 넘어가는지를 제대로 이해하려면, 그 안에서 일하는 Webpack과 Babel부터 알아야 하기 때문입니다. 결론부터 말하면 이 넷은 같은 종류의 도구가 아니라, 서로 다른 층(layer)에서 일하는 도구들이에요.
그래서 이 글에서는 Webpack과 Babel이 어떤 일을 하는지 먼저 짚고, 그 위에서 CRA와 Vite가 어떻게 다른지 — 그리고 왜 CRA는 뒤로 밀려나게 되었는지를 정리해 보겠습니다.
1. 먼저, 이 도구들은 레벨이 다릅니다
Babel, Webpack, CRA, Vite — 비슷해 보이지만 사실 하는 일이 전혀 다릅니다. 이 넷은 각자 다른 레벨에서 일하는 도구들이에요.
| 도구 | 한 줄 정의 | 역할의 층위 |
|---|---|---|
| Babel | 최신 JS/JSX를 구형 브라우저용 코드로 변환 | 부품 (변환기) |
| Webpack | 흩어진 파일들을 하나로 묶음 | 부품 (번들러) |
| CRA | Webpack + Babel을 미리 세팅해 둔 시작 키트 | 완성품 (도구 모음) |
| Vite | 번들링 방식을 새로 설계한 빌드 도구 | 완성품 (도구 모음) |
즉 Babel과 Webpack은 엔진·부품이고, CRA와 Vite는 그 부품을 조립해 만든 완성된 자동차입니다. CRA와 Vite를 비교하려면, 그 안에 들어 있는 Babel과 Webpack부터 이해해야 하는 이유가 여기 있습니다.
핵심: Babel·Webpack은 부품, CRA·Vite는 그 부품으로 만든 완성품이다.
2. Babel — 최신 문법을 번역하는 번역기
우리가 React에서 매일 쓰는 이런 코드를 떠올려 봅시다.
const App = () => {
return <h1>Hello!</h1>;
};
여기엔 두 가지 문제가 있습니다. 첫째, <h1> 같은 JSX 문법은 브라우저가 모릅니다. 둘째, 화살표 함수나 const 같은 최신 문법은 아주 오래된 브라우저에서 동작하지 않을 수 있습니다.
Babel은 이 코드를 브라우저가 알아들을 수 있는 평범한 JavaScript로 바꿔 줍니다.
// Babel이 변환한 결과 (실제 출력은 Babel 설정에 따라 조금씩 다릅니다)
var App = function App() {
return React.createElement("h1", null, "Hello!");
};
React 개발자에게 Babel이 중요한 이유는 단순합니다. Babel이 없으면 JSX 자체가 동작하지 않기 때문입니다. 우리가 JSX를 자유롭게 쓸 수 있는 건 뒤에서 Babel이 조용히 번역해 주고 있기 때문이에요.
핵심: Babel은 브라우저가 모르는 문법을 아는 문법으로 번역해 주는 번역기다.
3. Webpack — 흩어진 파일을 하나로 묶는 번들러
React 프로젝트는 컴포넌트, CSS, 이미지 등 수십~수백 개의 파일로 쪼개져 있습니다. 그런데 브라우저가 이 파일을 하나하나 따로 요청하면 느리고 비효율적입니다.
Webpack은 import / export로 연결된 파일들을 따라가며 의존성 그래프를 만들고, 그것을 몇 개의 파일(번들)로 합쳐 줍니다.
App.jsx ─┐
Button.jsx ─┼─> [ Webpack ] ─> bundle.js (하나로 합쳐진 결과)
style.css ─┘
여기서 중요한 점은 Webpack과 Babel은 협업 관계라는 것입니다. Webpack이 파일을 묶다가 JSX 파일을 만나면, 그 파일의 번역은 Babel에게 넘깁니다. Webpack은 묶는 일을, Babel은 번역하는 일을 맡는 분업 구조입니다.
핵심: Webpack은 흩어진 파일을 번들로 묶고, 그 과정에서 Babel에게 번역을 맡긴다.
4. CRA — Webpack과 Babel을 미리 조립해 둔 시작 키트
여기까지 읽으면 이런 생각이 들 겁니다. 그럼 React 프로젝트를 시작할 때마다 Webpack과 Babel을 매번 직접 설정해야 할까요?
예전에는 그래야 했습니다. 그리고 그 설정은 React를 막 시작한 사람에게 꽤 높은 진입 장벽이었죠 ૮(•᷄ࡇ•᷅ )ა CRA(Create React App)는 바로 그 번거로움을 없애주려고 등장했습니다.
CRA는 Webpack, Babel, 개발 서버, 테스트 환경 같은 설정을 미리 다 조립해서 명령어 한 줄로 끝내 줍니다.
npx create-react-app my-app
장점은 명확합니다. 설정을 몰라도 바로 React 개발을 시작할 수 있죠. 대신 그 설정들이 react-scripts라는 패키지 안에 숨겨져 있어서, 세부 설정을 바꾸려면 까다롭다는 단점이 있습니다.
중요: CRA는 2025년 초 React 공식 팀에 의해 권장 중단되었습니다. 공식 문서도 이제 새 프로젝트에는 Vite나 프레임워크를 권하니, 지금 React를 시작한다면 CRA보다 Vite를 보게 될 가능성이 큽니다.
핵심: CRA는 Webpack·Babel 설정을 대신 해 주는 시작 키트지만, 지금은 더 이상 권장되지 않는다.
5. Vite — 번들링 방식 자체를 다시 생각한 빌드 도구
CRA가 느리다는 불만은 오래전부터 있었습니다. 프로젝트가 커질수록 개발 서버를 켜는 데 한참 걸리고, 코드를 한 줄 고쳐도 화면 반영이 느려졌죠.
이유는 Webpack의 동작 방식에 있습니다. Webpack은 개발 서버를 켤 때 모든 파일을 미리 번들로 묶습니다. 파일이 많을수록 이 작업이 오래 걸립니다.
Vite는 발상을 뒤집었습니다. 요즘 브라우저는 import 문법(ES Modules)을 직접 이해할 수 있다는 점을 활용해, 개발 중에는 프로젝트 코드를 미리 묶지 않고 브라우저가 요청하는 파일만 그때그때 변환해서 보내 줍니다.
npm create vite@latest my-app -- --template react
그래서 프로젝트가 아무리 커도 개발 서버가 거의 즉시 켜집니다. (배포용 빌드에서는 Vite도 Rollup으로 묶지만, 개발 중에는 묶지 않는다는 점이 핵심입니다.)
참고: Rollup은 Webpack과 같은 번들러(파일을 묶는 도구)입니다. 결과물이 깔끔해 라이브러리 제작에 강점이 있고, Vite는 배포용 빌드에 이 Rollup을 사용합니다.
속도 차이는 처음 켤 때만의 이야기가 아닙니다. 개발 중 코드를 한 줄 고쳤을 때 그 변경을 화면에 반영하는 기능을 HMR(Hot Module Replacement) 이라고 하는데, 페이지 전체를 새로고침하지 않고 바뀐 부분만 즉시 갈아끼웁니다. Vite는 개발 서버가 파일 하나만 다시 변환하면 되기 때문에 이 HMR도 CRA보다 훨씬 빠릅니다. 우리가 “Vite는 빠르다”고 느끼는 건 결국 개발 서버 시작 속도 + HMR 반영 속도, 이 둘의 체감 차이인 셈입니다.
개발 서버와 HMR이 내부에서 정확히 어떻게 동작하는지는 이야기가 꽤 길어서, 추후에 Vite를 더 깊이 다루는 글에서 따로 정리해 보겠습니다.
핵심: Vite는 자주 바뀌는 프로젝트 코드는 미리 묶지 않고, 잘 바뀌지 않는 의존성만 한 번 묶어두는 방식으로 속도 문제를 해결했다.
참고: 의존성이란 react, lodash처럼 내가 직접 만들지 않고 외부에서 설치해 가져다 쓰는 라이브러리를 말합니다.
package.json에 적히고node_modules에 설치됩니다.
6. CRA vs Vite — 한눈에 비교
이제 진짜 비교 대상인 CRA와 Vite를 정리해 봅시다.
| 항목 | CRA | Vite |
|---|---|---|
| 내부 번들러 | Webpack | 개발: 브라우저 ESM / 배포: Rollup |
| 변환 도구 | Babel | esbuild (Go 기반, 매우 빠름) |
| 개발 서버 시작 속도 | 프로젝트가 크면 느림 | 거의 즉시 |
| 코드 수정 반영(HMR) | 상대적으로 느림 | 빠름 |
| 설정 변경 | 어려움 (eject 필요) | vite.config.js로 간단 |
| 현재 상태 | 공식 권장 중단 | 사실상 표준으로 자리잡음 |
표에서 보듯 CRA와 Vite의 차이는 결국 내부에서 어떤 부품을 어떤 방식으로 쓰느냐의 차이입니다. CRA는 Webpack+Babel을 전통적인 방식으로, Vite는 esbuild와 브라우저 ESM을 활용한 새로운 방식으로 조립했을 뿐이에요.
핵심: CRA와 Vite의 차이는 안에 든 부품과 조립 방식의 차이다.
참고: esbuild는 Go로 만든 아주 빠른 변환·번들링 도구로, Babel·Webpack이 하던 일을 훨씬 빠르게 처리합니다. 브라우저 ESM은 브라우저가
import·export문법을 직접 이해하는 기능으로, 덕분에 Vite는 개발 중 파일을 미리 다 묶지 않아도 됩니다.
7. 그래서 React 개발자가 알아야 할 것
여기까지의 내용을 다음 네 가지 질문으로 정리했습니다.
내가 쓴 JSX는 왜 그냥 동작할까? → Babel(또는 esbuild)이 번역해 줬으니까.
컴포넌트를 이렇게 많이 나눴는데 브라우저는 어떻게 한 번에 읽을까? → Webpack(또는 Rollup) 같은 번들러가 묶어 줬으니까.
그럼 이걸 매번 직접 설정해야 할까? → 아니다. CRA와 Vite가 대신 해 준다.
새 프로젝트는 뭘로 시작할까? → 이제는 CRA가 아니라 Vite.
이 흐름을 알아두면 에러 메시지에 babel·webpack·vite 같은 단어가 떠도 당황하지 않습니다. 번역 단계의 문제인지 묶는 단계의 문제인지, 어디부터 봐야 할지 방향이 잡히기 때문입니다.
핵심: 도구의 역할을 구분할 줄 알면, 에러가 나도 어디를 봐야 할지 알 수 있다.
한 줄 요약
Babel은 번역기, Webpack은 묶는 도구(번들러)이고, CRA와 Vite는 이 둘을 대신 세팅해 주는 시작 키트다. CRA는 Webpack을 전통 방식으로, Vite는 더 빠른 방식으로 조립했다. 그리고 앞으로 새 프로젝트의 답은 사실상 Vite 하나다.
