서비스 학습
SOURCE · fe/vite.config.ts · 2026-09-06

일곱 줄이 TSX를
브라우저가 읽는 파일로 바꾼다

설정이 거의 비어 있다는 사실 자체가 정보다. Vite의 기본값을 그대로 쓰겠다는 선언이며, 그 기본값이 무엇인지 아는 것이 이 페이지의 목적이다.

이 파일을 만든 이유

브라우저는 .tsx 파일을 실행하지 못한다. JSX 문법도 모르고 TypeScript type도 모른다. 누군가 이것을 평범한 JavaScript로 바꿔 줘야 하며, 그 일을 하는 도구가 Vite다.

Vite는 설정 없이도 대부분 동작하지만 React의 JSX만은 예외다. <div> 같은 문법을 어떻게 해석할지 알려 주는 plugin이 필요하다. 이 파일은 사실상 그 한 가지를 위해 존재한다.

전체 구조에서의 위치

사람이 쓰는 것src/*.tsx · *.cssJSX와 TypeScript
변환 규칙vite.config.ts여기 — plugin과 기본값
개발npm run dev메모리에서 즉시 변환, HMR
배포npm run builddist/ 에 정적 파일 생성

같은 설정이 두 가지 다른 실행을 지배한다. 개발 서버는 파일을 그때그때 변환해 브라우저에 주고, build는 전부 미리 변환해 파일로 남긴다. 결과가 달라 보이지만 변환 규칙은 하나다.

전체 코드

import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
})

한 줄씩 해석

import react from '@vitejs/plugin-react'

Vite에 React 지원을 더하는 공식 plugin이다. 두 가지를 한다. 첫째 JSX 변환<div className="x">를 React가 이해하는 함수 호출로 바꾼다. 둘째 Fast Refresh — 개발 중 컴포넌트를 고쳤을 때 페이지 전체를 새로 고치지 않고 그 부분만 교체해 state를 유지한다. 입력창에 글을 쓰다가 코드를 고쳐도 글이 사라지지 않는 이유가 이것이다.

import { defineConfig } from 'vite'

설정 객체를 그대로 내보내도 Vite는 동작한다. defineConfig로 감싸는 이유는 편집기의 자동완성과 type 검사를 얻기 위해서다. 실행 시점에는 받은 객체를 그대로 돌려주는 함수라 성능 비용이 없다. plugin처럼 오타를 내면 즉시 표시된다.

// https://vite.dev/config/

Vite가 프로젝트를 만들 때 넣어 주는 주석이다. 설정 항목이 필요할 때 찾아볼 곳을 가리킨다.

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

react가 아니라 react()라는 점에 주목한다. plugin은 호출해서 만든 객체를 넘긴다. 인수를 주면 동작을 조절할 수 있기 때문이다. plugins가 배열인 이유는 순서가 있는 여러 plugin을 받기 때문이며, 지금은 하나뿐이다.

적혀 있지 않지만 적용되는 기본값

설정에 없는 항목은 Vite의 기본값으로 동작한다. 이 프로젝트의 다른 파일들과 직접 연결되는 것만 정리한다.

항목기본값이 프로젝트에서의 의미
rootfe/index.html이 이 위치에 있어야 진입점으로 인식된다
build.outDirdistDockerfileCOPY --from=build /app/dist가 이 이름에 의존한다
server.port5173Dockerfile의 EXPOSE 5173과 짝을 이룬다
server.hostlocalhostcontainer 안에서는 밖에서 닿지 않는다. 그래서 --host 0.0.0.0을 명령으로 준다
base/자산 경로가 root 기준이 된다. Nginx가 root에서 서빙하므로 맞는다
build.target최신 브라우저오래된 브라우저 지원이 필요하면 명시해야 한다

특히 outDirEXPOSE는 다른 파일이 이 기본값을 전제로 적혀 있다. 여기서 outDir을 바꾸면 Dockerfile의 production 단계가 조용히 빈 이미지를 만든다.

이 파일이 하지 않는 일 — type 검사

"dev":     "vite"
"build":   "tsc -b && vite build"
"preview": "vite preview"

build가 두 명령이라는 점이 핵심이다. tsc -b가 type을 검사하고, vite build가 파일을 만든다. Vite 자신은 type을 검사하지 않고 지우기만 한다. 빠른 대신 잘못된 type을 그냥 통과시킨다.

명령type 검사결과물
npm run dev안 함없음. 메모리에서 변환해 브라우저로
npm run build (tsc -b)dist/
npm run preview안 함이미 만든 dist/를 서빙

그래서 개발 중에는 멀쩡하던 코드가 build에서 처음 실패할 수 있다. 편집기가 오류를 표시해 주지만, 편집기를 믿고 넘어가면 Docker build 단계에서 뒤늦게 막힌다. &&로 이어 둔 덕분에 type 오류가 있으면 dist/가 아예 만들어지지 않는다.

실제 실행 결과

cd fe
npm install
npm run build
dist/
├── index.html                 <script src=/assets/index-해시.js> 로 교체됨
├── vite.svg
└── assets/
    ├── index-<해시>.js        React + App.tsx + main.tsx 가 하나로
    └── index-<해시>.css       index.css + App.css 가 하나로
진입점index.htmlscript 태그가 해시 파일을 가리킴
자산 이름내용 해시캐시 무효화가 자동
소스 파일dist에 없음tsx·ts는 결과물에 남지 않는다

파일 이름에 내용 해시가 붙는 것이 중요하다. 코드가 바뀌면 이름이 바뀌므로 브라우저가 옛 파일을 캐시하고 있어도 새 이름을 새로 받는다. nginx.conf가 자산에 immutable 캐시를 1년으로 걸 수 있는 이유가 이것이다.

dist/자동 생성물이라 이 학습 사이트에서 파일별로 다루지 않는다. 만들어지는 과정과 대표 산출물만 여기서 설명한다.

자주 발생하는 오류

증상원인진단
Failed to parse source ... Unexpected token <plugins: [react()] 누락JSX를 해석하지 못한 것이다
container에서 개발 서버에 접속 불가기본 host가 localhostnpm run dev -- --host 0.0.0.0. Dockerfile의 development 단계가 이미 그렇게 한다
Docker production 이미지가 비어 있음outDir을 바꿈Dockerfile의 COPY --from=build /app/dist와 이름을 맞춘다
개발은 되는데 npm run build 실패tsc -b의 type 오류Vite는 type을 검사하지 않는다. 오류 메시지의 파일·줄을 그대로 따라간다
빈 화면 + 404 자산base와 실제 서빙 경로 불일치하위 경로에 배포한다면 base를 지정해야 한다
react()가 아니라 react를 씀호출하지 않음plugin은 호출 결과 객체를 넣는다

설계 선택과 대안

왜 설정을 더 채우지 않는가?

기본값으로 충분한데 미리 적어 두면 그 값이 왜 거기 있는지 아무도 모르게 된다. 나중에 Vite 기본값이 개선되어도 우리가 고정한 값에 발이 묶인다. 필요해질 때 이유와 함께 추가하는 편이 낫다.

server.proxy를 지금 넣어야 하지 않나?

3단계에서 채팅 API를 붙일 때 개발 서버의 /api 요청을 FastAPI로 넘기는 proxy 설정이 필요해질 수 있다. 다만 Docker Compose로 묶으면 다른 방법으로도 해결된다. 두 경로 중 무엇을 택할지는 10단계의 Compose 통합에서 정해지므로, 지금 넣으면 버릴 가능성이 크다.

@vitejs/plugin-reactplugin-react-swc의 차이

변환을 수행하는 엔진이 다르다. 현재 쓰는 쪽은 Oxc 기반이고, SWC 기반의 대안도 있다. 결과물은 같고 변환 속도만 다르다. 이 프로젝트 규모에서는 체감 차이가 없어 기본 선택을 유지한다.

defineConfig 없이 객체만 내보내면?

동작은 같다. 잃는 것은 편집기의 자동완성과 오타 검사뿐이다. 설정이 커질수록 그 도움이 커지므로 관례대로 감싸 둔다.

이전 단계와 다음 파일

이 설정이 변환하는 소스는 main.tsxApp.tsx다. 여기서 만들어진 dist/를 이미지에 담는 과정은 Dockerfile, 그것을 HTTP로 내보내는 설정은 nginx.conf에서 이어진다.

← 이전채팅 화면 스타일다음 →의존성과 명령