반응형

2025년 12월 초, React Server Components(RSC)에서 인증 없이 서버에서 임의 코드 실행(RCE) 이 가능한 치명적인 취약점이 공개됐다. 이 이슈는 React 측에서 CVE-2025-55182, Next.js 측에서 CVE-2025-66478로 공지되었고, 공통적으로 CVSS 10.0(최상위 등급) 을 받았다. (React)


이 글에서는:

  1. RSC(React Server Components)가 무엇인지
  2. 이번 RSC 취약점이 어떤 구조적 문제인지
  3. 공격 코드(Exploit)가 어떤 식으로 동작하는지 개념적으로
  4. 개발자/운영자가 당장 무엇을 해야 하는지

를 정리한다.


1. RSC(React Server Components)는 무엇인가?

1-1. 기존 CSR/SSR과 뭐가 다른가?

전통적인 React 앱은 크게 두 가지 방식으로 렌더링한다.

  • CSR(Client-Side Rendering): 브라우저가 JS 번들을 받아서 UI를 전부 그린다.
  • SSR(Server-Side Rendering): 서버에서 HTML을 만든 뒤 브라우저로 보내고, 이후에 JS가 “하이드레이션”을 통해 인터랙션을 붙인다.

React Server Components(RSC) 는 여기서 한 걸음 더 나가서,

“일부 컴포넌트는 아예 서버에서만 돌고, 그 결과만 클라이언트에 스트리밍하자”는 개념이다. (React)

핵심 포인트를 정리하면:

  • 서버 전용 컴포넌트(서버 컴포넌트)를 정의할 수 있다.
  • 이 컴포넌트는 Node 환경에서 돌아가며, 데이터베이스/파일 시스템 등 백엔드 리소스에 직접 접근한다.
  • 브라우저로는 이 컴포넌트의 JS 코드가 아니라, 직렬화된 결과(Flight payload) 만 보내진다.
  • 클라이언트는 이 스트림을 받아 기존 React 트리에 합쳐서 UI를 완성한다. (React)

Next.js 13 App Router 이후의 기본 구조가 바로 이 RSC를 중심으로 설계되어 있고, React 19에서 정식으로 Flight 프로토콜과 함께 도입되었다. (Snyk)

1-2. 왜 RSC가 매력적이었나?

RSC가 등장한 이유는 간단하다. 프론트엔드가 너무 “무거워졌기” 때문이다.

  • 대형 라이브러리를 전부 브라우저로 보내지 않고, 서버에 남겨둘 수 있다.
  • 서버에서 데이터 페칭과 렌더링을 함께 처리해 waterfall 요청을 줄인다.
  • 민감한 토큰/키는 브라우저로 절대 내려보내지 않고, 서버 코드 안에 숨길 수 있다. (tech.kakaopay.com)

즉, RSC는 성능 + DX + 보안(원래는…) 을 모두 잡기 위한 야심찬 기능이었다.

문제는, 이걸 위해 도입한 Flight 프로토콜 이 이번 RCE의 공격 표면이 됐다는 점이다.


2. RSC 취약점(CVE-2025-55182 / 66478)은 무엇인가?

2-1. 취약점 요약

React 팀 공식 블로그와 여러 보안 업체 분석을 종합하면, 이번 이슈의 본질은 다음과 같다. (React)

Flight 프로토콜을 통해 들어오는 RSC 페이로드를 역직렬화하는 과정에서,
공격자가 조작한 데이터를 “데이터”가 아니라 “코드 경로”로 해석해 버리는 논리적 역직렬화 취약점.

구체적으로는:

  • 취약 코드는 react-serverreact-server-dom-* 패키지 내부의 Flight 처리 부분에 존재한다. (React)
  • 클라이언트 → 서버로 전송되는 Server Function 호출 / RSC 업데이트 요청 을 해석할 때,
  • “어떤 함수를 호출할지”에 대한 참조(reference)를 신뢰하고,
  • 그 참조가 실제로 허용된 함수인지, 안전한 대상인지 충분히 검증하지 않는다.
  • 그 결과, 공격자가 특정 형태의 Flight 청크를 만들어 Node.js의 내부 객체, 모듈 로더, child_process 같은 위험한 함수에 간접적으로 도달하게 만들 수 있다. (Checkmarx)

이 취약점은:

  • 인증이 필요 없다 (pre-auth RCE)
  • React 19 계열과 이를 사용하는 Next.js 15–16 App Router 기본 설정에 영향을 준다.
  • 새로 만든 Next.js 앱(create-next-app)조차, 아무 커스텀 코드 없이도 취약할 수 있는 것으로 보고됐다. (upwind.io)

그래서 보안 업계에서 CVSS 10.0, “React2Shell / React4Shell” 같은 이름으로 부르며 강하게 경고하고 있다. (feature-sliced.design)

2-2. 어떤 앱이 영향을 받는가?

대부분의 분석과 공식 권고를 정리하면: (React)

  • 취약 대상
    • React 19 + react-server-dom-* 를 사용하는 RSC 지원 환경
    • Next.js 15–16에서 App Router + RSC/Server Actions를 사용하는 앱
  • 부분 논쟁 포인트
    • Server Function 엔드포인트를 직접 구현하지 않아도, RSC를 지원하는 설정 자체만으로도 취약할 수 있다는 리서치가 있다. (@Ounols)
  • 직접적인 영향 X(이번 CVE에 한정)
    • RSC를 전혀 사용하지 않는 순수 CSR 앱
    • Next.js 옛 Pages Router만 사용하는 레거시 앱
    • 서버에서 RSC 관련 패키지를 아예 로드하지 않는 환경
    • (캐나다 사이버 보안 센터, Snyk 등 일부 권고문에서 “RSC/서버 함수 비활성화 시 이번 CVE의 공격면은 사라진다”고 명시) (York University)

단, 이건 어디까지나 이번 RSC RCE 취약점에 한정된 얘기다.

SSR, API 라우트, 다른 라이브러리의 취약점은 여전히 별도의 공격면으로 존재한다.


3. 공격 시나리오 & 코드 예시(개념적)

이미 여러 보안 업체와 연구자들이 PoC(Proof of Concept) 익스플로잇 코드를 공개한 상태다. (Cyber Security News)

이 글에서는 실제 악성 코드를 그대로 가져오지 않고, “어떤 식으로 동작하는지”를 이해하기 위한 개념 수준의 예시만 정리한다.

3-1. RSC / Flight 요청 흐름 복습

RSC + Server Functions가 동작할 때의 기본 흐름은 대략 이렇다. (Checkmarx)

  1. 클라이언트 컴포넌트에서 Server Function 을 호출한다.
  2. React는 이 호출을 Flight 프로토콜 포맷으로 직렬화해 HTTP 요청으로 전송한다.
  3. 서버는 HTTP 요청을 받아 Flight 청크를 역직렬화 → 어떤 서버 함수인지 찾아서 호출 한다.
  4. 서버 함수 결과를 다시 Flight 포맷으로 직렬화해 클라이언트로 스트리밍한다.

문제는 3번 단계, “역직렬화 + 함수 참조 해석” 에 있다.

3-2. 서버 쪽 취약 로직(개념적 코드)

아주 단순화하면, 취약한 로직은 아래처럼 생각할 수 있다 (실제 구현과 동일하지 않다):

// ⚠ 개념 설명용 의사 코드 (실제 React 코드 아님)
function handleFlightRequest(req) {
  const chunk = decodeFlight(req.body);  // Flight 페이로드 역직렬화
  // chunk.fnRef 에는 "어떤 서버 함수를 호출할지"에 대한 정보가 들어 있음

  const fn = resolveFunctionReference(chunk.fnRef); // 여기서 사용자 입력을 너무 신뢰함
  const args = chunk.args;

  // 검증 없이 곧바로 호출
  return fn(...args);
}

여기서 fnRef정상적인 서버 함수를 가리키는 것이 아니라,

Node.js의 내부 객체나 위험한 함수(예: child_process.exec)로 이어지는 체인을 가리키도록 조작될 수 있다면?

공개된 PoC들은 바로 이 부분을 노려,

  • Flight 프로토콜이 허용하는 형식 안에서
  • 특정 객체 그래프를 타고
  • 최종적으로 OS 명령 실행이 가능한 함수까지 도달하도록

치밀하게 직렬화된 페이로드를 만든다. (GitHub)

3-3. 공격 코드가 하는 일(고수준)

공개 PoC들이 공통적으로 수행하는 단계는 대략 다음과 같이 요약할 수 있다. (GitHub)

  1. 대상 스캐닝
    • 인터넷에 노출된 React/Next.js 서버 중 RSC/Server Functions 엔드포인트가 열려 있는지 스캔
    • 특정 경로나 헤더 패턴(Flight 엔드포인트)을 찾는다.
  2. 특수하게 직렬화된 Flight 페이로드 생성
    • 정상적인 Server Function 호출처럼 보이도록 포맷을 맞추되,
    • fnRef나 인자 부분에 의도적으로 조작한 참조/값 을 넣는다.
    • 이 참조가 역직렬화 과정에서 위험한 함수 체인으로 해석되도록 구성한다.
  3. 원격 코드 실행
    • 최종적으로 Node.js에서 child_process / vm / 기타 코드 실행 기능에 도달하여
    • touch /tmp/pwned 같은 간단한 명령부터,
    • 쉘을 열거나 랜섬웨어/백도어 설치 스크립트를 다운로드하는 명령까지 실행 가능해진다.
  4. 후속 공격
    • 얻은 권한으로 추가 백도어 설치, 데이터 유출, 랜섬웨어 배포 등 일반적인 RCE 시나리오를 수행한다. (데일리시큐)

현재 그레이노이즈 등에서는 이미 자동화된 대량 스캐닝/공격 트래픽이 관측되고 있다고 보고한다. (greynoise.io)

정리하면:

공격 코드는 “React/Next.js를 해킹하는 마법 같은 스크립트”라기보다는,

Flight 프로토콜을 잘 이해하고, 역직렬화 로직이 “코드처럼” 해석하는 틈을 파고드는 특수 페이로드 생성기에 가깝다.


4. 어떻게 대처할 것인가?

4-1. 최우선: React / Next.js 패치

정식 패치 적용이 가장 중요하다.

  • React 팀은 react-server-dom-* 패키지에 대한 보안 업데이트를 배포했다. (React)
    • 예:
      • react-server-dom-webpack 19.0 → 19.0.1
      • 19.1.0–19.1.1 → 19.1.2
      • 19.2.0 → 19.2.1
  • AWS, Aikido 등도 “React 19.x + RSC 사용 시 위 버전 이상으로 즉시 업그레이드하라”고 안내한다. (Amazon Web Services, Inc.)
  • Next.js 측에서도 App Router 기반 프로젝트는 패치된 15/16 버전으로 업데이트할 것을 권고한다. (Next.js)

한국 KRCERT 역시 같은 내용의 업데이트 권고를 게시했다. (KISA 보호나라)

실무 팁:

  • 패치 후에는 CI/CD 파이프라인에서 잠재적으로 남아 있을 수 있는 구버전 lock 파일(예: yarn.lock, package-lock.json)도 같이 점검하는 게 좋다.
  • 모노레포/멀티 패키지 구조라면, 각 패키지별 react-server-dom-* 버전이 다르지 않은지 확인.

4-2. 임시 대응: RSC / Server Functions 비활성화

즉시 패치가 불가능한 환경이라면, 여러 기관에서 아래와 같은 임시 조치를 제안한다. (York University)

  • RSC 및 서버 함수 기능 비활성화
    • React 19: 서버에서 RSC/Server Functions를 사용하는 경로/엔드포인트를 임시로 막는다.
    • Next.js:
      • App Router에서 RSC/Server Actions를 사용하는 페이지를 비활성화하거나
      • 문제가 되는 라우트를 프록시 뒤로 숨기거나
      • 가능하다면 Pages Router로 임시 롤백
  • 공개 엔드포인트 축소
    • 외부 인터넷에서 직접 접근 가능한 RSC/Server Function 엔드포인트를 최소화
    • 사내망 또는 VPN 뒤로 숨기기

이렇게 하면 이번 CVE와 직결되는 공격면은 제거할 수 있다.

물론 애플리케이션 기능에 영향을 줄 수 있으니, 비즈니스 영향도와 균형을 맞추어야 한다.


5. RSC를 사용하는 개발자가 얻어야 할 교훈

이번 이슈가 주는 메시지는 꽤 명확하다.

  1. “데이터 직렬화”와 “코드 실행 경로”가 뒤섞이지 않도록 설계해야 한다.
    • Flight처럼 복잡한 프로토콜에서는 특히, 사용자가 조작 가능한 값이 코드 경로까지 흘러들어가지 않도록 엄격히 검증해야 한다.
  2. 보안을 “기능별”이 아니라 “요청 경로 / 데이터 흐름별”로 모델링해야 한다.
    • App Router, Middleware, API Routes, RSC, Server Functions 등 여러 레이어를 얇게 쌓다 보면,
    • “위 레이어에서 인증했겠지”라고 믿다가 아래 레이어에서 우회가 터질 수 있다.
  3. 새로운 추상화는 곧 새로운 공격면이다.
    • RSC는 확실히 DX/성능 측면에서 매력적인 기능이지만,
    • 그만큼 복잡한 직렬화 프로토콜과 서버 실행 경로를 내포한다.
    • 이런 기능을 도입할 때는 성능 벤치마크만 볼 게 아니라, 공격 모델 도 함께 설계해야 한다.

마무리

정리하면:

  • RSC는 “서버 전용 컴포넌트 + Flight 프로토콜”을 통해 클라이언트와 서버 사이의 렌더링을 세밀하게 쪼개는 기능이다.
  • 이번 CVE-2025-55182 / 66478는 그 Flight 역직렬화 과정에서,
    • 사용자 입력을 위험한 함수 참조로 해석해 버리는 논리적 역직렬화 취약점이며,
    • 인증 없는 RCE(CVSS 10.0)로 이어진다.
  • 공개 PoC들은 이 취약점을 이용해 공격자가 조작한 Flight 페이로드를 보내,
    • Node 내부 객체 체인을 타고
    • OS 명령 실행까지 도달하는 과정을 자동화하고 있다.
  • 대응은
    • React/Next.js 패치가 최우선,
    • 패치 전에는 RSC/Server Functions 비활성화 + WAF·권한 최소화·모니터링 강화가 현실적인 방안이다.

반응형

'Web > React' 카테고리의 다른 글

[React] useMemo, useEffect 에러 (인 줄 알았던 휴먼에러)  (0) 2025.03.23
[React] useRef, useMemo, useCallback  (1) 2024.12.13
React 번들링  (1) 2024.12.01
React의 특징  (2) 2024.11.17
반응형

Problem


    // 정렬된 랭킹 데이터 - 메모이제이션 적용
    const rankingItems = useMemo(() => {
        if (!userRankingData || userRankingData.length === 0) return [];

        let sortedItems = [...userRankingData];
        console.log("sortedItems:", sortedItems);
        switch (sortBy) {
            case 'score':
                return sortedItems.sort((a, b) => b.score - a.score);
            default:
                return sortedItems;
        }
    }, [userRankingData, sortBy]);

    // 데이터 프리페칭
    useEffect(() => {
        console.log("fetching ...")
        prefetchRankingData();
    }, []);

Why?


  • 코드의 목적
    • prefetchingRankingData → rankingItems 최신화
  • 렌더링 이후에 useEffect가 호출이 되기 때문에 useMemo가 먼저 호출되어 fetching이 제대로 되지 않는다.

Solve


prefecthRankingData() 에서 accounts 를 불러오는 함수가 잘못 설정 되어있었다.,,

지우고 refetch 함수를 제작해서 해결

반응형

'Web > React' 카테고리의 다른 글

React Server Components와 CVE-2025-55182 / 66478 RCE  (0) 2025.12.06
[React] useRef, useMemo, useCallback  (1) 2024.12.13
React 번들링  (1) 2024.12.01
React의 특징  (2) 2024.11.17
반응형

1. useRef

특징 및 사용 목적

  • 값 저장: 컴포넌트가 다시 렌더링되어도 참조 값을 유지할 수 있습니다.
  • DOM 접근: 특정 DOM 요소에 직접 접근하거나 조작할 때 사용됩니다.
  • 렌더링 영향 없음: 값이 변경되어도 컴포넌트를 다시 렌더링하지 않습니다.

주요 사용 예시

  • DOM 요소의 포커스 제어, 크기/위치 확인
  • 이전 상태 값 저장
  • 타이머가 업데이트 될 때마다 불필요한 렌더링 방지
function Timer() {
  const timerRef = useRef(null);
  const [time, setTime] = useState(0);

  const startTimer = () => {
    if (!timerRef.current) {
      timerRef.current = setInterval(() => {
        setTime((prevTime) => prevTime + 1);
      }, 1000);
    }
  };

  const stopTimer = () => {
    clearInterval(timerRef.current);
    timerRef.current = null;
  };

  return (
    <div>
      <p>Time: {time}s</p>
      <button onClick={startTimer}>Start</button>
      <button onClick={stopTimer}>Stop</button>
    </div>
  );
}

2. useMemo

특징 및 사용 목적

  • 계산된 값의 캐싱: 복잡한 계산 결과를 캐싱하여 성능을 최적화합니다.
  • 종속성 배열: 지정된 종속성 값이 변경될 때만 다시 계산합니다.
  • 렌더링 성능 개선: 렌더링 과정에서 불필요한 계산을 방지합니다.

주요 사용 예시

  • 무거운 연산이나 데이터 변환 최적화
  • 컴포넌트에서 조건에 따라 변경되는 데이터 처리
  • 자식 컴포넌트에 전달할 복잡한 데이터 생성
function Parent() {
  const [count, setCount] = useState(0);

  const data = useMemo(() => {
    console.log('Generating data...');
    return { value: count };
  }, [count]); // `count`가 변경될 때만 데이터 재생성

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Increment</button>
      <Child data={data} />
    </div>
  );
}

function Child({ data }) {
  console.log('Child rendered');
  return <p>Child received: {data.value}</p>;
}

3. useCallback

특징 및 사용 목적

  • 함수 캐싱: 동일한 함수 객체를 재사용하여 불필요한 렌더링을 방지합니다.
  • 종속성 배열: 지정된 종속성이 변경될 때만 새로운 함수 객체를 생성합니다.
  • 자식 컴포넌트 최적화: React.memo와 함께 사용하여 불필요한 렌더링을 줄입니다.

주요 사용 예시

  • 부모 컴포넌트에서 자식 컴포넌트로 콜백을 전달할 때, 불필요한 재생성으로 인해 자식 컴포넌트가 다시 렌더링되지 않도록 하고 싶을 때.
function Parent() {
  const [count, setCount] = useState(0);

  const handleClick = useCallback(() => {
    setCount((prevCount) => prevCount + 1);
  }, []); // 동일한 함수 객체 유지

  return (
    <div>
      <p>Parent Count: {count}</p>
      <Child onClick={handleClick} />
    </div>
  );
}

const Child = React.memo(({ onClick }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Increment Parent Count</button>;
});

비교

Hook 사용 목적 렌더링 영향
useRef 값 저장, DOM 접근 X
useMemo 계산된 값 캐싱 O
useCallback 함수 캐싱, 자식 컴포넌트 최적화 O

useMemo, useCallback 의 차이는 미미하다.

https://www.linkedin.com/feed/update/urn:li:activity:7233818253674889217/

 

최효빈님의 LinkedIn 활동 보기

로그인 또는 회원 가입 후 더 확인해 보세요.

www.linkedin.com

 

useMemo(() => {{원하는함수}}, dependencies)
//useCallback 과 비슷해보이는 모습

 

훅으로 훅 만들기

리액트의 구현 방식 때문에 useReduceruseStateuseRefuseMemo 를 구현할 수 있다.

왜일까?

리액트 공식문서를 찾아보면, useRef, useMemo, useState 는 결국 fiber에 붙은 hook.memoizedState 를 반환하는 것. 또한, setState, dispatch역시 react-reconciler의 dispatch 함수를 어떤 형태로 반환하느냐의 차이다.

useReducer ⇒ useState

function useState<S>(initState: S | (() => S)) : [S, (action: SetStateAction>S>) => void] {
    const [state, dispatch] = useReducer(
        (state: S, action: SetStateAction<S>): S =>
            typeof action === 'function' ? (action as (prevState: S) => S)(state) : action,
        typeof initState === 'function' ? (initState as () => S)() : initState
    );

    return [state, dispatch];
} 

useRef ⇒ useMemo

function useMemo<T>(factory: () => T, deps: React.DependencyList): T {
    const ref = useRef<{ value : T; deps: React.DependencyList | undefined }>){
        value: undefined as T,
        deps : undefined,
    });

    if(!ref.current_deps || !shallowEqual(deps, ref.current.deps)) {
        ref.current.value = factory();
        ref.current.deps = deps;
    }

    return ref.current.value;
}

useMemo ⇒ useCallback

function useCallback<T extends (...args: any[]) => any>(
    callback: T,
    deps: React.DependencyList
): T {
    return useMemo(() => callback, deps);
}
반응형

'Web > React' 카테고리의 다른 글

React Server Components와 CVE-2025-55182 / 66478 RCE  (0) 2025.12.06
[React] useMemo, useEffect 에러 (인 줄 알았던 휴먼에러)  (0) 2025.03.23
React 번들링  (1) 2024.12.01
React의 특징  (2) 2024.11.17
반응형

번들링이란?

여러 제품이나 코드, 프로그램을 묶어서 패키지로 제공하는 행위, 웹 애플리케이션을 제공하기 위한 파일 묶음

 

번들링에는 다양한 방법이 있습니다. 대표적으로 Webpack, Vite 등이 있죠

Webpack

Webpack 이란 여러 개의 파일을 하나의 파일로 합쳐주는 모듈 번들러

모듈 번들러

  • HTML, CSS, JS 등의 자원을 전부 각각의 모듈로 보고 이를 조합해 하나의 묶음으로 번들링하는 도구
  • 변수들의 스코프 문제 해결
  • 각 자원을 호출할 떄 생겨나는 네트워크 쪽의 코스트도 신경써야 하기에 등장

등장 배경

  • 웹 앱의 빠른 로딩 속도와 높은 성능을 위해서 필요한 파일들을 묶어 제공
  • 두개의 다른 js 파일에서 같은 변수를 사용할 경우 충돌

빌드와 번들링

  1. 빌드
    • 개발이 완료된 앱을 배포하기 위해 하나의 폴더로 구성하여 준비하는 작업
  2. 번들링
    • 파일을 묶는 작업, 모듈간의 의존성 관계를 파악해 그룹화하는 작업

Webpack 핵심개념

module.exports = {
  target: ["web", "es5"],
  entry: "./src/script.js",
  output: {
    path: path.resolve(__dirname, "docs"),
    filename: "app.bundle.js",
    clean: true
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, "css-loader"],
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "src", "index.html"),
    }),
    new MiniCssExtractPlugin(),
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin(),
    ]
  }
};

 

Target

웹팩은 다양한 환경과 target을 컴파일한다.

  • target의 기본값은 web
  • esX 를 넣으면 지정된 ECMAScript 버전으로 컴파일

Entry

개발자가 작성한 코드의 시작점

  • 리액트의 경우 index.js 에서 HTML 엘리먼트 하나에 리액트 코드를 적용하는것 부터 시작
  • Entry 속성은 Entry point 라고 한다.
    • Webpack 은 Entry point 를 기반으로 직간접적 의존하는 다른 모듈과 라이브러리를 찾아낼 수 있음

Output

생성된 번들을 내보낼 위치와 이 파일의 이름을 지정하는 방법을 웹팩에 알려주는 역할

Loaders

loader를 사용하면 웹팩이 다른 유형의 파일을 처리하거나, 유효한 모듈로 변환해 애플리케이션에 사용하거나 디펜던시 그래프에 추가할 수 있다.

Plugins

번들을 최적화하거나 애셋을 관리하고, 또는 환경변수 주입 등 광범위한 작업을 수행한다.

  • require 을 통해 플러그인 요청

Mode

Browser Compatibility

 

Vite

빠르고 만능, Esbuild와 Rollup의 장점을 합쳤다.

  • ES 모듈 시스템을 사용하여 필요한 모듈만 로드하고, 핫모듈 리플레이스먼트 (HMR) 성능이 뛰어나 빠른 개발 서버 속도를 자랑

특징

  • 빠른 개발 서버 : 모듈을 ESM 형식으로 제공해, 필요한 모듈만 즉시 로드
  • HMR : 코드 변경 사항을 즉시 반영하여 브라우저 새로고침 없이도 UI 업데이트 가능
  • 빠른 번들링 : Esbuild를 사용해 번들링 속도 향상

흔히 리액트 프로젝트를 만드는데 create-react-app 혹은 vite 로 생성하게 되는데 이 둘의 차이가 극명하다.

CRA vs Vite

항목 Create React App (CRA) Vite
번들링 도구 Webpack ESBuild 또는 Rollup
빌드 속도 상대적으로 느림 매우 빠름 (ESBuild 기반)
개발 서버 성능 느린 초기 빌드와 Hot Module Replacement(HMR) 속도 빠른 초기 빌드와 즉각적인 HMR
설치 및 구성 자동화된 설정, 시작하기 쉬움 간단한 설정, 플러그인 기반으로 높은 확장성 제공
출력 번들 크기 기본적으로 최적화가 부족할 수 있음 작은 번들 크기, Tree Shaking 및 코드 분할 기본 제공
플러그인 지원 제한적 (Webpack 플러그인에 의존) 풍부한 플러그인 생태계
ESM 지원 제한적 (CommonJS 중심) 기본적으로 ES Module 지원
구성 유연성 제한적 (eject를 해야 커스텀 가능) 유연한 설정 파일 (vite.config.js)로 커스텀 가능
로드 시간 번들 파일 크기에 따라 느릴 수 있음 ESBuild 기반으로 빠른 로드 시간
SSR(서버 사이드 렌더링) 직접 지원하지 않음 내장된 SSR 지원
사용 사례 기존 React 프로젝트에서 간편한 시작을 원할 때 빠른 개발 환경과 최적화된 번들링이 필요한 프로젝트
커뮤니티 더 많은 사용 사례와 기존 자료 빠르게 성장하는 커뮤니티
호환성 오래된 브라우저 및 라이브러리와 높은 호환성 최신 브라우저 중심, 구형 브라우저와의 호환성은 Polyfill 필요

 

결론

CRA는 설정 없이 바로 사용할 수 있으며, React의 공식 지원 도구이지만, 대규모 프로젝트에서는 빌드 속도가 느려질 수 있고, 설정을 변경하려면 eject 명령이 필요하는 단점이 있고,

 

Vite는 매우 빠른 개발 서버와 빌드 성능을 제공하며, 설정 파일을 통해 유연하게 설정을 변경할 수 있고, 다양한 모던 프레임워크를 지원하는 동시에 빠르게 성장하는 도구다.

 

둘 중의 프로젝트에 맞는 번들링 방식을 적용하면 된다.

반응형

+ Recent posts