출시·고도화 중
React 안내서 · 2/6
Vite의 react-ts 템플릿이 만든 폴더와 파일이 각각 어떤 역할을 하는지 살펴보고, 프로젝트가 커질 때 쓸 만한 폴더 구성과 설정 방법을 정리합니다.
my-app/
├── public/
│ └── vite.svg
├── src/
│ ├── assets/
│ │ └── react.svg
│ ├── App.css
│ ├── App.tsx
│ ├── index.css
│ └── main.tsx
├── eslint.config.js
├── index.html
├── package.json
├── tsconfig.json
├── tsconfig.app.json
├── tsconfig.node.json
└── vite.config.ts| 경로 | 역할 |
|---|---|
index.html | 앱의 진입점. Vite는 이 파일에서 출발해 스크립트를 찾습니다 |
src/main.tsx | React를 HTML의 #root 요소에 연결합니다 |
src/App.tsx | 최상위 컴포넌트 |
src/assets/ | 코드에서 import하는 이미지 · 글꼴. 빌드 때 파일 이름에 해시가 붙습니다 |
public/ | 가공 없이 그대로 복사되는 파일(파비콘, robots.txt 등) |
vite.config.ts | Vite 설정(플러그인, 경로 별칭, 개발 서버) |
tsconfig.*.json | 앱 코드용(app)과 설정 파일용(node)으로 나뉜 TypeScript 설정 |
eslint.config.js | ESLint 설정. React 훅 규칙이 포함되어 있습니다 |
다른 번들러와 달리 Vite에서는 index.html이 프로젝트 루트에 있고, 이 파일이 곧 진입점입니다. <script type="module">이 가리키는 src/main.tsx부터 의존성을 따라가며 모듈을 불러옵니다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>my-app</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>main.tsx는 react-dom/client의 createRoot로 #root 요소에 React 루트를 만들고 App을 그립니다. 앱 전체에 필요한 Provider(라우터, 데이터 요청 라이브러리, 테마 등)도 보통 이곳에서 감쌉니다.
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
}
}Vite는 빌드 속도를 위해 타입 검사를 하지 않고 코드 변환만 합니다. 그래서 build 스크립트는 먼저 tsc -b로 타입을 검사하고, 오류가 없을 때만 vite build를 실행합니다. preview는 빌드 결과물을 로컬에서 확인할 때 씁니다.
../../components/Button 같은 긴 상대 경로 대신 @/components/Button처럼 쓰고 싶다면 Vite와 TypeScript 양쪽에 별칭을 등록합니다.
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
resolve: {
alias: { "@": fileURLToPath(new URL("./src", import.meta.url)) },
},
server: { port: 3000 },
});{
"compilerOptions": {
"paths": { "@/*": ["./src/*"] }
}
}위 paths 설정은 앱 코드를 검사하는 tsconfig.app.json의 compilerOptions에 추가합니다. 설정 파일에서 node:url을 쓰려면 npm install -D @types/node가 필요할 수 있습니다.
Vite는 프로젝트 루트의 .env, .env.local, .env.production 같은 파일을 읽습니다. 이 가운데 VITE_로 시작하는 변수만 클라이언트 코드에 노출되며, import.meta.env로 읽습니다.
# .env.local (Git에 올리지 않습니다)
VITE_API_URL=http://localhost:8080const apiUrl = import.meta.env.VITE_API_URL;
const isDev = import.meta.env.DEV;이 값들은 빌드 시점에 코드에 그대로 박히므로 누구나 볼 수 있습니다. API 비밀 키 같은 비밀 값은 절대 VITE_ 변수에 넣지 말고 서버 쪽에서 다룹니다.
React는 폴더 구조를 강제하지 않습니다. 작은 앱은 src/components/ 하나로 충분하고, 커지면 기능(feature) 단위로 나누는 방식이 흔히 쓰입니다.
src/components/: 버튼, 모달처럼 여러 화면에서 쓰는 공용 컴포넌트src/features/<기능>/: 한 기능에 속한 컴포넌트, 훅, API 호출을 한곳에src/hooks/: 여러 기능에서 쓰는 사용자 정의 훅(useDebounce.ts 등)src/lib/: 화면과 무관한 함수, API 클라이언트src/pages/ 또는 src/routes/: 라우터를 쓸 때 페이지 단위 컴포넌트관례적으로 컴포넌트 파일은 UserCard.tsx처럼 파스칼 표기법(PascalCase)을, 훅은 useUser.ts처럼 use로 시작하는 이름을 씁니다. 스타일은 전역 CSS를 import하거나, 이름이 겹치지 않는 CSS Modules(Button.module.css)를 쓰거나, Tailwind CSS 같은 도구를 붙일 수 있습니다.
index.html이 진입점이고, src/main.tsx가 #root에 React 앱을 연결합니다.npm run build는 tsc -b로 타입을 검사한 뒤 vite build로 묶습니다.vite.config.ts와 tsconfig.app.json 두 곳에 등록합니다.VITE_ 환경 변수는 공개 값이므로 비밀을 넣지 않습니다.
댓글 0개
로그인 · 로그인하면 댓글을 남길 수 있습니다.
첫 댓글을 남겨 보세요.