> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# build

> 프로덕션 빌드하기

export const FileItem = ({name, description, children}) => {
  const isLeaf = !children;
  const ext = getFileExtension(name);
  const extStyle = ext ? getExtensionStyle(ext) : null;
  return <div style={{
    marginLeft: "30px"
  }}>
      <div style={{
    display: "flex",
    alignItems: "center",
    gap: "4px"
  }}>
        <span style={{
    position: "relative",
    display: "inline-block"
  }}>
          <span className="file-icon">{isLeaf && !name.endsWith("/") ? "📄" : "📁"}</span>
          {ext && <span style={{
    position: "absolute",
    bottom: "2px",
    right: "0px",
    fontSize: "5px",
    fontWeight: "bold",
    padding: "1px",
    borderRadius: "2px",
    lineHeight: "1",
    minWidth: "8px",
    textAlign: "center",
    ...extStyle
  }}>
              {ext}
            </span>}
        </span>
        <code>{name}</code>
        {description && <span className="description"> - {description}</span>}
      </div>
      {children}
    </div>;
};

export const FileTree = ({children}) => {
  return <div className="file-tree" style={{
    margin: "20px",
    marginLeft: "-30px"
  }}>
      {children}
    </div>;
};

`pnpm build` 명령어는 프로젝트를 프로덕션 환경에 배포할 수 있도록 **최적화된 코드로 빌드**합니다. TypeScript를 JavaScript로 컴파일하고, 불필요한 코드를 제거하여 실행 속도를 높입니다.

## 기본 사용법

```bash theme={null}
pnpm build
```

빌드가 완료되면 `dist` 디렉토리에 최적화된 JavaScript 파일이 생성됩니다.

### 하위 명령어

API와 Web을 분리해서 빌드할 수 있습니다.

| 명령어              | 설명                                            |
| ---------------- | --------------------------------------------- |
| `pnpm build`     | API + Web 전체 빌드 (기본, Web 디렉토리가 없으면 Web 빌드 스킵) |
| `pnpm build api` | API 프로젝트만 빌드                                  |
| `pnpm build web` | Web 프로젝트만 빌드                                  |

<FileTree>
  <FileItem name="my-project/">
    <FileItem name="dist/" description="빌드 결과물">
      <FileItem name="index.js" />

      <FileItem name="models/" />

      <FileItem name="api/" />
    </FileItem>

    <FileItem name="src/" description="원본 소스" />

    <FileItem name="package.json" />
  </FileItem>
</FileTree>

## 빌드 과정

빌드는 다음 단계로 진행됩니다:

### 1. 기존 빌드 결과물 제거

이전 빌드의 잔여 파일을 깨끗하게 제거합니다.

```
✓ Build artifacts removed successfully.
```

**제거되는 디렉토리**:

* `dist/` - API 빌드 결과물
* `web/dist/` - Web 빌드 결과물
* `web-dist/` - 복사된 Web 결과물

### 2. API 빌드 설정 준비

API 빌드에 사용할 tsdown 설정 파일을 결정합니다.

```typescript theme={null}
// 우선순위
// 1. 프로젝트 루트의 tsdown.config.ts (커스텀 오버라이드)
// 2. Sonamu 기본 tsdown API 설정 (없을 경우)
```

**커스텀 설정 사용**:

```bash theme={null}
# 프로젝트 루트에 tsdown.config.ts 생성
touch tsdown.config.ts
```

**기본 설정 사용**:

```
Using default tsdown API config from sonamu package...
```

### 3. API 프로젝트 빌드

TypeScript를 JavaScript로 컴파일합니다.

<Steps>
  <Step title="빌드 시작">
    `📦 API Server Building production-ready API /path/to/project`
  </Step>

  <Step title="컴파일 실행">
    `bash tsc --noEmit && pnpm exec tsdown --config /path/to/tsdown.config.ts ` **빌드 도구**:
    tsdown + OXC/Rolldown
  </Step>

  <Step title="완료">`✓ build completed (2.5s) ✓ API build completed in 2.5s`</Step>
</Steps>

### 4. Web 프로젝트 빌드 (선택)

Web 프로젝트가 있는 경우 빌드하고 API 프로젝트로 복사합니다.

<Steps>
  <Step title="빌드 시작">
    `🌐 Web Application Building static web assets /path/to/project/web`
  </Step>

  <Step title="Vite 빌드">`bash vite build ` 정적 에셋을 최적화하고 번들링합니다.</Step>

  <Step title="파일 복사">
    `bash web/dist → web-dist ` API 서버에서 서빙할 수 있도록 복사합니다.
  </Step>

  <Step title="완료">
    `✓ build completed (8.2s) ✓ copy completed (0.1s) ✓ Web build completed in 8.3s`
  </Step>
</Steps>

**Web 빌드 결과물**:

* `web/dist/` - 원본 빌드 결과
* `web-dist/` - API 서버에서 서빙할 복사본

## 빌드 설정

### API 빌드 설정 커스터마이징

프로젝트 루트에 `tsdown.config.ts` 파일을 생성하여 기본 API 빌드를 오버라이드할 수 있습니다.

```ts title="tsdown.config.ts" theme={null}
import { defineConfig } from "tsdown";

export default defineConfig({
  clean: true,
  entry: {
    index: "src/index.ts",
  },
  format: "esm",
  platform: "node",
  sourcemap: "inline",
  target: "esnext",
  unbundle: true,
});
```

**주요 옵션**:

| 옵션           | 설명       | 기본값      |
| ------------ | -------- | -------- |
| `target`     | 컴파일 타겟   | `esnext` |
| `decorators` | 데코레이터 지원 | `true`   |
| `sourceMaps` | 소스맵 생성   | `inline` |
| `unbundle`   | 파일 구조 유지 | `true`   |

<Tip>`tsdown.config.ts` 파일이 없으면 Sonamu가 제공하는 기본 API 빌드 설정을 사용합니다.</Tip>

## 빌드 결과물

### API 빌드 결과

<FileTree>
  <FileItem name="dist/">
    <FileItem name="index.js" description="엔트리포인트" />

    <FileItem name="models/" description="Model 파일들">
      <FileItem name="user.model.js" />

      <FileItem name="post.model.js" />
    </FileItem>

    <FileItem name="api/" description="API 로직">
      <FileItem name="sonamu.js" />
    </FileItem>

    <FileItem name="entities/" description="Entity 정의">
      <FileItem name="entities.js" />
    </FileItem>

    <FileItem name="practices/" description="Practice 스크립트">
      <FileItem name="p1-test.js" />
    </FileItem>
  </FileItem>
</FileTree>

**특징**:

* TypeScript → JavaScript 변환
* 데코레이터 변환 완료
* 소스맵 포함 (`.js.map`)
* Import 경로 해석 완료

### Web 빌드 결과 (선택)

<FileTree>
  <FileItem name="web-dist/">
    <FileItem name="index.html" description="HTML 엔트리" />

    <FileItem name="assets/" description="최적화된 에셋">
      <FileItem name="index-abc123.js" />

      <FileItem name="index-def456.css" />
    </FileItem>

    <FileItem name="favicon.ico" />
  </FileItem>
</FileTree>

**특징**:

* 코드 압축 (minification)
* 에셋 해싱 (cache busting)
* Tree shaking (사용하지 않는 코드 제거)

## 빌드 최적화

### 1. 타입 체크 분리

빌드 속도를 높이려면 타입 체크를 별도로 수행하세요.

```bash theme={null}
# 타입 체크만 수행 (빠름)
pnpm tsc --noEmit

# 빌드만 수행 (타입 체크 없음)
pnpm build
```

### 2. 증분 빌드

변경된 파일만 재빌드하려면 개발 서버를 사용하세요.

```bash theme={null}
# 전체 빌드 (느림)
pnpm build

# HMR 개발 서버 (빠름)
pnpm dev
```

### 3. 캐시 활용

tsdown은 빌드 간 의존성 분석 결과를 재사용합니다.

```bash theme={null}
# 첫 빌드 (느림)
pnpm build  # 5초

# 두 번째 빌드 (빠름)
pnpm build  # 2초
```

## 문제 해결

### 빌드 실패

**문제**: TypeScript 에러로 빌드 실패

```
Error: Cannot find module 'some-module'
```

**해결**:

```bash theme={null}
# 1. 타입 체크
pnpm tsc --noEmit

# 2. 의존성 확인
pnpm install

# 3. node_modules 재설치
rm -rf node_modules
pnpm install
```

### tsdown 설정 에러

**문제**: `tsdown.config.ts` 설정 오류

```
Error: Failed to load tsdown config
```

**해결**:

```bash theme={null}
# 기본 설정으로 복구
rm tsdown.config.ts
pnpm build
```

### Web 빌드 실패

**문제**: Vite 빌드 에러

```
Error: Could not resolve './some-file'
```

**해결**:

```bash theme={null}
# Web 프로젝트 디렉토리로 이동
cd web

# 의존성 확인
pnpm install

# Web만 빌드 테스트
pnpm build

# 루트로 돌아와 전체 빌드
cd ..
pnpm build
```

## 빌드 후 실행

빌드가 완료되면 `start` 명령어로 프로덕션 서버를 실행합니다.

```bash theme={null}
# 빌드
pnpm build

# 실행
pnpm start
```

**프로덕션 실행의 특징**:

* **빠른 시작**: 컴파일이 완료된 JavaScript 실행
* **낮은 메모리**: TypeScript 변환 오버헤드 없음
* **소스맵 지원**: 에러 발생 시 원본 파일 위치 표시

### 직접 실행

`pnpm start` 대신 Node.js로 직접 실행할 수도 있습니다:

```bash theme={null}
node --enable-source-maps dist/index.js
```

**옵션 설명**:

* `--enable-source-maps`: 에러 발생 시 원본 TypeScript 파일 위치 표시
* `dist/index.js`: 빌드된 엔트리포인트

### 환경 변수 로드

환경 변수가 필요한 경우:

```bash theme={null}
# dotenv로 .env 파일 로드
node -r dotenv/config --enable-source-maps dist/index.js

# 또는 직접 지정
NODE_ENV=production PORT=3000 node --enable-source-maps dist/index.js
```

## CI/CD 설정

CI/CD 파이프라인을 구성하면 코드를 푸시할 때마다 **자동으로 빌드하고 배포**할 수 있습니다. GitHub Actions, GitLab CI, Jenkins 등 다양한 도구를 사용할 수 있습니다.

### 왜 CI/CD가 필요한가?

| 이점         | 설명             |
| ---------- | -------------- |
| **자동화**    | 수동 빌드/배포 작업 제거 |
| **일관성**    | 항상 같은 방식으로 빌드  |
| **빠른 피드백** | 빌드 실패를 즉시 확인   |
| **안전성**    | 테스트 통과 후에만 배포  |
| **추적성**    | 모든 배포 기록 보존    |

### GitHub Actions

GitHub Actions는 GitHub에 통합된 CI/CD 플랫폼입니다. `.github/workflows/` 디렉토리에 YAML 파일을 작성하여 워크플로우를 정의합니다.

```yaml title=".github/workflows/deploy.yml" theme={null}
name: Deploy

on:
  push:
    branches: [main] # main 브랜치에 푸시할 때 실행

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      # 1. 코드 체크아웃
      - uses: actions/checkout@v3

      # 2. pnpm 설치
      - uses: pnpm/action-setup@v2
        with:
          version: 8

      # 3. Node.js 설정 (pnpm 캐시 활성화)
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: "pnpm"

      # 4. 의존성 설치
      - run: pnpm install

      # 5. 빌드
      - run: pnpm build

      # 6. 배포
      - name: Deploy
        run: |
          # rsync로 빌드 결과물 업로드
          rsync -avz dist/ server:/app/
```

**주요 단계 설명**:

<Steps>
  <Step title="코드 체크아웃">`actions/checkout@v3`을 사용하여 저장소 코드를 가져옵니다.</Step>

  <Step title="pnpm 설치">`pnpm/action-setup@v2`로 pnpm 패키지 매니저를 설치합니다.</Step>

  <Step title="Node.js 설정">
    `actions/setup-node@v3`으로 Node.js를 설치하고 pnpm 캐시를 활성화합니다. 캐시 덕분에 의존성 설치가
    훨씬 빠릅니다.
  </Step>

  <Step title="의존성 설치">`pnpm install`로 프로젝트 의존성을 설치합니다.</Step>

  <Step title="빌드">`pnpm build`로 프로덕션 빌드를 수행합니다.</Step>

  <Step title="배포">
    빌드 결과물을 서버로 업로드합니다. rsync, scp, FTP 등 다양한 방법 사용 가능.
  </Step>
</Steps>

### 테스트 추가

배포 전에 테스트를 실행하여 버그를 조기에 발견할 수 있습니다:

```yaml title=".github/workflows/deploy.yml" theme={null}
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2
        with:
          version: 8
      - uses: actions/setup-node@v3
        with:
          node-version: 20
          cache: "pnpm"
      - run: pnpm install
      - run: pnpm test # 테스트 실행

  build:
    needs: test # 테스트 통과 후에만 빌드
    runs-on: ubuntu-latest
    steps:
      # ... 빌드 스텝
```

### 환경별 배포

Staging과 Production 환경을 분리할 수 있습니다:

```yaml theme={null}
on:
  push:
    branches:
      - develop # Staging으로 배포
      - main # Production으로 배포

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      # ... 빌드 스텝

      - name: Deploy to Staging
        if: github.ref == 'refs/heads/develop'
        run: |
          rsync -avz dist/ staging-server:/app/

      - name: Deploy to Production
        if: github.ref == 'refs/heads/main'
        run: |
          rsync -avz dist/ prod-server:/app/
```

### Docker

Docker를 사용하면 **일관된 실행 환경**을 보장할 수 있습니다. 개발, 스테이징, 프로덕션 모두 같은 환경에서 실행됩니다.

```dockerfile title="Dockerfile" theme={null}
# Stage 1: 빌드 스테이지
FROM node:20-alpine AS builder

WORKDIR /app

# pnpm 설치
RUN npm install -g pnpm

# 의존성 설치 (package.json만 먼저 복사하여 캐시 활용)
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --frozen-lockfile

# 소스 코드 복사
COPY . .

# 빌드
RUN pnpm build

# Stage 2: 프로덕션 스테이지
FROM node:20-alpine

WORKDIR /app

# pnpm 설치
RUN npm install -g pnpm

# 프로덕션 의존성만 설치
COPY package.json pnpm-lock.yaml ./
RUN pnpm install --prod --frozen-lockfile

# 빌드 결과물 복사
COPY --from=builder /app/dist ./dist

# 환경 변수
ENV NODE_ENV=production

# 포트 노출
EXPOSE 3000

# 실행
CMD ["pnpm", "start"]
```

**멀티스테이지 빌드의 장점**:

| 장점            | 설명                    |
| ------------- | --------------------- |
| **작은 이미지 크기** | 빌드 도구를 최종 이미지에서 제외    |
| **빠른 배포**     | 작은 이미지는 pull/push가 빠름 |
| **보안**        | 불필요한 개발 도구 제거         |
| **레이어 캐싱**    | 의존성이 변경되지 않으면 재사용     |

### Docker Compose

데이터베이스와 함께 실행하려면 Docker Compose를 사용합니다:

```yaml title="docker-compose.yml" theme={null}
version: "3.8"

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
    depends_on:
      - db

  db:
    image: pgvector/pgvector:pg16
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
```

**실행**:

```bash theme={null}
# 빌드 및 실행
docker-compose up --build

# 백그라운드 실행
docker-compose up -d

# 중지
docker-compose down
```

## 성능 비교

프로덕션 빌드는 개발 서버보다 **훨씬 빠르고 효율적**입니다.

| 측정 항목  | 개발 서버 | 프로덕션 빌드 | 차이            |
| ------ | ----- | ------- | ------------- |
| 시작 시간  | 2-3초  | 0.5초    | **4-6배 빠름**   |
| 메모리 사용 | 200MB | 100MB   | **50% 절감**    |
| 요청 처리  | 느림    | 빠름      | **2-3배 빠름**   |
| 파일 크기  | 원본    | 압축됨     | **30-50% 작음** |

**프로덕션이 빠른 이유**:

1. **미리 컴파일됨**: TypeScript를 실시간으로 변환하지 않음
2. **코드 최적화**: 불필요한 코드 제거, 압축
3. **HMR 오버헤드 없음**: 파일 감시 및 재로딩 비용 없음
4. **프로덕션 모드**: Node.js와 의존성들이 최적화 모드로 실행

### 실제 성능 측정

개발 서버와 프로덕션 빌드의 성능을 직접 비교해보세요:

```bash theme={null}
# 개발 서버 시작 시간 측정
time pnpm dev

# 프로덕션 빌드 + 시작 시간 측정
time (pnpm build && pnpm start)
```

**API 응답 시간 비교**:

```bash theme={null}
# 개발 서버
curl -w "\n%{time_total}s\n" http://localhost:3000/api/users
# 예: 0.05초

# 프로덕션
curl -w "\n%{time_total}s\n" http://localhost:3000/api/users
# 예: 0.02초
```

## 다음 단계

<CardGroup cols={2}>
  <Card title="start" icon="play" href="/ko/tools-and-cli/sonamu-cli/start">
    빌드된 서버 실행하기
  </Card>

  <Card title="dev" icon="code" href="/ko/tools-and-cli/sonamu-cli/dev">
    개발 서버로 돌아가기
  </Card>
</CardGroup>
