SPA 프로젝트 진행 시 매번 같은 환경 설정에 많은 시간을 들이지 않기 위한 보일러플레이트입니다.
- 코어: React, Typescript
- 상태 관리: TanStack Query, Zustand
- 스타일링: SCSS(Sass)
- 패키지 매니저: PNPM
- 빌드: Vite
- 테스트:
- CI/CD:
src/
├── App.tsx # 메인 App 컴포넌트
├── AppRoutes.tsx # 라우트 설정
├── main.tsx # 진입점
├── assets/ # 이미지, 아이콘 등 정적 자원
│ └── react.svg
├── components/ # 재사용 가능한 UI 컴포넌트
├── containers/ # 로직과 상태를 포함하는 컨테이너
├── pages/ # 라우트와 매칭되는 페이지 컴포넌트
├── lib/
│ ├── api/ # API 통신 관련
│ │ ├── axiosInstance.ts # Axios 인스턴스 설정
│ │ └── queryClient.ts # React Query 설정
│ └── styles/ # 전역 스타일, 변수
│ ├── _color.scss # 색상 변수
│ ├── _mixin.scss # SCSS 믹스인
│ └── global.scss # 전역 스타일
pnpm installpnpm dev개발 서버는 http://localhost:5173에서 실행됩니다.
pnpm buildpnpm lintpnpm previewSCSS를 사용하여 모듈 방식의 스타일링을 적용합니다. classnames 라이브러리와 함께 사용하면 조건부 클래스 적용이 간편합니다.
예시:
// Button.module.scss
.button {
padding: 10px 20px;
border: none;
border-radius: 4px;
cursor: pointer;
&.primary {
background-color: $primary-color;
color: white;
}
&.secondary {
background-color: $secondary-color;
color: black;
}
}// Button.tsx
import cx from "classnames";
import styles from "./Button.module.scss";
interface ButtonProps {
variant?: "primary" | "secondary";
children: React.ReactNode;
}
export const Button = ({ variant = "primary", children }: ButtonProps) => {
return (
<button className={cx(styles.button, styles[variant])}>{children}</button>
);
};색상 변수:
lib/styles/_color.scss에서 프로젝트의 색상을 정의하고 전체에서 재사용합니다.
코드 품질과 일관성을 유지하기 위해 ESLint를 설정했습니다.
린트 검사 실행:
pnpm lint주요 규칙:
- TypeScript 문법 검사
- React Hooks 규칙 (exhaustive-deps 등)
- Import 정렬
- 코드 스타일 가이드
필요에 따라 eslint.config.js에서 규칙을 커스텀할 수 있습니다.
Axios와 React Query를 사용하여 API 통신을 관리합니다.
Axios 인스턴스 설정:
// lib/api/axiosInstance.ts
import axios from "axios";
const axiosInstance = axios.create({
baseURL: import.meta.env.VITE_API_BASE_URL || "http://localhost:3000",
timeout: 10000,
});
// 요청/응답 인터셉터 설정 가능
export default axiosInstance;React Query 설정:
// lib/api/queryClient.ts
import { QueryClient } from "@tanstack/react-query";
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 1000 * 60 * 5, // 5분
gcTime: 1000 * 60 * 10, // 10분
},
},
});API 호출 예시:
import { useQuery } from "@tanstack/react-query";
import axiosInstance from "@/lib/api/axiosInstance";
const fetchUsers = async () => {
const response = await axiosInstance.get("/users");
return response.data;
};
export const UserList = () => {
const { data, isLoading, error } = useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
});
if (isLoading) return <p>로딩 중...</p>;
if (error) return <p>에러 발생</p>;
return (
<ul>
{data?.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};-
라이브러리 추가/삭제
pnpm add <package-name> pnpm remove <package-name>
-
폴더 구조 수정
- 프로젝트 규모에 맞게 폴더 구조를 자유롭게 조정하세요.
- 예:
features구조 도입,hooks,utils폴더 추가 등
-
환경 변수 설정
.env파일 생성import.meta.env.VITE_*형식으로 접근
-
TypeScript 설정
tsconfig.json참고하여 필요에 따라 수정