장난감 연구소

[React] CRA → Vite 마이그레이션 과정 정리 본문

개발/React

[React] CRA → Vite 마이그레이션 과정 정리

changi1122 2025. 5. 23. 14:58

    이번 글에서는 기존에 CRA(Create React App)를 사용하던 리액트 프로젝트를 Vite로 마이그레이션하면서 진행한 작업들을 개인적으로 정리해보았습니다.

    타입스크립트 관련 설정 등 제가 사용하지 않은 내용은 포함되어 있지 않으니, 해당 주제가 필요하신 분은 다른 참고 자료를 함께 보시는 것을 추천드립니다.

     

    Create React App is deprecated

    한동안 백엔드 관련 기술에 집중하느라 프론트엔드에 소홀했었는데, 어느새 Create React App(CRA)이 공식적으로 Depreceted 되었다. CRA는 리액트 빌드 도구로, 2025년 2월 14일부터 더 이상 권장되지 않는다.

    그 이유로는, Webpack 기반의 빌드 속도가 느리고, 라우팅/코드 스플리팅처럼 앱 개발에 필수적인 기능이 기본 제공되지 않았기 때문이다. 현재 유지보수자가 없고, 호환성을 위한 최소한의 업데이트만 제공된다.

    React 팀은 기존 CRA 앱들을 Next.js, React Rounter, Expo 같은 프레임워크나 Vite, Parcel, RSBuild같은 빌드 도구로 마이그레이션을 권장하고 있다. 개인적으로 찾아본 결과, 빠른 개발과 소규모의 프로젝트에는 Vite가, 서버 사이드 렌더링이나 정적 사이트 생성이 필요한 대규모 프로젝트에는 Next.js를 사용하는 게 적합해 보인다.

     

    마이그레이션 과정

     

    Migrate to Vite from Create React App (CRA)

    How to migrate to Vite from Create React App (CRA) with environment variables, testing, SVG, ESLint, TypeScript ...

    www.robinwieruch.de

    마이그레이션 과정은 react.dev 블로그에 링크되어 있는 위 글을 많이 참고하였다.

     

    CRA 전용 의존성 제거 및 Vite 설치

    react-scripts (CRA 빌드 도구), @craco/craco (CRA 설정 커스터마이징 도구) 제거 및

    Webpack과 craco에서 사용하는 webpack.config.js , craco.config.js 파일 삭제

    npm uninstall react-scripts @craco/craco
    rm webpack.config.js craco.config.js

    vite @vitejs/plugin-react 설치

    npm install vite @vitejs/plugin-react --save-dev

    package.json 스크립트 수정

    react-scripts를 vite 관련 스크립트로 변경한다.

      "scripts": {
        "start": "vite",
        "build": "vite build",
        "serve": "vite preview",
      },

    js 확장자를 jsx로 변경

    Vite에서는 JSX 문법을 사용하는 파일의 확장자는 반드시 .jsx 여야 한다. 따라서 JSX 파일 중 확장자가 .js인 파일은 모두 확장자를 .jsx로 변경한다. 타입스크립트를 사용하는 파일도 .tsx로 변경한다.

    vite.config.js 파일 생성

    vite.config.js 파일을 최상단 디렉터리에 생성한다.

    import { defineConfig } from 'vite';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig(() => {
      return {
        build: {
          outDir: 'build',
        },
        plugins: [react()],
      };
    });

    index.html 위치 변경 및 수정

    index.html 파일을 public 디렉터리에서 최상단 디렉터리로 이동한다.

    mv public/index.html .

    해당 파일 내 %PUBLIC_URL% 을 제거한다. 또한 root.render()가 들어있는 파일인 index.jsx 아래와 같이 연결한다.

    <body>
      <div id="root"></div>
      <script type="module" src="/src/index.jsx"></script>
    </body>

    .env 환경변수 수정

    Vite에서 .env 파일에 환경변수를 정의할 때는 VITE_ 라는 접두사를 붙여야 한다. 이 접두사가 붙은 환경변수만 브라우저 코드에서 접근할 수 있다.

    또한 코드에서 환경변수 사용할 때 process.env.XXX 방식으로 사용하고 있었다면 import.meta.env.XXX 형식으로 바꿔야 한다.

    const requestURL = `${import.meta.env.REACT_APP_API_URL}/api/community/${postId}`;
    -> const requestURL = `${import.meta.env.VITE_API_URL}/api/community/${postId}`;

    setupProxy.js 코드 변경

    CRA에선 아래와 같이 setupProxy.js 파일을 통해 /api 로 시작하는 요청을 다른 포트로 전달하고 있었다.

    // 삭제
    const {createProxyMiddleware} = require('http-proxy-middleware')
    
    /* 개발환경에서 4001포트로 proxy하기 위한 코드, 배포시엔 nginx가 proxy해야 함 */
    module.exports = app => {
        app.use('/api',
            createProxyMiddleware(
                {
                    target: 'http://localhost:4001',
                    changeOrigin: true,
                }
            )
        )
    }

    Vite에선 아래와 같이 vite.config.js 파일에 proxy와 관련된 설정을 해야 한다.

    import { defineConfig, loadEnv } from 'vite';
    import react from '@vitejs/plugin-react';
    
    export default defineConfig(({ mode }) => {
      // 환경 변수 로드
      const env = loadEnv(mode, process.cwd());
    
      return {
        build: {
          outDir: 'build',
        },
        plugins: [react()],
          server: {
            proxy: {
                '/api': {
                    target: env.VITE_API_URL,
                    changeOrigin: true,
                }
            }
        },
        assetsInclude: ['**/*.md']
      };
    });

    추가로, vite.config.js 파일에서 환경 변수를 사용하기 위해서는 loadEnv() 메서드를 사용해야 했다.

    require() → import로 바꾸기

    Vite는 ESM(ECMAScript Modules) 기반의 번들러로, CommonJS 방식의 require() 방식으로 import를 지원하지 않는다. require()를 사용하여 import하는 코드가 있었기에 require is not defined 오류가 발생하였다.

    특별한 설정을 하면 CommonJS 방식을 사용할 수 있는 걸로 보이지만, 아래와 같이 import로 바꾸는 것이 권장된다.

    // ❌ 이렇게 하면 오류 발생
    const tailwindcss = require('tailwindcss');
    
    // ✅ ESM 방식으로 수정
    import tailwindcss from 'tailwindcss';

     

    결과

      전 (CRA) 후 (Vite)
    빌드 소요시간 (초) 12.0345 4.2732

    주된 개선점으로 Vite 마이그레이션 결과, 빌드 소요시간이 약 12.0초에서 약 4초로 줄어들어 매우 빨라졌다.

     

    • 관련 PR 및 커밋 내용 보기

    https://github.com/changi1122/TUX-website-front/pull/1