Bulletproof React

코헤·2026년 2월 16일

cohiChat

목록 보기
7/10

Bulletproof React

프로덕션 레벨의 확장 가능하고 유지보수하기 쉬운 React 애플리케이션 아키텍처

참고: alan2207/bulletproof-react


핵심 개념

1. Feature 기반 구조

기존 방식은 파일 유형별로 폴더를 나눔:

src/
├── components/    # 모든 컴포넌트
├── hooks/         # 모든 훅
├── utils/         # 모든 유틸
└── types/         # 모든 타입

문제점: Calendar 기능 수정하려면 4개 폴더를 돌아다녀야 함

Bulletproof 방식은 기능(feature) 단위로 폴더를 나눔:

src/
├── features/
│   ├── calendar/   # Calendar 관련 모든 것
│   ├── auth/       # 인증 관련 모든 것
│   └── chat/       # 채팅 관련 모든 것
└── ...

장점: Calendar 수정할 때 features/calendar/ 폴더만 보면 됨


폴더 구조

전체 구조

src/
├── app/                 # 애플리케이션 레이어 (라우터, 프로바이더)
├── assets/              # 정적 파일 (이미지, 폰트)
├── components/          # 공용 컴포넌트 (Button, Modal, Input 등)
├── config/              # 환경 설정
├── features/            # ⭐ 기능별 모듈 (핵심!)
├── hooks/               # 공용 훅
├── libs/                # 외부 라이브러리 설정 (axios, dayjs 등)
├── stores/              # 전역 상태 관리
├── types/               # 공용 타입
└── utils/               # 공용 유틸 함수

Feature 내부 구조

features/calendar/
├── api/                 # API 요청 함수, React Query 훅
│   ├── getCalendar.ts
│   ├── getBookings.ts
│   └── createBooking.ts
├── components/          # 이 기능에서만 쓰는 컴포넌트
│   ├── CalendarBody.tsx
│   ├── CalendarNavigator.tsx
│   └── BookingForm.tsx
├── hooks/               # 이 기능에서만 쓰는 훅
│   ├── useCalendarNavigation.ts
│   └── useBookings.ts
├── types/               # 이 기능에서만 쓰는 타입
│   └── index.ts
├── utils/               # 이 기능에서만 쓰는 유틸
│   ├── getCalendarDays.ts
│   └── checkAvailableDate.ts
└── index.ts             # ⭐ Public API (배럴 파일)

3가지 핵심 원칙

1. 단방향 의존성 (Unidirectional Flow)

shared(components, hooks, utils)
         ↓
      features
         ↓
        app
  • shared → 누구나 import 가능
  • features → shared만 import 가능, 다른 feature import 금지
  • app → 모든 것 import 가능

왜?

  • 순환 참조 방지
  • 코드 흐름 예측 가능
  • feature 간 결합도 낮춤

2. Feature 간 직접 import 금지

// ❌ 나쁜 예: feature에서 다른 feature import
// features/calendar/components/CalendarBody.tsx
import { useAuth } from '~/features/auth/hooks/useAuth';

// ✅ 좋은 예: app 레벨에서 조합
// app/routes/calendar.tsx
import { useAuth } from '~/features/auth';
import { Calendar } from '~/features/calendar';

function CalendarPage() {
  const { user } = useAuth();
  return <Calendar userId={user.id} />;
}

3. Public API (배럴 파일)

각 feature의 index.ts에서 외부에 노출할 것만 export:

// features/calendar/index.ts
// 컴포넌트
export { Calendar } from './components/Calendar';
export { BookingForm } from './components/BookingForm';

// 훅
export { useCalendarNavigation } from './hooks/useCalendarNavigation';
export { useBookings } from './hooks/useBookings';

// 타입
export type { IBooking, ITimeSlot } from './types';

외부에서는 index.ts를 통해서만 import:

// ✅ 좋은 예
import { Calendar, useBookings } from '~/features/calendar';

// ❌ 나쁜 예: 내부 경로 직접 import
import { Calendar } from '~/features/calendar/components/Calendar';

ESLint로 규칙 강제하기

.eslintrc.js에 추가:

module.exports = {
  rules: {
    'import/no-restricted-paths': [
      'error',
      {
        zones: [
          // features는 다른 features를 import 불가
          {
            target: './src/features',
            from: './src/features',
            except: ['./'],
          },
          // features는 app을 import 불가
          {
            target: './src/features',
            from: './src/app',
          },
        ],
      },
    ],
  },
};

cohi-chat 적용 예시

Before (분산된 구조)

src/
├── components/calendar/
│   ├── Body.tsx
│   └── Navigator.tsx
├── hooks/
│   ├── useBookings.ts
│   └── useCalendarNavigation.ts
├── libs/
│   └── bookings.ts
└── types/
    └── booking.d.ts

After (Bulletproof 구조)

src/
├── features/
│   └── calendar/
│       ├── api/
│       │   └── bookings.ts
│       ├── components/
│       │   ├── Body.tsx
│       │   └── Navigator.tsx
│       ├── hooks/
│       │   ├── useBookings.ts
│       │   └── useCalendarNavigation.ts
│       ├── types/
│       │   └── index.ts
│       └── index.ts
├── components/          # 공용만 남김
├── hooks/               # 공용만 남김
└── types/
    └── base.d.ts        # 공용 타입만 남김

언제 쓰면 좋을까?

상황추천
작은 프로젝트 (5개 이하 페이지)굳이 안 써도 됨
중간 규모 (5-20개 페이지)적용 추천
대규모 (20개+ 페이지, 팀 협업)필수

참고 자료

profile
하이하이

0개의 댓글