홍승아블로그

vite

Vite를 사용해야 하는 이유

기존 모듈 번들러 문제점

  • 브라우저에서 Native ESM 방식을 지원하기 전까지는 Javascript 모듈화를 브라우저 레벨에서 진행할 수 없었고, 해당 소스 모듈을 브라우저에서 지원하기 위해서 require/IIFE/import,expor를 통한 모듈화 문법을 이용하여서 여러개의 파일로 합쳐주거나 의미 있는 단위로 묶어주는 기능을 번들링이라고 하며, 현재는 WebpackRollup 그리고 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>

    Untitled 예전에는 브라우저가 import와 export를 해석할 수 있는 능력이 없었지만 이제는 다음과 같이 속성을 추가하면 브라우저에서 import와 export를 소화할 수 있게 되었습니다.

    <script type="module" src="app.mjs></script>

Vite 특징

  • 콜드 스타트 방식의 개발 서버 구동에 대한 성능 개선 Untitled

    • 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 방식을 적용해서 브라우저가 모듈을 직접 가져오고 변환 및 제공하도록 처리 Untitled

  • 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 빠름 )

Untitled

Untitled

Dev Server 구동: 167ms → 엄청 빠름^^

Untitled

참고페이지

이전글
개발 생산성 & 빌드 성능 개선
다음글
esbuild