Vite는 어떻게 빌드되는가?

sham·2025년 1월 5일
1

개요

처음 개발을 시작할 때, 개발 강의를 찾아보면 거의 대부분 CRA를 사용해서 프로젝트 환경을 세팅하는 것이 대부분이었다. 그러나 오늘날에는 CRA 대신 Vite를 사용하는 것을 어렵지 않게 찾아볼 수 있다. Vite는 대체 무엇일까?

Vite 공식 문서 왈

공식 문서에서는 이렇게 이야기하는데, 좀 더 자세히 알아보도록 하자.

Vite를 사용해야 하는 이유

탄생 배경

  • 기존에는 브라우저가 ES Modules(ESM)을 지원하기 전에는 모든 파일을 번들링해야 했음.
  • 번들링 도구(Webpack, Rollup, Parcel 등)는 파일 크롤링과 처리에 시간이 많이 소요됨.
  • 대규모 프로젝트에서는 파일 갱신과 HMR(Hot Module Replacement)이 느려져 개발 속도가 저하됨.

Vite 작동 방식

  • 소스 코드를 두 가지 카테고리로 구분
    • Dependencies: 변하지 않는 일반 JavaScript 모듈은 Esbuild로 사전 번들링. (기존 도구보다 10~100배 빠름)
    • Source Code: Native ESM를 이용해 브라우저가 요청하는 모듈만 변환 및 제공.
  • HTTP 요청 기반으로 필요한 모듈만 로드.
  • HMR(Hot Module Replacement)
    • 수정된 모듈만 교체하여 빠르게 반영.
    • 브라우저와 네이티브 ESM을 통해 빠른 갱신 속도 제공.
  • 캐싱 활용
    • 디펜던시는 장기 캐싱(immutable) 설정.
    • 변경되지 않은 소스는 304 Not Modified로 요청 최소화.

프로덕션 빌드

  • 번들링 필요성
    • ESM을 직접 사용하는 것은 네트워크 요청 증가로 인해 비효율적.
    • 프로덕션에서는 Rollup을 통해 Tree Shaking, 코드 스플리팅 등으로 최적화된 번들 생성.
  • Rollup 채택
    • 플러그인 생태계와 유연성 때문에 Rollup을 사용.
    • 미래에는 Rust 기반 Rolldown으로 성능을 더 개선할 계획.

용어 정리

ESM (ES Modules)

  • JavaScript의 공식적인 모듈 시스템.
  • exportimport 키워드를 사용해 모듈 형태로 파일 간의 코드를 사용할 수 있게 한다.
  • ES6(ECMAScript 2015)에서 도입되어 JavaScript 표준으로 인정.

Native ESM

  • 브라우저나 Node.js가 ESM을 네이티브(기본적으로) 지원하는 환경을 의미한다.
    • 별도의 번들링 도구 없이 ESM을 직접 실행할 수 있다는 뜻.
  • 브라우저의 경우 <script type="module"> 태그를 통해 ESM을 사용할 수 있다.
<script type="module">
  import { add } from './math.js';
  console.log(add(1, 2));
</script>
  • Node.js의 경우 .mjs 확장자를 사용하거나 package.json"type": "module”을 설정하는 것으로 사용할 수 있다.
  • 단, 배포(production) 환경에서는 여전히 번들링(파일 통합)이 필요하다.

Bundling (번들링)

  • 웹사이트에서 JS 파일을 요청한다고 생각해보자. 여러 개의 파일을 하나하나 요청하는 것보다 하나의 파일만을 요청하는 것이 훨씬 비용적으로 유리할 것이다.
  • 번들링은 여러 개의 JavaScript 파일(모듈)을 하나의 파일로 병합하는 과정으로, 브라우저가 JS 파일을 효율적으로 로드할 수 있도록 최적화된다.
  • 몇몇 번들러의 경우 트랜스파일러 역할도 수행한다. Vite가 대표적인 예
  • Webpack, Rollup, Parcel, Vite 등이 존재한다.

번들링 과정을 이해해보자

Transpile (트랜스파일)

  • 코드의 언어 또는 문법을 다른 형태로 변환하는 과정.
  • 모던 웹 어플리케이션은 HTML, CSS, JavaScript만을 사용해서 개발하기엔 너무나 복잡해져 버렸기에, 이를 보완하고자 다양한 슈퍼셋(Superset, 기존 집합을 포함하는 더 큰 집합)이 등장함.
    • 이들을 기존 생태계에서 사용하기 위해 트랜스파일이 등장.
    • 대표적인 트랜스파일 예시
      • TypeScript → JavaScript
      • SASS → CSS
      • ES2021 JavaScript → ES2014 JavaScript
      • JSX → JavaScript
  • 코드의 문법 수준을 변환하여 브라우저 호환성을 높이거나 최신 기능을 사용할 수 있게 함이 목적.
  • Babel, TypeScript Compiler(TSC), SWC 등이 대표적인 트랜스파일러.
  • 언어 및 문법 변환에 초점을 맞추며, 번들링과 달리 파일 병합이나 최적화 작업은 하지 않음.
  • Polyfill과는 런타임 이전에 변환 작업을 수행

Polyfill (폴리필)

  • 특정 기능이 지원되지 않는 환경(주로 구형 브라우저)에서 해당 기능을 대체 구현하거나 에뮬레이션하는 코드.
  • Promisefetch API와 같이 최신 JavaScript 기능을 지원하지 않는 브라우저에서 이 기능들을 사용할 수 있게 해준다.
    • 브라우저가 새로운 기능을 호출할 때 폴리필이 동작하여 대체 기능을 제공
    • 코드 변경 없이 구형 환경에서도 최신 기능을 사용할 수 있도록 보완하며 브라우저 호환성 보장
  • 트랜스파일링과 달리, 폴리필은 런타임에 동작
  • 번들링과는 관련이 없으며, 주로 브라우저의 API나 메서드 부족을 보완하는 역할

번들링, 트랜스파일, 폴리필

키워드목적수행 시점주요 역할대표 도구
Bundling여러 파일 병합 및 최적화빌드(개발/배포 전)파일 병합, 트리 셰이킹, 압축Webpack, Vite, Parcel
Transpile언어 또는 문법 변환빌드(개발/배포 전)코드 변환 (ES6→ES5 등)Babel, TSC, SWC
Polyfill브라우저에서 새로운 기능 대체 구현런타임(실행 중)환경이 지원하지 않는 기능 보완core-js, polyfill.io

Esbuild

  • JavaScript와 TypeScript 코드를 초고속으로 번들링하고 트랜스파일러하는 도구.
  • Go 언어로 작성되어 기존 번들러 대비 10~100배 빠른 성능을 제공.
  • CPU 멀티코어와 효율적인 메모리 사용으로 매우 빠르게 작동하며, ESM을 지원하다.
  • 별도의 플러그인 없이도 TypeScript와 React JSX를 처리할 수 있다.

Rollup

  • JavaScript 번들링 도구로, 주로 라이브러리와 같은 재사용 가능한 코드를 번들링하는 데 최적화.
  • ES Modules(ESM)을 중심으로 설계되었으며, 트리 셰이킹(Tree Shaking)을 통해 사용되지 않는 코드를 제거.

본문

vite 빌드 과정

Vite는 개발 서버프로덕션 빌드에서 서로 다른 전략을 사용한다.

  • 개발 서버
    • 번들링 없이 Native ESM을 사용해 브라우저 요청에 따라 파일을 실시간으로 변환하고 제공한다.
    • 의존성 파일은 Esbuild로 사전 번들링하여 캐싱된 상태로 제공한다.
    • 파일 변경 시 HMR을 통해 필요한 파일만 다시 로드한다.
  • 배포 서버
    • Vite는 Rollup을 사용하여 최적화된 번들링을 수행한다.
      • 트리 셰이킹(Tree Shaking): 사용되지 않는 코드를 제거.
      • 코드 스플리팅(Code Splitting): 큰 파일을 작은 청크로 나누어 로드 성능 최적화.
      • CSS 및 이미지 최적화: CSS를 하나로 합치고, 이미지 파일을 압축.
    • 번들된 결과물을 최적화하여 dist 디렉토리에 생성한다.

run dev - vite

1. Vite 설정 파일 로드

  • Vite는 프로젝트 루트에 있는 vite.config.js 또는 vite.config.ts 파일을 읽는다.
    • 이 파일에는 개발 서버 설정, 플러그인, 빌드 옵션 등이 정의되어 있다.
    • 설정 파일이 없으면 기본값으로 동작한다.

2. 의존성 분석 및 사전 번들링

  • Vite는 프로젝트의 node_modules에서 외부 의존성을 분석한다.
    • 예: React, Vue, Lodash 등.
  • 의존성 파일은 대부분 변화가 없기 때문에 Esbuild를 사용해 사전 번들링을 수행.
    • Esbuild는 매우 빠르게 번들링을 처리하고, 결과를 캐싱해 개발 서버를 시작할 때 재사용.

3. 개발 서버 실행

  • 개발 서버가 실행되고 브라우저가 연결할 수 있도록 로컬 서버가 열린다.
    • 기본적으로 http://localhost:5173에서 실행.
    • vite.config.js에서 server.port를 설정하면 포트를 변경할 수 있다.

4. Native ESM 방식으로 파일 제공

  • 브라우저가 요청을 보내면, Vite는 Native ESM 방식으로 동작.
    • 브라우저는 ESM을 기반으로 동적으로 필요한 모듈을 요청.
    • 예: import { useState } from 'react';와 같은 코드는 React 모듈을 브라우저가 직접 가져온다.
  • 브라우저 요청 처리 과정
    • 브라우저가 JavaScript 파일(예: main.tsx)을 요청.
    • Vite는 해당 파일을 읽고, 필요하다면 컴파일(JSX → JS, TS → JS 등)을 진행.
    • 결과를 브라우저에 반환.

5. HMR(Hot Module Replacement) 활성화

  • Vite는 HMR(Hot Module Replacement)을 통해 코드 변경 사항을 실시간으로 반영.
    • 소스 파일이 변경되면, 변경된 모듈만 브라우저에 다시 전송.
    • 전체 페이지를 새로고침하지 않고도 업데이트 내용을 즉시 확인 가능.
  • HMR 작동 방식
    • 코드가 수정되면 Vite는 해당 파일과 의존성을 감지.
    • 브라우저에 이 파일이 변경됨을 알리고 변경된 모듈만 갱신.
    • UI가 즉시 업데이트.

6. Static Assets 처리

  • CSS, 이미지, JSON 등 정적 파일 요청도 처리.
    • CSS는 <style> 태그로 주입하거나 브라우저에 직접 전달.
    • 이미지와 같은 파일은 브라우저에서 로드 가능하도록 URL로 변환하여 제공.

7. 브라우저 연결 및 초기 로드

  • 브라우저가 초기 페이지를 요청하면, Vite는 엔트리 파일(예: index.html)을 전달.
    • index.html 파일 내 스크립트 태그에서 type="module"을 통해 JavaScript 모듈을 로드.
    • 브라우저가 필요에 따라 모듈을 동적으로 요청.

8. 브라우저 캐싱 활용

  • Vite는 HTTP 캐싱을 활용해 자주 변경되지 않는 파일(의존성 파일 등)을 효율적으로 관리.
    • 예: Cache-Control: max-age=31536000, immutable 헤더를 설정해 브라우저가 의존성 파일을 캐싱.
    • 변경된 소스 코드만 새로 전송.

run build - tsc && vite build

tsc - typescript 컴파일러

  • TypeScript 파일을 JavaScript 파일로 변환하는 작업을 수행.
  • dist/ 폴더 안에 ts 파일이 js 파일로 변환.
    • tsconfig.jsonoutDir 설정에 따라 출력 경로 수정 가능
  • tsconfig.json에서 설정한 target 옵션에 따라 ES5, ES6 등 특정 JavaScript 버전으로 변환.

vite build - 배포용 정적 파일

  • Vite의 프로덕션 빌드를 실행하며, 최적화된 정적 파일을 생성

1. 번들링된 JavaScript 파일

  • 프로젝트의 여러 JavaScript 파일을 하나 또는 여러 개의 번들 파일로 결합.
    • 예: dist/assets/index-abc123.js.
  • 결과물은 최적화된 상태로, 사용되지 않는 코드(Dead Code)는 제거되고, 필요한 부분만 남는다. (트리 셰이킹)

2. CSS 파일 병합 및 최적화

  • 모든 CSS 파일이 하나로 병합되고, 중복된 스타일을 제거.
    • 예: dist/assets/style-xyz456.css.

3. 코드 압축

  • JavaScript와 CSS 코드가 축소(minified).
    • 공백, 주석, 불필요한 코드가 제거되어 파일 크기가 작아진다.
    • 결과 파일명: index-abc123.min.js.

4. 정적 파일 복사

  • public 폴더에 있는 정적 파일(이미지, 폰트, 아이콘 등)이 그대로 복사되어 빌드 디렉토리에 포함.
    • 예: public/logo.pngdist/logo.png.

5. HTML 파일 최적화

  • index.html 파일이 번들 파일을 참조하도록 수정되고, 최적화.
    • 예: <script type="module" src="/src/main.ts"><script src="/assets/index-abc123.js">.

6. 결과물 저장

  • 모든 빌드 결과물은 dist/ 폴더에 저장

레퍼런스

JavaScript 번들러의 이해 — (3) 번들러 개론

JavaScript 번들러의 이해 — (4) Webpack 및 다른 번들러들

profile
씨앗 개발자

0개의 댓글