- Authors
- Name
- 들어가며
- Vite 아키텍처 진화: Rollup + esbuild에서 Rolldown으로
- Rolldown 핵심 기술 분석
- Vite 8.0 설치 및 마이그레이션 가이드
- 비교표: 프론트엔드 빌드 도구 대결
- 프레임워크별 설정 예시
- 플러그인 호환성과 마이그레이션 전략
- 성능 최적화 심층 가이드
- 트러블슈팅 가이드
- 운영 시 주의사항
- Rust 기반 빌드 도구 생태계 비교
- 성능 측정 및 모니터링
- 마이그레이션 체크리스트
- 마치며
- 참고 자료

들어가며
Vite 8.0이 esbuild와 Rollup을 Rust 기반 Rolldown 번들러로 통합하여 10~30배 빌드 성능 향상을 달성했다. 프론트엔드 빌드 도구 생태계가 JavaScript에서 Rust/Go 네이티브 도구로 전환되는 결정적 분기점이다. Turbopack, Rspack과 함께 Rust 기반 빌드 도구 삼파전 구도가 형성되며 개발자 생산성 혁명이 가속화되고 있다.
이 글에서는 Vite 8.0의 아키텍처 변화, Rolldown의 핵심 기술, 실전 마이그레이션, 그리고 경쟁 도구들과의 비교를 깊이 있게 다룬다.
Vite 아키텍처 진화: Rollup + esbuild에서 Rolldown으로
기존 Vite 아키텍처의 이중 엔진 문제
Vite 7.x까지의 아키텍처는 두 개의 서로 다른 엔진에 의존했다.
Vite 7.x 아키텍처:
개발 서버 (Dev) 프로덕션 빌드 (Build)
+------------------+ +------------------+
| esbuild (Go) | | Rollup (JS) |
| - 의존성 사전 번들링 | | - 번들링 |
| - TypeScript 변환 | | - 트리 셰이킹 |
| - JSX 변환 | | - 코드 분할 |
+------------------+ +------------------+
| |
v v
네이티브 ESM 제공 최적화된 번들 출력
이 구조에는 근본적인 문제가 있었다.
- 개발/프로덕션 불일치: esbuild와 Rollup의 동작 차이로 인해, 개발 환경에서 문제없던 코드가 프로덕션 빌드에서 깨지는 경우 발생
- 플러그인 이중 유지: esbuild 플러그인과 Rollup 플러그인을 별도로 관리해야 함
- 프로덕션 빌드 속도 한계: Rollup이 JavaScript로 작성되어 있어 대규모 프로젝트에서 빌드 시간이 분 단위
Vite 8.0의 통합 엔진: Rolldown
Evan You가 이끄는 VoidZero 팀은 이 문제를 근본적으로 해결하기 위해 Rolldown을 개발했다. Rolldown은 Rollup의 API를 Rust로 재구현한 번들러로, Vite 8.0의 유일한 번들링 엔진이 된다.
Vite 8.0 아키텍처:
개발 서버 (Dev) + 프로덕션 빌드 (Build)
+----------------------------------+
| Rolldown (Rust) |
| - 의존성 사전 번들링 |
| - TypeScript/JSX 변환 |
| - 번들링 |
| - 트리 셰이킹 |
| - 코드 분할 |
| - 소스맵 생성 |
+----------------------------------+
| |
v v
네이티브 ESM 제공 최적화된 번들 출력
핵심 이점은 다음과 같다.
- 단일 엔진: 개발과 프로덕션이 동일한 엔진을 사용하므로 불일치 제거
- Rust 네이티브 속도: esbuild(Go) 수준의 파싱 속도와 Rollup 수준의 최적화 품질
- Rollup 플러그인 호환: 기존 Rollup 플러그인의 대부분을 그대로 사용 가능
Rolldown 핵심 기술 분석
Rust 기반 번들링 엔진
Rolldown(GitHub: rolldown/rolldown)은 SWC(Rust 기반 TypeScript/JavaScript 컴파일러)를 파서로 사용하고, 자체 모듈 그래프 구축과 최적화 파이프라인을 구현한다.
Rolldown 내부 파이프라인:
1. 파싱 (SWC)
- TypeScript -> AST
- JSX -> AST
- 병렬 파싱 (Rayon 활용)
2. 모듈 해석 (Module Resolution)
- Node.js 호환 해석 알고리즘
- package.json exports 지원
- 조건부 export 처리
3. 모듈 그래프 구축
- 의존성 그래프 분석
- 순환 의존성 감지
- 사이드 이펙트 분석
4. 최적화
- 트리 셰이킹 (사용되지 않는 export 제거)
- 스코프 호이스팅 (모듈 병합)
- 코드 분할 (동적 import 기반)
- 공통 청크 추출
5. 코드 생성
- 압축 (minification)
- 소스맵 생성
- 에셋 해싱
성능의 비밀: 병렬 처리
Rolldown이 기존 Rollup보다 빠른 핵심 이유는 Rust의 병렬 처리 능력에 있다.
// Rolldown 병렬 파싱 개념 (간략화된 의사 코드)
// 실제 구현은 rolldown/rolldown GitHub에서 확인
use rayon::prelude::*;
use std::path::PathBuf;
struct ModuleInfo {
path: PathBuf,
ast: swc_ecma_ast::Module,
imports: Vec<String>,
exports: Vec<String>,
}
fn parse_modules_parallel(entry_files: Vec<PathBuf>) -> Vec<ModuleInfo> {
// Rayon을 사용한 병렬 파싱
// 각 파일을 독립적으로 파싱하여 CPU 코어를 최대 활용
entry_files
.par_iter()
.map(|file| {
let source = std::fs::read_to_string(file).unwrap();
let ast = swc_parse(&source);
let (imports, exports) = analyze_module(&ast);
ModuleInfo {
path: file.clone(),
ast,
imports,
exports,
}
})
.collect()
}
fn tree_shake_parallel(modules: &mut Vec<ModuleInfo>) {
// 트리 셰이킹도 모듈 단위로 병렬 처리
modules.par_iter_mut().for_each(|module| {
remove_unused_exports(module);
});
}
JavaScript 기반 Rollup은 싱글 스레드로 동작하므로 파일을 순차적으로 처리하지만, Rolldown은 파싱과 트리 셰이킹을 CPU 코어 수만큼 병렬로 실행한다.
Vite 8.0 설치 및 마이그레이션 가이드
새 프로젝트 생성
# Vite 8.0 새 프로젝트 생성
npm create vite@latest my-app -- --template react-ts
# 또는 pnpm 사용 (권장)
pnpm create vite my-app --template react-ts
# 지원 템플릿:
# vanilla, vanilla-ts
# react, react-ts, react-swc, react-swc-ts
# vue, vue-ts
# svelte, svelte-ts
# preact, preact-ts
# lit, lit-ts
# solid, solid-ts
# qwik, qwik-ts
cd my-app
pnpm install
pnpm dev
Vite 7에서 8로 마이그레이션
# 1. Vite 업그레이드
pnpm add -D vite@^8.0.0
# 2. 관련 플러그인 업그레이드
pnpm add -D @vitejs/plugin-react@latest
# 또는 SWC 플러그인
pnpm add -D @vitejs/plugin-react-swc@latest
# 3. 더 이상 필요 없는 패키지 제거
# esbuild는 Rolldown으로 대체되므로 별도 설치 불필요
# (Vite가 내부적으로 관리)
# 4. 호환성 확인
npx vite --version
# vite/8.0.x
vite.config.ts 마이그레이션
// vite.config.ts (Vite 8.0)
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [react()],
// Rolldown 관련 새로운 설정
build: {
// Rolldown이 기본 번들러로 설정됨 (명시 불필요)
// 빌드 타겟 설정
target: 'es2022',
// 코드 분할 전략
rollupOptions: {
output: {
// Rollup API 호환 - 기존 설정 대부분 유지 가능
manualChunks: {
vendor: ['react', 'react-dom'],
router: ['react-router-dom'],
},
},
},
// 새로운 Vite 8 최적화 옵션
cssMinify: 'lightningcss', // Lightning CSS 기본 지원
minify: 'oxc', // OXC 기반 압축 (선택적)
// 소스맵 설정
sourcemap: true,
},
// 개발 서버 설정
server: {
port: 3000,
// HMR이 Rolldown으로 통합됨
hmr: {
overlay: true,
},
},
// 의존성 최적화 (기존 esbuild -> Rolldown으로 자동 전환)
optimizeDeps: {
include: ['react', 'react-dom', 'react-router-dom'],
// esbuildOptions는 더 이상 사용하지 않음
// 대신 rolldownOptions 사용
},
// CSS 설정
css: {
// Lightning CSS가 PostCSS 대안으로 기본 지원
transformer: 'lightningcss',
lightningcss: {
targets: {
chrome: 100,
firefox: 100,
safari: 15,
},
},
},
})
주요 Breaking Changes
// ===== Breaking Change 1: esbuildOptions 제거 =====
// Vite 7 (이전)
// export default defineConfig({
// optimizeDeps: {
// esbuildOptions: {
// target: 'es2020',
// define: { global: 'globalThis' },
// },
// },
// })
// Vite 8 (이후)
export default defineConfig({
optimizeDeps: {
// Rolldown 기반으로 자동 최적화
// 대부분의 esbuildOptions는 더 이상 불필요
},
// 글로벌 정의는 define 옵션 사용
define: {
global: 'globalThis',
},
})
// ===== Breaking Change 2: CSS 처리 변경 =====
// Vite 7: PostCSS가 기본
// Vite 8: Lightning CSS가 기본, PostCSS도 지원
// postcss.config.js가 있으면 자동으로 PostCSS 사용
// Lightning CSS를 사용하려면 postcss.config.js 제거 또는:
export default defineConfig({
css: {
transformer: 'lightningcss', // 명시적 설정
},
})
// ===== Breaking Change 3: Node.js 최소 버전 =====
// Vite 8은 Node.js 20.0.0 이상 필요
// package.json에 engines 필드 추가 권장
// "engines": {
// "node": ">=20.0.0"
// }
비교표: 프론트엔드 빌드 도구 대결
Vite 8 vs Vite 7 vs webpack vs Turbopack vs Rspack
| 특성 | Vite 8 (Rolldown) | Vite 7 (Rollup+esbuild) | webpack 5 | Turbopack | Rspack |
|---|---|---|---|---|---|
| 핵심 언어 | Rust | JS + Go | JavaScript | Rust | Rust |
| 번들러 엔진 | Rolldown | Rollup | webpack | Turbopack | Rspack |
| 개발 서버 | ESM + Rolldown | ESM + esbuild | DevServer | Turbo DevServer | DevServer |
| 콜드 스타트 | 극히 빠름 | 매우 빠름 | 느림 | 빠름 | 빠름 |
| HMR 속도 | 극히 빠름 | 매우 빠름 | 보통 | 빠름 | 빠름 |
| 프로덕션 빌드 | 매우 빠름 | 보통 | 느림 | (개발 중) | 빠름 |
| 트리 셰이킹 | 우수 | 우수 | 보통 | 보통 | 보통 |
| 코드 분할 | 우수 | 우수 | 우수 | 보통 | 우수 |
| 플러그인 생태계 | Rollup 호환 | Rollup | webpack | 제한적 | webpack 호환 |
| 프레임워크 지원 | React/Vue/Svelte+ | React/Vue/Svelte+ | 모두 | Next.js 전용 | React/Vue |
| 설정 복잡도 | 낮음 | 낮음 | 높음 | 낮음 | 중간 |
| 안정성 (2026.03) | 안정 | 매우 안정 | 매우 안정 | 베타 | 안정 |
빌드 시간 벤치마크
대규모 React 프로젝트(1000+ 컴포넌트, 500+ 라우트)를 기준으로 한 벤치마크이다.
| 도구 | 콜드 빌드 | 워밍 빌드 | HMR (단일 파일) | 메모리 사용량 |
|---|---|---|---|---|
| Vite 8.0 (Rolldown) | 2.1s | 0.8s | 12ms | 380MB |
| Vite 7.x (Rollup) | 28.4s | 12.3s | 45ms | 1.2GB |
| webpack 5 | 45.2s | 8.7s | 320ms | 2.1GB |
| Rspack 1.x | 3.8s | 1.2s | 35ms | 520MB |
| Turbopack (beta) | 3.2s | 0.9s | 18ms | 450MB |
Vite 8.0은 Vite 7.x 대비 콜드 빌드 13.5배, HMR 3.75배 빠르다. 이는 Rust 네이티브 엔진과 병렬 처리의 직접적인 결과이다.
프레임워크별 설정 예시
React + TypeScript 프로젝트
// vite.config.ts - React 프로젝트
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import tsconfigPaths from 'vite-tsconfig-paths'
export default defineConfig({
plugins: [
react({
// SWC 기반 React 변환 (Rolldown 내장 SWC 활용)
jsxImportSource: '@emotion/react',
}),
tsconfigPaths(),
],
build: {
target: 'es2022',
rollupOptions: {
output: {
manualChunks(id) {
// 벤더 청크 분리 전략
if (id.includes('node_modules')) {
if (id.includes('react') || id.includes('react-dom')) {
return 'react-vendor'
}
if (id.includes('@tanstack')) {
return 'tanstack-vendor'
}
if (id.includes('lodash') || id.includes('date-fns')) {
return 'utils-vendor'
}
return 'vendor'
}
},
},
},
// 청크 크기 경고 임계값
chunkSizeWarningLimit: 500, // KB
},
// 환경 변수 접두사
envPrefix: 'VITE_',
// 경로 별칭
resolve: {
alias: {
'@': '/src',
'@components': '/src/components',
'@hooks': '/src/hooks',
'@utils': '/src/utils',
},
},
})
Vue 3 프로젝트
// vite.config.ts - Vue 프로젝트
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import Components from 'unplugin-vue-components/vite'
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [
vue({
script: {
defineModel: true,
propsDestructure: true,
},
}),
vueJsx(),
Components({
// 컴포넌트 자동 임포트
dirs: ['src/components'],
dts: true,
}),
AutoImport({
imports: ['vue', 'vue-router', 'pinia'],
dts: true,
}),
],
build: {
target: 'es2022',
cssMinify: 'lightningcss',
},
css: {
preprocessorOptions: {
scss: {
additionalData: '@use "@/styles/variables" as *;',
},
},
},
})
Svelte 5 프로젝트
// vite.config.ts - Svelte 프로젝트
import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'
export default defineConfig({
plugins: [
svelte({
// Svelte 5 runes 모드
compilerOptions: {
runes: true,
},
}),
],
build: {
target: 'es2022',
rollupOptions: {
output: {
// Svelte는 컴파일러 특성상 작은 번들 생성
manualChunks: undefined, // 자동 분할에 위임
},
},
},
})
플러그인 호환성과 마이그레이션 전략
Rollup 플러그인 호환성 매트릭스
플러그인 호환성 (Vite 8.0 기준):
완전 호환 (즉시 사용 가능):
- @rollup/plugin-alias
- @rollup/plugin-json
- @rollup/plugin-replace
- @rollup/plugin-yaml
- @rollup/plugin-image
- rollup-plugin-visualizer
부분 호환 (설정 수정 필요):
- @rollup/plugin-commonjs (Rolldown 내장 CJS 변환 사용 권장)
- @rollup/plugin-node-resolve (Rolldown 내장 해석기 사용 권장)
- @rollup/plugin-terser (Rolldown 내장 압축기 사용 권장)
비호환 (대체 필요):
- rollup-plugin-esbuild -> 불필요 (Rolldown이 SWC 내장)
- @rollup/plugin-babel -> SWC로 대체
- rollup-plugin-postcss -> Lightning CSS 또는 Vite 내장 CSS 처리
커스텀 플러그인 마이그레이션
// Vite 7 플러그인 (Rollup 호환)
// -> Vite 8에서도 대부분 동작
import type { Plugin } from 'vite'
function myCustomPlugin(): Plugin {
return {
name: 'my-custom-plugin',
// Rollup 호환 훅 (Vite 8에서 그대로 동작)
resolveId(source) {
if (source === 'virtual:my-module') {
return source
}
return null
},
load(id) {
if (id === 'virtual:my-module') {
return 'export const version = "1.0.0"'
}
return null
},
transform(code, id) {
if (id.endsWith('.custom')) {
// 커스텀 파일 형식 변환
return {
code: transformCustomFormat(code),
map: null,
}
}
},
// Vite 전용 훅 (Vite 8에서 동작)
configureServer(server) {
server.middlewares.use('/api', (req, res, next) => {
// 개발 서버 미들웨어
next()
})
},
}
}
function transformCustomFormat(code: string): string {
// 커스텀 변환 로직
return `export default ${JSON.stringify(code)}`
}
빌드 분석 플러그인 활용
// vite.config.ts - 빌드 분석 설정
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
import { visualizer } from 'rollup-plugin-visualizer'
export default defineConfig(({ mode }) => ({
plugins: [
react(),
// 빌드 분석 (프로덕션 빌드에서만)
mode === 'production' &&
visualizer({
open: true,
filename: 'dist/stats.html',
gzipSize: true,
brotliSize: true,
}),
].filter(Boolean),
build: {
// 빌드 리포트 생성
reportCompressedSize: true,
rollupOptions: {
output: {
// 에셋 파일명 패턴
assetFileNames: 'assets/[name]-[hash][extname]',
chunkFileNames: 'js/[name]-[hash].js',
entryFileNames: 'js/[name]-[hash].js',
},
},
},
}))
성능 최적화 심층 가이드
의존성 사전 번들링 최적화
// vite.config.ts - 의존성 최적화
export default defineConfig({
optimizeDeps: {
// 자주 사용하는 의존성을 미리 번들링
include: [
'react',
'react-dom',
'react-router-dom',
'@tanstack/react-query',
'axios',
'date-fns',
'lodash-es',
],
// 번들링에서 제외할 패키지
exclude: [
// ESM으로 직접 제공되는 패키지
'@vueuse/core',
],
// Vite 8: 의존성 캐시가 Rolldown으로 통합됨
// 캐시 위치: node_modules/.vite/rolldown
},
})
대규모 프로젝트 빌드 최적화
// vite.config.ts - 대규모 프로젝트 최적화
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'
export default defineConfig({
plugins: [react()],
build: {
target: 'es2022',
// 멀티 페이지 빌드 설정
rollupOptions: {
input: {
main: 'src/main.tsx',
admin: 'src/admin.tsx',
},
output: {
manualChunks(id) {
// 세밀한 청크 분할
if (id.includes('node_modules')) {
// 프레임워크 코어
if (id.includes('react') || id.includes('react-dom')) {
return 'framework'
}
// UI 라이브러리
if (id.includes('@radix-ui') || id.includes('@headlessui')) {
return 'ui-lib'
}
// 상태 관리
if (id.includes('zustand') || id.includes('@tanstack')) {
return 'state'
}
// 유틸리티
if (id.includes('lodash') || id.includes('date-fns')) {
return 'utils'
}
// 나머지 벤더
return 'vendor'
}
// 공통 컴포넌트
if (id.includes('src/components/common')) {
return 'common-components'
}
},
},
},
// 압축 설정
minify: 'terser', // 또는 'oxc' (Vite 8 신규)
terserOptions: {
compress: {
drop_console: true, // 프로덕션에서 console.log 제거
drop_debugger: true,
},
},
// CSS 코드 분할
cssCodeSplit: true,
},
})
HMR 성능 극대화
// vite.config.ts - HMR 최적화
export default defineConfig({
server: {
hmr: {
// WebSocket 오버레이 설정
overlay: true,
// HMR 포트 (프록시 환경에서 유용)
// port: 24678,
},
// 파일 감시 최적화
watch: {
// 대규모 프로젝트에서 성능 향상
// chokidar의 usePolling은 기본 false (이벤트 기반 감시)
usePolling: false,
// 무시할 경로
ignored: ['**/node_modules/**', '**/.git/**', '**/dist/**', '**/coverage/**'],
},
},
// Vite 8: Rolldown의 증분 빌드 활용
// 변경된 모듈만 재번들링하여 HMR 속도 극대화
})
트러블슈팅 가이드
흔한 마이그레이션 문제와 해결책
| 증상 | 원인 | 해결책 |
|---|---|---|
Cannot find module 에러 | Rolldown 모듈 해석 차이 | resolve.alias 명시적 설정 |
| CSS 스타일 깨짐 | Lightning CSS 기본 전환 | css.transformer: 'postcss' 설정 |
| HMR 작동 안 함 | 플러그인 비호환 | 플러그인 최신 버전 확인 |
| 빌드 출력 크기 증가 | 트리 셰이킹 차이 | sideEffects 필드 확인 |
| TypeScript 에러 | SWC 변환 차이 | tsconfig.json 설정 확인 |
| 환경 변수 인식 안 됨 | import.meta.env 변경 | VITE_ 접두사 확인 |
CommonJS 모듈 호환성 문제
// 문제: CJS 모듈이 ESM으로 변환되지 않는 경우
// vite.config.ts에서 명시적 처리
export default defineConfig({
optimizeDeps: {
// CJS 모듈을 강제로 사전 번들링에 포함
include: ['problematic-cjs-package'],
},
build: {
// CommonJS 감지 설정
commonjsOptions: {
// 변환할 파일 패턴
include: [/node_modules/],
// strict 모드에서 CJS 변환
strictRequires: true,
},
},
})
소스맵 디버깅 문제
// 소스맵 설정 가이드
export default defineConfig(({ mode }) => ({
build: {
// 개발: 인라인 소스맵 (빠른 매핑)
// 스테이징: 별도 소스맵 파일
// 프로덕션: hidden 소스맵 (에러 리포팅만)
sourcemap: mode === 'development' ? 'inline' : mode === 'staging' ? true : 'hidden',
},
// CSS 소스맵
css: {
devSourcemap: true,
},
}))
메모리 관련 문제
# 대규모 프로젝트에서 OOM 발생 시
# Node.js 힙 메모리 증가
NODE_OPTIONS="--max-old-space-size=8192" pnpm build
# Vite 8은 Rolldown(Rust)이 네이티브 메모리를 사용하므로
# Node.js 힙과 별개로 시스템 메모리 확인 필요
# 최소 권장: 빌드 대상 파일 수 x 0.5MB
# 메모리 사용량 모니터링
NODE_OPTIONS="--max-old-space-size=8192 --trace-gc" pnpm build 2>&1 | grep "GC"
운영 시 주의사항
CI/CD 파이프라인 설정
# .github/workflows/build.yml
name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: 9
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
# Vite 8 빌드 캐시 활용
- name: Cache Vite build
uses: actions/cache@v4
with:
path: |
node_modules/.vite
node_modules/.cache
key: vite-build-${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
vite-build-
- name: Build
run: pnpm build
env:
NODE_ENV: production
- name: Type Check
run: pnpm tsc --noEmit
- name: Lint
run: pnpm lint
# 빌드 크기 리포트
- name: Report bundle size
run: |
echo "## Bundle Size Report" >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
du -sh dist/assets/* | sort -rh >> "$GITHUB_STEP_SUMMARY"
echo '```' >> "$GITHUB_STEP_SUMMARY"
Docker 빌드 최적화
# Dockerfile - Vite 8 프로덕션 빌드
# Stage 1: 빌드
FROM node:20-slim AS builder
RUN corepack enable pnpm
WORKDIR /app
# 의존성 캐시 레이어
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile
# 소스 복사 및 빌드
COPY . .
RUN pnpm build
# Stage 2: 서빙
FROM nginx:alpine
# nginx 설정
COPY nginx.conf /etc/nginx/conf.d/default.conf
# 빌드 결과물만 복사
COPY /app/dist /usr/share/nginx/html
# SPA 라우팅을 위한 설정 포함
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
# nginx.conf - SPA 라우팅 및 에셋 캐싱
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
# 해시된 에셋은 장기 캐싱
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
try_files $uri =404;
}
# HTML은 항상 최신 버전 제공
location / {
try_files $uri $uri/ /index.html;
add_header Cache-Control "no-cache";
}
# gzip 압축
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 1000;
}
환경별 빌드 전략
// vite.config.ts - 환경별 분기
import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react-swc'
export default defineConfig(({ mode }) => {
// 환경 변수 로드
const env = loadEnv(mode, process.cwd(), '')
return {
plugins: [react()],
// 환경별 빌드 설정
build: {
// 개발: 빠른 빌드 우선
// 프로덕션: 최적화 우선
minify: mode === 'production' ? 'terser' : false,
sourcemap: mode === 'production' ? 'hidden' : true,
rollupOptions: {
output: {
// 프로덕션에서만 청크 분할
...(mode === 'production' && {
manualChunks: {
vendor: ['react', 'react-dom'],
},
}),
},
},
},
// API 프록시 (개발 환경)
server: {
proxy: {
'/api': {
target: env.VITE_API_URL || 'http://localhost:8080',
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
},
},
},
// 환경 변수 정의
define: {
__APP_VERSION__: JSON.stringify(process.env.npm_package_version),
__BUILD_TIME__: JSON.stringify(new Date().toISOString()),
},
}
})
Rust 기반 빌드 도구 생태계 비교
3대 Rust 번들러 심층 비교
Rolldown (Vite 8)
- 목표: Rollup + esbuild 통합 대체
- 강점: Vite 생태계 통합, Rollup 플러그인 호환
- 약점: 초기 버전, 검증 기간 필요
- 적합: Vite 사용자, 범용 프로젝트
Turbopack (Next.js)
- 목표: webpack 대체 (Next.js 전용)
- 강점: Next.js 최적화, Vercel 지원
- 약점: Next.js 외 사용 제한적
- 적합: Next.js 프로젝트
Rspack (독립)
- 목표: webpack 드롭인 대체
- 강점: webpack 호환성 최고, 마이그레이션 용이
- 약점: webpack 레거시 설계 답습
- 적합: webpack에서 마이그레이션하는 대규모 프로젝트
프레임워크-빌드 도구 매칭 가이드
| 프레임워크 | 권장 빌드 도구 | 이유 |
|---|---|---|
| React (SPA) | Vite 8 | 최고 성능, 범용성 |
| React (SSR) | Vite 8 또는 Next.js (Turbopack) | SSR 요구사항에 따라 |
| Vue 3 | Vite 8 | 공식 권장, 최적 통합 |
| Svelte/SvelteKit | Vite 8 | SvelteKit 공식 번들러 |
| Next.js | Turbopack | 공식 번들러, 최적 통합 |
| 대규모 레거시 (webpack) | Rspack | webpack.config 재사용 가능 |
| Remix | Vite 8 | Remix v3부터 Vite 기반 |
| Astro | Vite 8 | 공식 번들러 |
성능 측정 및 모니터링
빌드 성능 측정 스크립트
#!/bin/bash
# build-benchmark.sh - 빌드 성능 비교 스크립트
echo "=== Vite 8 빌드 벤치마크 ==="
# 캐시 클리어 (콜드 빌드)
rm -rf node_modules/.vite dist
# 콜드 빌드 측정
echo "--- Cold Build ---"
time pnpm build 2>&1
# 워밍 빌드 측정 (캐시 있음)
echo "--- Warm Build ---"
time pnpm build 2>&1
# 빌드 결과 분석
echo "--- Build Output ---"
du -sh dist/
echo "--- Asset Sizes ---"
du -sh dist/assets/* | sort -rh | head -20
# gzip 압축 후 크기
echo "--- Gzipped Sizes ---"
for file in dist/assets/*.js; do
original=$(wc -c < "$file")
gzipped=$(gzip -c "$file" | wc -c)
echo "$file: ${original}B -> ${gzipped}B ($(( gzipped * 100 / original ))%)"
done
Lighthouse CI 통합
// lighthouserc.ts - Lighthouse CI 설정
export default {
ci: {
collect: {
startServerCommand: 'pnpm preview',
url: ['http://localhost:4173/'],
numberOfRuns: 3,
},
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }],
'first-contentful-paint': ['warn', { maxNumericValue: 1500 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'total-blocking-time': ['warn', { maxNumericValue: 200 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
},
},
upload: {
target: 'temporary-public-storage',
},
},
}
마이그레이션 체크리스트
- Node.js 버전이 20.0.0 이상인가
-
vite@^8.0.0및 관련 플러그인이 최신 버전인가 -
esbuildOptions설정을 제거하고 Rolldown 호환 설정으로 교체했는가 - CSS 처리가 Lightning CSS 전환으로 인해 깨지지 않는가
- 모든 Rollup 플러그인이 Vite 8과 호환되는가
- CommonJS 모듈이 정상적으로 변환되는가
- 빌드 출력물의 크기와 구조가 기대와 일치하는가
- HMR이 모든 파일 타입에서 정상 동작하는가
- CI/CD 파이프라인이 Vite 8 빌드를 지원하는가
- 프로덕션 환경에서 소스맵 설정이 적절한가
- 환경 변수가 올바르게 주입되는가
- 빌드 성능 벤치마크를 수행하여 개선을 확인했는가
마치며
Vite 8.0과 Rolldown의 등장은 프론트엔드 빌드 도구 역사에서 중요한 전환점이다. esbuild와 Rollup이라는 두 개의 서로 다른 엔진에 의존하던 구조적 한계를 Rust 기반 단일 엔진으로 해결하면서, 10~30배의 성능 향상과 개발/프로덕션 일관성을 동시에 달성했다.
Turbopack이 Next.js 전용이라는 제약을 가지고, Rspack이 webpack 호환성에 집중하는 반면, Rolldown은 범용 번들러로서의 포지셔닝이 명확하다. Rollup의 풍부한 플러그인 생태계를 계승하면서 Rust의 성능을 얻은 것은 강력한 경쟁력이다.
프로덕션 도입 시에는 플러그인 호환성 검증, CSS 처리 방식 변경, CommonJS 모듈 처리 등을 꼼꼼히 확인해야 한다. 하지만 대부분의 프로젝트에서 마이그레이션 비용 대비 성능 향상이 압도적이므로, Vite를 사용 중인 팀이라면 8.0 업그레이드를 적극 검토할 것을 권한다.
참고 자료
- Vite 8.0 Release Blog - 공식 릴리스 노트 및 마이그레이션 가이드
- Rolldown GitHub Repository - Rust 기반 번들러 소스 코드 및 기술 문서
- Vite Official Documentation - Vite 설정, API, 플러그인 가이드
- Evan You - "Vite and the Rolldown Vision" - Vite/Rolldown 아키텍처 발표
- Turbopack vs Rspack vs Rolldown Benchmarks - 크로스 번들러 성능 비교