개발/프론트엔드 (JS & React)

[React] CRA로 생성한 프로젝트 Vite로 마이그레이션하기 (타입스크립트)

jungwon_ 2022. 11. 16. 00:28

앞선 글에서 Vite가 무엇인지, 그리고 왜 Vite로 리액트 프로젝트를 생성하는 것이 나은지에 대해 다뤘다.

 

[React] 리액트 프로젝트 생성 - Create React App 보다 더 빠른 Vite 사용하기

보통 리액트에서 간단한 프로젝트를 생성하기 위해 가장 많이 사용하는 것은 Create React App 즉 CRA다. 그러나 CRA는 단점이 있는데, 바로 속도가 느리다는 것이다. 심지어 프로젝트 크기가 커질 수

jwdevv.tistory.com

오늘은 이미 CRA(Create React App)으로 생성한 리액트 프로젝트를 Vite로 마이그레이션하는 방법에 대해 알아보자.

 

그 외에도 Vite 에서 환경 변수를 설정하고 index.html에서 접근하는 방법, 흔히 발생하는 오류를 해결하는 방법 등도 이 글의 마지막에 추가했다.

 


1. Dependencies 설치

아래 네 가지 dependencies를 설치해준다.

npm i --save-dev vite @vitejs/plugin-react vite-tsconfig-paths vite-plugin-svgr

 

2. index.html 수정

index.htmlpublic 에서 루트 디렉토리로 옮기고 %PUBLIC_URL% 을 모두 제거한다.

<!-- X -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

<!-- O -->
<link rel="manifest" href="/manifest.json" />

그리고 <body> element를 아래와 같이 수정한다.

<body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
    <script type="module" src="/src/index.tsx"></script>
</body>

 

3. tsconfig.json 수정

compilerOptions 에서 target, lib, types를 아래와 같이 수정한다.

{
  "compilerOptions": {
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "types": ["vite/client", "vite-plugin-svgr/client"],
    // ...
  },
  "include": ["src"]
}

 

4. Vite config file 생성 ( + 환경 변수, output 디렉토리 설정)

프로젝트의 루트 디렉토리에 vite.config.ts 파일을 생성하고 아래 코드를 복붙한다.

import { defineConfig, loadEnv } from 'vite';
import react from '@vitejs/plugin-react';
import viteTsconfigPaths from 'vite-tsconfig-paths';
import svgrPlugin from 'vite-plugin-svgr';

// https://vitejs.dev/config/
export default defineConfig(({mode}) => {
  const env = loadEnv(mode, "env");

  const htmlPlugin = () => {
    return {
      name: "html-transform",
      transformIndexHtml(html: string) {
        return html.replace(/%(.*?)%/g, function (match, p1) {
          return env[p1];
        });
      },
    }
  }
  return {
    plugins: [
      htmlPlugin(),
      react(),
      viteTsconfigPaths(),
      svgrPlugin()
    ],
    build: {
      outDir: './build',
      emptyOutDir: true
    }
  }
});

index.html에서 환경 변수 접근하기

Vite는 CRA와 환경 변수를 다르게 취급한다.

 

그래서 기존의 %REACT_APP_VARNAME%와 같은 템플릿을 사용해서 index.html에서 환경 변수에 접근할 수 없다.

 

위 htmlPlugin()은 이런 문제를 해결해주기 위한 방법인데, 구글링 해보니 여러가지 방법이 있었지만 테스트 결과 이 방법이 CRA와 같은 방법으로 %VITE_VARNAME%을 사용할 수 있도록 해주고 가장 간편했다. (출처는 vite 깃허브 issue)

 

JS/TS에서 환경 변수 접근하기

자바스크립트/타입스크립트에서 환경 변수에 접근하는 방법은 process.env 대신 import.meta.env 를 사용한다. (참고)

 

Output 디렉토리 변경

마지막 build 프로퍼티는 vite build가 output 디렉토리의 default 가 dist인 것을 build로 바꿔주기 위함인데, 이는 Netlify 배포 부분에서 더 자세히 설명하겠다.

 

output 디렉토리가 dist여도 상관없다면 이 부분은 스킵해도 좋다.

 

5. 환경 변수 prefix 수정

CRA에서는 환경 변수 prefix로 REACT_APP_ 을 사용했는데, VITE에서는 VITE_ 를 사용한다.

// CRA
REACT_APP_VARNAME=hello

// VITE
VITE_VARNAME=hello

 

환경 변수 prefix를 커스터마이즈하고 싶다면 여기에서 envPrefix 옵션을 참고하자.

 

6. env.d.ts 파일 변경

react-app-env.d.ts 파일은 삭제하고 src 디렉토리에 vite-env.d.ts 파일을 만들어준다.

/// <reference types="vite/client" />

 

7. react-scripts 제거 및 스크립트 업데이트

react-scripts를 제거한다.

npm uninstall react-scripts

 

그리고 package.json에서 아래와 같이 스크립트를 업데이트한다.

"scripts": {
  "start": "vite",
  "build": "tsc && vite build",
  "serve": "vite preview",
  // ...
},

 

이제 npm run start를 시작하면 vite로 dev 서버가 실행되는 것을 확인할 수 있다.


그 외 도움이 될만한 팁

실제 예제를 보고 싶어요

아래 깃허브 저장소의 commit에서 실제 예제 및 파일 구조를 확인할 수 있다.

 

깃허브 저장소

Commit

 

index.html에서 여전히 환경변수가 안불러와져요

src/vite-env.d.ts 파일에 아래와 같이 ImportMetaEnvImportMeta를 추가한다.

/// <reference types="vite/client" />

interface ImportMetaEnv {
  readonly VITE_VARNAME1: string
  readonly VITE_VARNAME1: string
}

interface ImportMeta {
  readonly env: ImportMetaEnv
}

ImportMetaEnv 안에는 index.html에서 불러올 환경 변수와 그 타입을 추가해준다.

 

❗ Netlify를 사용중인데 netlify dev 실행시 서버가 무한 로딩하고 실행이 안돼요

이는 netlify dev가 npm run serve 를 실행하는데, vite preview를 실행하는데서 오류가 발생해서 그렇다.

 

package.json에서 serve를 "vite"로 변경해주자.

"scripts": {
  "start": "vite",
  "build": "tsc && vite build",
  "serve": "vite",
  // ...
},

 

window 혹은 globalThis 객체에 접근하는데 문제가 있어요

나는 Naver Map API를 사용중인데 naver.maps를 불러오는데 문제가 있었다.

 

만약 외부 라이브러리를 모듈 형식으로 import 하는 것이 아니라 index.html의 script에서 불러와 window/globalThis 객체에 저장해서 사용하는 경우에는 아래와 같이 src/types/index.d.ts 파일을 생성해 해결할 수 있다.

export {};

declare global {
  interface Window {
    naver: any; // 사용하고자 하는 프로퍼티의 타입 체킹을 제거한다
  }
}

그러면 더이상 오류가 나지 않는 것을 확인할 수 있다.

console.log(window.naver);

 

Netlify를 사용 중인데 배포시 오류가 나요

Netlify에서 환경 변수를 수정해줘야한다. 

 

Deploys - 해당 프로젝트 - Build & deploy - Environment 에서 REACT_APP_ 으로 시작하는 환경변수를 VITE_ 로 변경해주자.

그리고 Build settings 에서 Publish directory를 프로젝트의 output 디렉토리에 맞게 수정해준다.

 

나는 이 부분은 CRA를 사용할 때와 똑같이 build로 두고 vite의 build 프로퍼티에서 output 디렉토리를 dist에서 build로 수정해줬다. (4. Vite config file 생성 참고)


Reference

- [Blog Post] Migrating from Create React App (CRA) to Vite by Cathal Mac Donnacha

- [Vite Github Issues] Accessing env variables from index.html

- [Blog Post] Property does not exist on type Window in TypeScript by Borislav Hadzhiev