Vite를 사용해야 하는 이유
기존 모듈 번들러 문제점
-
브라우저에서 Native ESM 방식을 지원하기 전까지는 Javascript 모듈화를 브라우저 레벨에서 진행할 수 없었고, 해당 소스 모듈을 브라우저에서 지원하기 위해서 require/IIFE/import,expor를 통한 모듈화 문법을 이용하여서 여러개의 파일로 합쳐주거나 의미 있는 단위로 묶어주는 기능을 번들링이라고 하며, 현재는 Webpack, Rollup 그리고 Parcel을 도구들이 지원하고 있습니다.
-
하지만 애플리케이션이 점점 더 발전함에 따라서 JS 도구들의 성능 병목 현상이 발생, HMR 사용하더라도 변경된 파일 적용 시 수초가 걸려서 개발자 생산성을 떨어뜨는 문제가 발생하고 있습니다.
-
ESM(ECMAScript Modules)
- ESM은 모듈화 문법인 import, export를 별도의 도구 없이 브라우저 자체에서 소화해 낼 수 있는 모듈 방식을 의미한다. 만약 아래와 같은 코드를 웹팩과 같은 번들러 없이 브라우저에서 실행하면 에러가 발생합니다.
// app.js import { sum } from 'test.js' console.log(sum(1,2)); <script src="app.js></script>
<script type="module" src="app.mjs></script>
Vite 특징
-
-
Dependencies: node_modulesd와 같이 내용이 바뀌지 않는 소스코드에 대해서 esbuild 이용한 사전 번들링 기능 제공
-
esbuild는 webpack, parcel과 같은 기존의 번들러 대비 10-100배 빠른 속도를 제공
-
esbuild 로 node_modules 의 모든 패키지를 사전 번들링하여 아래와 같이 serving 하고 캐시
// Dependencies package import 할 경우 import dayjs from 'dayjs'; // vite esm 지원을 위한 변환/캐싱 /node_modules/.vite/deps/dayjs.js?v=b09621d8
-
-
Source code: Native ESM 방식을 적용해서 브라우저가 모듈을 직접 가져오고 변환 및 제공하도록 처리
-
-
HMR 성능 개선 기존 번들러 기반에서는 소스 코드 변경 시 다시 번들링 과정을 다시 수행하다보니 성능이 느려지는 이슈를 Native ESM 방식을 사용하여 변경된 모듈만 교체해서 성능 개선 HTTP 헤더를 활용하여 페이지 로드 속도 개선(요청 횟수 최소화)
- 304 Not Modified: 클라이언트 캐시 사용
- Cache-Control: max-age=31536000, immutalble 이용한 캐시 사용
-
프로덕션 환경 Rollup 사용
- 가장 빠른 성능을 자랑하는 esbuild이지만 아쉬운 생태계와 브라우저용 번들링에서는 안정성이 떨어진다는 평가가 있어서 vite에서는 프로덕션 환경에서 Rollup 번들러를 사용(트리 셰이킹, 지연로딩, 파일 분활 등 성능 이점 제공)
- Rollup은 v4에서 파서를 SWC 전환 → Rust 포팅인 Rolldown 만드는 작업을 진행 중이며 개발이 완료된다면 esbuild를 모두 대체 가능(개발/빌드 사이에 불이치 제거 목표)
CRA to Vite Migration
Setting the Stage with Vite Installation
npm install vite @vitejs/plugin-react --save-dev
npm uninstall react-scripts
Updating package.json for Vite Commands
"scripts": {
"start": "vite",
"build": "vite build",
"serve": "vite preview"
},
Renaming File Extensions to .jsx or .tsx
mv src/App.js src/App.jsx
mv src/index.js src/index.jsx
Crafting the Vite Configuration
// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig(() => {
return {
build: {
outDir: 'build',
},
plugins: [react()],
};
});
Move the index.html File
mv public/index.html .
Rehousing the index.html File
- Remove %PUBLIC_URL%
<script type="module" src="/src/index.jsx"></script> -
<link rel="icon" type="image/svg+xml" href="%PUBLIC_URL%/favicon.svg" /> +
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />;
Add module script to the bottom of the body tag
Vite treats index.html as source code and part of the module graph
<body>
{/* others here */}
<script type="module" src="/src/index.tsx"></script>
</body>
Update tsconfig.json
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"target": "ESNext",
"types": ["vite/client"],
"isolatedModules": true,
},
}
Update process.env.REACT_APP(optional)
-process.env.REACT_APP_VARIABLE + import.meta.env.REACT_APP_VARIABLE;
Replace REACT* with VITE* (optional)
-REACT_APP_API_BASE + VITE_APP_API_BASE;
Html Minify
https://www.npmjs.com/package/vite-plugin-minify
// vite.config.js
import { defineConfig } from 'vite';
import { ViteMinifyPlugin } from 'vite-plugin-minify';
export default defineConfig({
plugins: [
// input https://www.npmjs.com/package/html-minifier-terser options
ViteMinifyPlugin({}),
],
});
결과
빌드 성능: 6.16s → 2.49s ( 3.67s 빠름 )
Dev Server 구동: 167ms → 엄청 빠름^^