이 글에서는 Create React App (CRA) 를 Vite로 마이그레이션하는 과정들을 정리하였습니다. 동일한 프로세스를 겪고 있는 다른 분들에게 도움이 되기를 바랍니다. 이 글은 https://cathalmacdonnacha.com/migrating-from-create-react-app-cra-to-vite 를 한글로 번역하여 작성하였습니다.
마이그레이션을 한 이유
저는 CRA를 정말 좋아한다는 말로 글을 시작하고 싶습니다. CRA는 많은 프로젝트(개인 및 전문)를 신속하게 세팅하고 유지보수하는 데 도움이 되었습니다. 그러나 궁극적으로 Vite로 전환하기로 결정한 몇 가지 이유는 다음과 같습니다.
- 전담 관리자가 없습니다.
- 출시가 느립니다. 이것은 React와 Webpack에 더 많은 기능이 추가됨에 따라 더 많은 문제를 야기할 뿐입니다.
- 빌드 도구인지 여부에 관계없이 보안 팀이 수정해야 하는 github 종속 봇 경고를 유발하는 취약점이 증가하고 있습니다.
- 속도입니다. 개발 서버를 거의 다시 시작하지 않고 CI 파이프라인이 프로덕션 빌드를 처리하므로 이것은 실제로 심각한 문제가 되지는 않습니다. 앱이 매우 작은 경우에는 큰 문제가 아닐 수도 있지만, 크고 복잡한 앱을 개발하는 사람들에게는 매우 큰 문제일 수 있습니다. 이 이유만으로는 마이그레이션하지 않을 것이지만 속도 향상이 상당히 인상적이라는 점을 인정해야 합니다.
- 2년 전 제가 CRA 기반 앱을 처음 만들 때와 비교하면 Vite가 많이 발전했고 커뮤니티가 크게 성장했습니다. 새로운 프로젝트에 대해 두 가지를 다시 평가한다면 이번에는 Vite를 선택하겠습니다.
이 모든 것을 감안할 때 Vite로 전환해야 할 때라고 생각했습니다.
Vite를 사용할 때의 유일한 "단점"은 타입 체크를 하지 않고 Javascript로 변환하기만 한다는 것입니다. 하지만 저는 개인적으로 오늘날 많은 IDE가 훌륭하게 Typescript 지원을 하고 있기 때문에 괜찮다고 생각합니다.
마이그레이션 과정
다음은 CRA에서 Vite로 마이그레이션하기 위해 취한 모든 단계입니다. 대부분의 단계가 Javascript 프로젝트와 유사해야 하지만 Typescript 프로젝트를 마이그레이션한다는 점은 주목할 가치가 있습니다.
시작해보겠습니다!
1. 디펜던시 설치
다음 4가지 디펜던시를 설치합니다.
- Vite
- @vitejs/plugin-react
- vite-tsconfig-paths
- vite-plugin-svgr
npm install --save-dev vite @vitejs/plugin-react vite-tsconfig-paths vite-plugin-svgr
NOTE
Vite에게 tsconfig 파일에서 절대 경로를 확인하는 방법을 알려주려면 vite-tsconfig-paths가 필요합니다. 이 방법으로 다음과 같은 모듈을 가져올 수 있습니다.
import MyButton from '../../../components' ==> import MyButton from 'components'
SVG를 React 구성 요소로 가져오려면 vite-plugin-svgr이 필요합니다. 예를 들어:
import { ReactComponent as Logo } from './logo.svg'.
2. Vite Config 파일 생성
프로젝트 루트에 vite.config.ts를 만듭니다. 여기에서 모든 Vite 구성 옵션을 지정합니다.
import { defineConfig } 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({
plugins: [react(), viteTsconfigPaths(), svgrPlugin()],
});
3. index.html 파일 이동
index.html 파일을 /public 폴더에서 프로젝트 루트로 이동합니다. 이것은 Vite가 index.html 파일의 위치를 프로젝트 루트로 하기를 권고하고 있기 때문이며, Vite 공식 문서에서 이에 대한 자세한 내용을 확인 할 수 있습니다.
4. index.html 수정
URL은 Vite에서 약간 다르게 취급되므로 %PUBLIC_URL%의 모든 참조를 제거해야 합니다. 예를 들면 아래와 같습니다.
// Before
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
// After
<link rel="icon" href="/favicon.ico" />
또한 <body> 요소에 진입점을 추가해야 합니다.
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!-- 엔트리포인트를 추가하세요 👇 -->
<script type="module" src="/src/index.tsx"></script>
5. tsconfig.json 수정
tsconfig.json 파일에서 업데이트해야 하는 주요 사항은 target, lib, types입니다. 아래는 예시입니다.
{
"compilerOptions": {
"target": "ESNext",
"lib": ["dom", "dom.iterable", "esnext"],
"types": ["vite/client", "vite-plugin-svgr/client"],
"allowJs": false,
"skipLibCheck": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noFallthroughCasesInSwitch": true,
"module": "ESNext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react"
},
"include": ["src"]
}
6. vite-env.d.ts 파일 생성
Typescript를 사용하고 있으므로 src 폴더 아래에 다음 내용으로 vite-env.d.ts 파일을 생성해야 합니다.
/// <reference types="vite/client" />
7. react-scripts 제거
CRA와 작별을 고할 때입니다. 👋 아래 명령을 실행하여 제거합니다.
npm uninstall react-scripts
그리고 react-app-env.d.ts 파일은 삭제합니다.
8. package.json 에서 scripts 수정
react-scripts를 제거했으므로 이제 vite를 참조하도록 package.json 내의 스크립트를 업데이트해야 합니다.
"scripts": {
"start": "vite",
"build": "tsc && vite build",
"serve": "vite preview"
},
9. 시작
npm start 를 실행하면 이제 Vite로 구동되는 브라우저에서 앱이 열리는 것을 볼 수 있을 것입니다.
앱이 작은 경우에는 이 작업만 수행하면 될 것입니다. 만약 앱이 좀더 크고 복잡한 경우라면 아래 추가 설정 사항을 확인해보시기 바랍니다.
추가 설정 사항
다음은 고유한 프로젝트 설정에 따라 수행할 수 있는 몇 가지 추가 선택적 단계입니다.
환경 변수 설정
환경 변수를 마이그레이션하는 것은 매우 간단합니다. .env 파일 내에서 REACT_APP_의 이름을 VITE_로 바꾸기만 하면 됩니다.
그런 다음 process.env.REACT_APP_를 사용하여 변수를 참조하는 대신 import.meta.env.VITE_를 사용합니다.
한 단계 더 나아가 src 폴더에 env.d.ts 파일을 만들어 환경 변수의 유형을 지정할 수도 있습니다. 예를 들면 아래와 같습니다.
interface ImportMetaEnv {
readonly VITE_TOKEN: string;
readonly VITE_CLIENT_ID: number;
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
노드 환경(예: 개발 또는 프로덕션)을 확인해야 하는 경우 import.meta.env 객체를 사용하여 확인할 수 있습니다.
if (import.meta.env.DEV) {
// do something in development mode only
}
if (import.meta.env.PROD) {
// do something in production mode only
}
빌드 아웃풋 디렉토리 변경
Vite에서 기본 프로덕션 빌드 폴더 이름은 dist이며 필요한 경우 이를 CRA의 기본 build 폴더로 변경할 수 있습니다. 저의 CI/CD 스크립트가 모두 build를 참조해서 이 설정을 하게 되었습니다.
// vite.config.ts
export default defineConfig({
...
build: {
outDir: 'build',
},
});
서버 시작 시 자동으로 앱 열기
CRA에서 마음에 들었던 점은 서버 시작 시 브라우저에서 앱을 자동으로 열 수 있다는 것입니다. Vite에는 다음과 같은 옵션도 있습니다.
// vite.config.ts
export default defineConfig({
...
server: {
open: true,
},
});
포트 변경
기본 3000에서 포트 번호를 변경해야 하는 경우 다음과 같이 지정합니다.
// vite.config.ts
export default defineConfig({
...
server: {
port: 4000,
},
});
벤치마크
다음은 마이그레이션 전후에 기록한 몇 가지 벤치마크입니다.
CRA | Vite | |
npm install | 21 seconds | 9 seconds |
Server startup time (cold) | 11 seconds | 856 milliseconds |
Tests run | 17 seconds | 14 seconds |
Production build | 45 seconds | 17 seconds |
Production build size | 886 KB / gzip: 249 KB | 656.91 KB / gzip: 195.21 KB |
실제로 서버 시작 시간이 개선된 것을 볼 수 있지만 그 외에는 큰 차이가 없었습니다. 이것은 매우 작은 앱이므로 더 큰 앱의 경우 차이가 훨씬 커질 수 있습니다.
트러블슈팅
다음은 발생할 수 있는 몇 가지 오류입니다.
1. npm start를 실행할 때 다음 오류가 표시됩니다. 오류: Error: Cannot find module 'node:path'.
노드 버전을 14.18.0 또는 v16+로 업데이트했는지 확인해야 합니다. 이하 버전일 경우 에러가 발생할 수 있습니다.
2. npm start를 실행할 때 다음 오류가 표시됩니다. 오류 : No matching export in MODULE_NAME for import TYPE_NAME.
이것은 Vite가 ESM 번들을 예상하는 umd 번들과 함께 라이브러리를 사용할 때 자주 발생합니다. 이것은 okta-auth-js에서 발생했으며 수정 사항은 Vite 구성 파일에서 umd 번들을 로드하도록 Vite config에 구체적으로 설정하는 것입니다.
// vite.config.ts
export default defineConfig({
...
resolve: {
alias: {
'@okta/okta-auth-js': '@okta/okta-auth-js/dist/okta-auth-js.umd.js',
},
},
});
3. npm start를 실행한 후 화면이 비어 있습니다.
3단계와 4단계에 따라 index.html 파일을 이동하고 업데이트했는지 확인합니다.
마치며
전반적으로 저는 Vite에 매우 만족했습니다. 마이그레이션은 간단했고 개발자 경험이 크게 향상되었습니다. CRA가 할 수 있는 모든 것을 할 수 있지만 더 나은 구현이 가능했습니다.
읽어주셔서 감사합니다.
참고
https://cathalmacdonnacha.com/migrating-from-create-react-app-cra-to-vite