
개요
처음 개발을 시작할 때, 개발 강의를 찾아보면 거의 대부분 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의 공식적인 모듈 시스템.
export
와 import
키워드를 사용해 모듈 형태로 파일 간의 코드를 사용할 수 있게 한다.
- 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 (폴리필)
- 특정 기능이 지원되지 않는 환경(주로 구형 브라우저)에서 해당 기능을 대체 구현하거나 에뮬레이션하는 코드.
Promise
나 fetch
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
에서 외부 의존성을 분석한다.
- 의존성 파일은 대부분 변화가 없기 때문에 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.json
의 outDir
설정에 따라 출력 경로 수정 가능
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.png
→ dist/logo.png
.
5. HTML 파일 최적화
index.html
파일이 번들 파일을 참조하도록 수정되고, 최적화.
- 예:
<script type="module" src="/src/main.ts">
→ <script src="/assets/index-abc123.js">
.
6. 결과물 저장
레퍼런스
JavaScript 번들러의 이해 — (3) 번들러 개론
JavaScript 번들러의 이해 — (4) Webpack 및 다른 번들러들