0479

FE

[Vite] 공통 옵션 (Shared Options) 1편

| 서론

안녕하세요, 팡일입니다.

Vite를 사용하다 보면 vite.config.ts 파일에서 다양한 옵션들을 설정하게 되는데, 처음에는 어떤 옵션이 언제, 어떻게 적용되는지 감이 잘 잡히지 않는 경우가 많습니다. 특히 설정을 추가할 때마다 “이건 dev에서만 적용되는 걸까, 아니면 build에도 영향을 줄까?”와 같은 고민을 한 번쯤 해보게 됩니다.

이러한 혼란을 줄이기 위해 Vite 공식 문서에서는 Shared Options라는 개념을 통해, 개발(dev), 빌드(build), 미리보기(preview) 전반에 공통으로 적용되는 핵심 설정들을 정리하고 있습니다.

이번 글에서는 이 Shared Options를 중심으로, root, base, mode, define, plugins, publicDir, cacheDir와 같은 주요 옵션들이 어떤 역할을 하고, 실제 프로젝트에서 어떤 영향을 미치는지 흐름 중심으로 정리해보겠습니다.

단순히 옵션을 나열하는 것이 아니라, “왜 필요한지”와 “어디에 영향을 주는지”를 이해하는 것에 초점을 맞춰보겠습니다.

| 공통 옵션 (Shared Options)

앞서 Vite config의 구조를 살펴봤다면, 이제 실제로 자주 사용하는 설정 옵션들을 이해할 차례입니다.

Vite 공식 문서에서는 이러한 설정들을 Shared Options라는 이름으로 정의하고 있으며, 이 옵션들은 별도의 언급이 없는 한 개발(dev), 빌드(build), 미리보기(preview) 모든 환경에서 공통적으로 적용됩니다.

즉, 특정 상황에서만 동작하는 옵션이 아니라, 프로젝트 전체의 실행 방식과 결과에 영향을 주는 핵심 설정들이라고 이해하는 것이 중요합니다.

| root

  • Type: string

  • Default: process.cwd()

root 옵션은 Vite가 프로젝트를 해석할 때 기준이 되는 루트 디렉토리를 설정합니다. 이 경로는 일반적으로 index.html이 위치한 디렉토리를 의미하며, Vite는 이 파일을 기준으로 애플리케이션을 시작합니다.

기본적으로는 현재 디렉토리(process.cwd())를 기준으로 동작하기 때문에, 일반적인 프로젝트에서는 별도로 설정할 필요가 없습니다.

하지만 프로젝트 구조가 다음과 같이 나뉘어 있다면 이야기가 달라집니다.

TypeScript
project/
 ├── client/
 │   └── index.html
 └── server/

이 경우 Vite는 기본적으로 project/를 루트로 인식하기 때문에, index.html을 찾지 못하는 문제가 발생할 수 있습니다.

그래서 아래와 같이 명시적으로 설정해줘야 합니다.

TypeScript
export default defineConfig({
  root: "./client",
});

| base

base는 애플리케이션이 서비스되는 기준 경로(public base path)를 설정하는 옵션입니다. 특히 빌드된 정적 파일(JS, CSS, 이미지 등)이 어떤 경로를 기준으로 로드될지를 결정하는 중요한 설정이며, 옵션은 특히 배포 환경에서 매우 중요합니다.

로컬에서는 /로 동작하기 때문에 체감이 잘 안 되지만, 실제 서비스에서는 /my-app/ 같은 하위 경로에서 실행되는 경우가 많기 때문입니다.

1) 작동 흐름

TypeScript
export default defineConfig({
  base: "/my-app/",
});

이 설정이 적용되면, 빌드 결과의 리소스 경로가 다음과 같이 바뀝니다.

TypeScript
<script src="/my-app/assets/index.js"></script>

즉, base는 단순한 경로 설정이 아니라 정적 파일이 어디에서 로드될지를 결정하는 기준입니다.

만약 이 설정이 잘못되면, CSS/JS 파일 로딩 실패, 이미지 깨짐과 같은 문제가 발생할 수 있습니다.

| mode

  • Type: string

  • Default: 'development' for serve, 'production' for build

mode는 현재 실행 환경을 나타내는 값입니다. 여기서 중요한 점은, mode는 우리가 직접 설정하지 않아도 Vite가 실행 명령어에 따라 자동으로 설정해준다는 것입니다.

  • vite 실행 → mode = development

  • vite build 실행 → mode = production

즉, mode는 단순한 문자열이 아니라 환경을 구분하기 위한 기준 값으로 사용됩니다.

1) 작동 흐름

TypeScript
vite build --mode staging

예를 들어 위와 같이 명령어를 실행하면, mode = “staging”으로 설정되며, 아래와 같은 파일이 로드됩니다.

CSS
.env.staging
.env.staging.local

즉, mode는 단순한 문자열이 아니라 환경 분기를 위한 기준 값으로 사용됩니다.

| define

  • Type: Record<string, any>

define은 전역 상수를 정의하는 옵션입니다. 이 옵션의 핵심은 “코드를 실행할 때 값이 바뀌는 것이 아니라, 빌드 시점에 코드 자체가 바뀐다”는 점입니다.

즉, 런타임에 변수 값을 읽는 것이 아니라, 빌드 과정에서 해당 값이 실제 코드로 대체되는 방식으로 동작합니다.

1) 작동 흐름

(1) 설정

code
export default defineConfig({
  define: {
    __APP_VERSION__: JSON.stringify("v1.0.0"),
  },
});

(2) 사용

code
console.log(__APP_VERSION__);

(3) 빌드 결과

CSS
console.log("v1.0.0");

이처럼 define은 단순한 변수 선언이 아니라, 코드 치환(replace)을 통한 최적화 및 환경 분기 처리에 활용되는 옵션입니다.

예를 들어, 개발 환경과 운영 환경에 따라 다른 값을 주입하거나, 빌드 시점에 고정된 값을 코드에 직접 삽입하고 싶을 때 유용하게 사용할 수 있습니다.

2) 주의사항

  • define의 값은 JSON 직렬화 가능한 값(문자열, 숫자, boolean, 객체 등) 또는 단일 식별자를 담은 문자열이어야 합니다.

  • 문자열이 아닌 값은 Vite가 내부적으로 JSON.stringify를 통해 자동 변환합니다.

3) TypeScript 사용자

define으로 선언한 전역 상수는 TypeScript가 기본적으로 알지 못하기 때문에, 타입 지원과 자동완성을 위해 별도의 선언이 필요합니다.

TypeScript
// vite-env.d.ts
declare const __APP_VERSION__: string;

이 과정을 통해 IDE에서 타입 체크와 자동완성을 정상적으로 사용할 수 있습니다.

| plugins

  • Type: (Plugin | Plugin[] | Promise<Plugin | Plugin[]>)[]

plugins는 Vite의 기능을 확장하는 핵심 옵션으로, 프로젝트에서 사용할 플러그인 목록을 정의하는 역할을 합니다.

Vite는 기본적으로 매우 가볍고 빠른 빌드 도구이지만, 플러그인을 통해 React, Vue, SVG 처리, 번들 분석 등 다양한 기능을 추가할 수 있습니다.

code
export default defineConfig({
  plugins: [react()],
});

react()와 같이 사용하게 될 경우, JSX 변환, Fast Refresh, React 최적화, 최신 문법 처리 등 이걸 전부 묶어서 Vite에 “React 능력”을 추가한다고 이해하면 쉽습니다. 또한, react() 말고도, svelte(), vue(), solid()와 같이 사용할 수 있습니다.

이처럼 필요한 기능을 플러그인 형태로 추가하면서 프로젝트의 빌드 환경을 점진적으로 확장해 나갈 수 있습니다.

1) 특징

  • false, null 등의 값은 자동으로 무시됩니다.

  • 배열 형태로 전달해도 내부적으로 평탄화(flatten)됩니다.

  • Promise를 반환하는 플러그인도 지원되며, 실행 전에 resolve됩니다.

이러한 특성 덕분에 다음과 같이 조건부로 플러그인을 적용하는 패턴도 자연스럽게 사용할 수 있습니다.

TypeScript
plugins: [
  react(),
  isProd && somePlugin(),
]

Vite는 false, null 등의 falsy 값을 자동으로 무시하기 때문에 위와 같이 조건부 플러그인 구성이 가능합니다. 필요에 따라 일반적인 배열 정리를 위해 .filter(Boolean)을 함께 사용할 수도 있습니다.

| publicDir

  • Type: string | false

  • Default: "public"

publicDir는 정적 파일(static assets)을 관리하는 디렉토리를 지정하는 옵션입니다.
이미지, favicon, manifest 파일처럼 번들링 없이 그대로 사용해야 하는 파일들을 이 디렉토리에 두게 됩니다.

즉, Vite가 처리하지 않고 “그대로 제공만 하는 파일 전용 공간”이라고 이해하시면 됩니다.

1) 작동 흐름

(1) 파일 위치

code
public/logo.png

(2) 개발 환경에서 접근

HTML
<img src="/logo.png" />

개발 서버에서 /logo.png로 바로 접근 가능합니다.

(3) 빌드 결과

code
dist/logo.png

별도의 변환 없이 그대로 outDir(기본값: dist)의 루트 경로로 복사됩니다.

2) 핵심 특징

  • 번들링 대상이 아님 (transform 없음)

  • 해시(hash) 처리도 되지 않음

  • 항상 원본 그대로 유지

이러한 특성 때문에 다음과 같은 경우에 사용합니다.

  • 로고, 이미지, favicon

  • 외부에서 직접 참조해야 하는 파일

  • 경로가 고정되어야 하는 리소스

3) React에서의 사용 예시

HTML
<img src="/logo.png" />

import 없이 바로 사용 가능하며, /public 경로는 생략하고 루트(/) 기준으로 접근할 수 있습니다.

4) 기능 비활성화

필요하지 않은 경우, 해당 기능을 완전히 끌 수도 있습니다.

code
export default defineConfig({
  publicDir: false,
});

이 경우 public 디렉토리는 무시됩니다.

| cacheDir

  • Type: string

  • Default: "node_modules/.vite"

cacheDir는 Vite가 사용하는 캐시 파일 저장 디렉토리를 지정하는 옵션입니다. 이 디렉토리는 성능 최적화를 위해 자동으로 생성되고 관리됩니다.

1) 무엇이 저장될까?

이 디렉토리에는 다음과 같은 데이터가 저장됩니다.

  • 사전 번들링된 의존성 (pre-bundled deps)

  • 빌드 및 변환 결과 캐시

쉽게 말해, “다시 계산하지 않기 위한 결과 저장소”입니다.

2) 왜 필요한가?

Vite는 빠른 개발 경험을 제공하기 위해 자주 사용하는 라이브러리들을 미리 처리해 캐시에 저장합니다.

예를 들어:

  • react, react-dom 같은 라이브러리

  • 변경되지 않는 외부 패키지

이런 것들을 매번 다시 처리하지 않도록 해서 서버 시작 속도와 빌드 속도를 크게 개선합니다.

3) 캐시 초기화 방법

가끔 캐시가 꼬이거나 문제가 발생할 수 있습니다. 이럴 때는 캐시를 초기화하면 해결되는 경우가 많습니다.

(1) CLI 명령어

code
vite --force

캐시를 무시하고 다시 생성합니다.

(2) 직접 삭제

code
rm -rf node_modules/.vite

기본 설정 기준(node_modules/.vite)에 생성된 캐시 디렉토리를 삭제하면, Vite가 다음 실행 시 자동으로 다시 생성합니다

4) 언제 변경할까?

기본값으로 대부분 충분하지만, 아래 상황에서는 변경을 고려할 수 있습니다.

  • 모노레포 환경에서 캐시 위치를 분리하고 싶을 때

  • CI/CD 환경에서 캐시 경로를 커스터마이징할 때

| 결론

지금까지 Vite의 Shared Options를 중심으로, 프로젝트 전반에 영향을 주는 핵심 설정들을 살펴봤습니다.

이 옵션들의 공통점은 단순히 특정 기능을 켜고 끄는 설정이 아니라, 프로젝트의 실행 기준 자체를 정의한다는 점입니다. root는 프로젝트의 시작점을, base는 리소스가 로드되는 경로를, mode는 환경 분기의 기준을 결정하며, define과 plugins는 빌드 결과와 개발 경험을 직접적으로 바꾸는 역할을 합니다. 또한 publicDir과 cacheDir은 각각 정적 자산 처리와 성능 최적화 측면에서 중요한 역할을 담당합니다.

결국 Vite 설정을 잘 이해한다는 것은 단순히 옵션을 외우는 것이 아니라, 개발 환경과 빌드 결과가 어떤 흐름으로 만들어지는지를 이해하는 것이라고 볼 수 있습니다.

작은 프로젝트에서는 기본 설정만으로도 충분히 동작하지만, 프로젝트 규모가 커지고 배포 환경이 다양해질수록 이러한 Shared Options의 중요성은 더욱 커집니다. 이번 정리를 통해 각 옵션이 어떤 맥락에서 사용되는지 감을 잡고, 상황에 맞게 설정을 설계할 수 있는 기반이 되었으면 좋겠습니다.