Vite 8에서 React TypeScript 프로젝트를 만들고 dev·build·preview를 어떻게 사용하나요?
Vite의 react-ts 템플릿으로 React 프로젝트를 생성하고 설치한 뒤 개발 서버 주소를 엽니다. dev는 수정하며 확인하는 서버, build는 배포용 결과 생성, preview는 만들어진 결과 확인에 사용합니다.
적용 조건·범위: Node.js와 npm이 필요합니다. 이 글의 실습 기준은 Node.js 22.12 이상입니다. HTML·JavaScript 기본 문법을 알고 있으면 파일 연결을 이해하기 쉽습니다. 새 프로젝트가 없는 독자는 아래 명령으로 바로 시작할 수 있습니다.
본문 근거: Vite Getting Started
Vite란 무엇인가
Vite는 개발 서버와 빌드 도구를 제공하는 프론트엔드 개발 도구입니다. React 자체가 파일을 번들링하거나 개발 서버를 실행하는 것은 아닙니다. Vite가 개발 중 모듈을 제공하고, 최종 배포에 사용할 빌드 결과를 생성합니다.
처음에는 다음 두 역할만 구분하면 됩니다.
- 개발 중: 빠른 개발 서버와 변경 반영
- 배포 전: 최적화된 정적 빌드 결과 생성
기본 파일 구조
react-ts 템플릿을 만들면 대략 다음 파일을 볼 수 있습니다.
taskflow/
├─ src/
│ ├─ App.tsx
│ ├─ main.tsx
│ └─ index.css
├─ index.html
├─ package.json
├─ tsconfig.json
└─ vite.config.ts
index.html
브라우저가 처음 읽는 HTML 문서입니다. React가 렌더링될 root 요소가 들어 있습니다.
src/main.tsx
React 애플리케이션의 진입점입니다. root DOM 요소를 찾고 App 컴포넌트를 렌더링합니다.
src/App.tsx
실제 화면 컴포넌트가 시작되는 파일입니다. 이후 TaskFlow의 여러 컴포넌트가 이 파일에서 연결됩니다.
React가 화면에 나타나는 흐름
흐름은 다음과 같습니다.
index.html
↓
src/main.tsx
↓
<App />
↓
브라우저 화면
이 관계만 이해해도 “App.tsx를 수정했는데 왜 화면이 안 바뀌지?” 같은 문제를 추적하기 쉬워집니다.
package.json scripts
Vite 프로젝트에서는 보통 다음 scripts를 사용합니다.
{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"preview": "vite preview"
}
}
npm run dev
개발 서버를 실행합니다.
npm run dev
코드를 수정하면서 결과를 확인할 때 사용합니다.
npm run build
TypeScript 검사와 Vite 빌드를 실행해 배포용 결과를 만듭니다.
npm run build
개발 서버에서 잘 보인다고 해서 build도 반드시 성공하는 것은 아닙니다. 배포 전에 build까지 확인하는 습관이 중요합니다.
npm run preview
빌드된 결과를 로컬에서 확인합니다.
npm run preview
자주 발생하는 오류와 해결
import 경로를 찾을 수 없습니다
파일 이름과 실제 경로의 대소문자를 먼저 확인합니다. Windows에서는 우연히 동작하던 경로가 Linux 배포 환경에서 실패할 수 있습니다.
TypeScript 오류 때문에 build가 실패합니다
개발 화면이 보이더라도 타입 오류가 남아 있으면 build가 실패할 수 있습니다.
npm run build
출력되는 첫 번째 타입 오류부터 수정합니다.
개발 서버 포트가 다릅니다
기본 포트가 이미 사용 중이면 Vite가 다른 포트를 선택할 수 있습니다. 터미널에 표시된 Local 주소를 기준으로 확인합니다.
독립 실습: dev와 build·preview의 차이 직접 확인
위의 새 react-ts 프로젝트만 있으면 됩니다. TaskFlow ZIP은 필요 없습니다.
src/App.tsx에서 화면에 보이는 제목 하나를 ‘첫 번째 수정’으로 바꿉니다.npm run dev가 알려 주는 Local 주소를 열어 새 문구가 보이는지 확인합니다.- 개발 서버를 중지한 뒤
npm run build를 실행합니다. 성공하면 프로젝트의dist폴더가 생겼는지 확인합니다. 이어npm run preview를 실행하고 터미널에 표시된 주소에서 ‘첫 번째 수정’을 확인합니다. - preview를 켠 상태에서
src/App.tsx의 같은 제목을 ‘두 번째 수정’으로 바꾸고 페이지를 새로고침합니다. 아직 build를 다시 하지 않았으므로 preview에는 ‘첫 번째 수정’이 보입니다. - preview를 중지하고
npm run build,npm run preview를 다시 실행합니다. 이제 ‘두 번째 수정’이 보이는지 확인합니다. 수정 내용이 보이지 않으면 터미널의 실제 주소, build 성공 여부, 파일 저장 여부를 순서대로 확인하세요.
스스로 확인: dev에서는 새 코드가 바로 보이는데 preview에서는 이전 제목이 남는 이유는 무엇일까요? preview는 현재 소스가 아니라 마지막 build 결과인 dist를 보여 주기 때문입니다. 이 실습의 목적은 개발 서버, 빌드 산출물, 로컬 미리보기를 구별하는 것입니다.
학습 완료 체크리스트
- Vite와 React의 역할을 구분할 수 있습니다.
- main.tsx와 App.tsx의 연결을 설명할 수 있습니다.
- dev와 build의 목적을 구분할 수 있습니다.
- build 오류와 개발 서버 오류를 따로 확인할 수 있습니다.
선택 실습: 할 일 앱에 적용하기
TaskFlow는 작업을 추가·완료·삭제하는 할 일 앱입니다. 이 선택 실습에서는 React로 화면과 상태를 이어서 만듭니다.
기본 데모 파일을 정리하고 이후 React 과정에서 계속 사용할 최소 TaskFlow 화면을 만듭니다.
선택: 연재 프로젝트와 전체 자료
연재 프로젝트를 이어 만드는 분을 위한 자료입니다. 이 글의 개념과 예제만 찾으셨다면 필요한 파일과 실행 방법만 펼쳐보세요.
TaskFlow 프로젝트 적용
TaskFlow 2단계 실행
시작 상태와 완성 결과를 바꾸어 본문에서 적용한 화면과 동작을 비교하세요.
예제 크게 보기 (새 탭)시작 체크포인트: 이전: React 학습 순서 컴포넌트 props state부터 상태관리까지의 완료 상태에서 이어갑니다.
이전 회차 완료 ZIP으로 시작하기. 새 폴더에 풀어 현재 회차 완료본과 나란히 비교합니다.
이전 완료본과 달라진 파일: package.json, src/App.tsx, src/index.css. 아래 변경 설명을 따라 수정하고 전체 코드의 같은 파일과 대조합니다.
완료 코드 ZIP 다운로드 — step-02-vite-base
이전 체크포인트
step-01-first-run
현재 상태
Vite 기본 프로젝트가 실행되며 App.tsx에 TaskFlow 시작 문구만 있습니다.
이번 목표
기본 데모 파일을 정리하고 이후 React 과정에서 계속 사용할 최소 TaskFlow 화면을 만듭니다.
Before
Vite 기본 데모 또는 최소 시작 문구
After
TaskFlow
오늘 할 일을 하나씩 정리해 보세요.
작업 목록은 다음 회차부터 컴포넌트로 분리합니다.
실행 확인
npm run dev
npm run build
개발 화면이 정상적으로 보이고 build가 성공하면 이번 단계는 완료입니다.
step-02-vite-base
전체 코드 뷰어의 모든 파일은 다운로드 ZIP과 같습니다. ZIP은 독립 실행할 수 있는 완료 시점의 코드입니다. Node.js 22.12 이상에서 npm install 후 npm run dev로 실행하고, npm run build로 검사합니다.
전체 파일·코드 보기
실습 프로젝트 전체 코드
index.html
<!doctype html>
<html lang="ko"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>TaskFlow</title></head><body><div id="root"></div><script type="module" src="/src/main.tsx"></script></body></html>
package.json
{
"name": "taskflow-step-02-vite-base",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": {
"node": ">=22.12.0"
},
"scripts": {
"dev": "vite --host 127.0.0.1",
"build": "tsc --noEmit && vite build",
"preview": "vite preview --host 127.0.0.1"
},
"dependencies": {
"react": "19.3.0",
"react-dom": "19.3.0"
},
"devDependencies": {
"typescript": "7.0.2",
"vite": "8.3.0",
"@vitejs/plugin-react": "6.1.1",
"@types/react": "19.3.0",
"@types/react-dom": "19.3.0",
"@types/node": "26.6.2"
}
}
src/App.tsx
function App() {
return (
<main className="app">
<header>
<p className="eyebrow">React Learning Project</p>
<h1>TaskFlow</h1>
<p>오늘 할 일을 하나씩 정리해 보세요.</p>
</header>
<section>
<h2>작업 목록</h2>
<p>작업 목록은 다음 회차부터 컴포넌트로 분리합니다.</p>
</section>
</main>
);
}
export default App;
src/index.css
* {
box-sizing: border-box;
}
body {
margin: 0;
font-family: Arial, sans-serif;
color: #111;
background: #f5f5f5;
}
button,
input {
font: inherit;
}
.app {
width: min(720px, calc(100% - 32px));
margin: 48px auto;
}
.eyebrow {
margin: 0 0 8px;
color: #666;
font-size: 14px;
}
h1,
h2,
p {
margin-top: 0;
}
button, input, select { min-height: 44px; font: inherit; }
button, input, select { border: 1px solid #aaa; padding: 8px 12px; }
button { cursor: pointer; }
button:disabled { cursor: wait; opacity: .6; }
ul { list-style: none; padding: 0; display: grid; gap: 12px; }
.task-card { border: 1px solid #ccc; padding: 16px; display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.task-card__content, .task-card__actions { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
form, section { margin-block: 20px; }
input:not([type="checkbox"]), select { max-width: 100%; }
details { margin-block: 24px; } summary { cursor: pointer; min-height: 44px; }
body { overflow-wrap: anywhere; }
[role="dialog"], [data-radix-popper-content-wrapper] { --radius: 0; }
src/main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import './index.css';
import App from './App';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
);
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"lib": [
"ES2022",
"DOM",
"DOM.Iterable"
],
"module": "ESNext",
"moduleResolution": "Bundler",
"jsx": "react-jsx",
"strict": true,
"skipLibCheck": true,
"noEmit": true,
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"types": [
"vite/client"
],
"paths": {
"@/*": [
"./src/*"
]
}
},
"include": [
"src",
"vite.config.ts"
]
}
vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({ plugins: [react()] });
글 소개·학습 준비·전체 목차

React · 2/32 · TaskFlow 누적 실습
React Vite 사용법 Vite 8 프로젝트 생성 실행 빌드
React · 2 / 32 · 필수 학습 · Vite 환경
React 프로젝트는 Vite의 react-ts 템플릿으로 생성하고, 개발 서버에서 화면을 확인한 뒤 빌드 결과를 점검할 수 있습니다. 이 글은 프로젝트 생성부터 기본 파일 구조와 dev·build·preview의 차이까지 설명합니다. 아직 프로젝트를 만들지 않아도 아래 준비 단계부터 따라갈 수 있습니다.
상단에서는 Vite 사용법만 독립적으로 설명하고, 하단에서는 1회차에서 만든 TaskFlow를 학습용 베이스 프로젝트로 정리합니다.
바로 확인하기: 프로젝트 생성·설치 → 개발 서버와 빌드 명령 → 화면 수정과 빌드 결과 비교 순서로 진행합니다. 이전 TaskFlow ZIP 없이 새 프로젝트만으로 확인할 수 있습니다.
이번 글에서 배우는 내용
- Vite가 React 프로젝트에서 맡는 역할
- react-ts 템플릿의 기본 파일 구조
- index.html → main.tsx → App.tsx 렌더링 흐름
- package.json의 scripts
- npm run dev, build, preview의 차이
- TaskFlow 기본 파일을 정리하는 방법
먼저 알아야 할 내용
Node.js와 npm이 필요합니다. 이 글의 실습 기준은 Node.js 22.12 이상입니다. HTML·JavaScript 기본 문법을 알고 있으면 파일 연결을 이해하기 쉽습니다. 새 프로젝트가 없는 독자는 아래 명령으로 바로 시작할 수 있습니다.
npm create vite@latest taskflow -- --template react-ts
cd taskflow
npm install
이미 이전 글에서 프로젝트를 만든 경우 새로 생성하지 않고 그대로 사용합니다.
목차
다음 학습
다음 글에서는 App.tsx에 모여 있는 화면을 Header, TaskList, TaskItem으로 나누면서 React 컴포넌트의 역할과 재사용 기준을 배웁니다.
공식 문서
이 글이 도움이 되었나요?
읽음 기록
읽음 — / 전체 33개 · 필수 27개
새 글 받아보기
RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.