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

기본 사용법

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

하위 명령어

API와 Web을 분리해서 빌드할 수 있습니다.
명령어설명
pnpm buildAPI + Web 전체 빌드 (기본, Web 디렉토리가 없으면 Web 빌드 스킵)
pnpm build apiAPI 프로젝트만 빌드
pnpm build webWeb 프로젝트만 빌드

빌드 과정

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

1. 기존 빌드 결과물 제거

이전 빌드의 잔여 파일을 깨끗하게 제거합니다.
✓ Build artifacts removed successfully.
제거되는 디렉토리:
  • dist/ - API 빌드 결과물
  • web/dist/ - Web 빌드 결과물
  • web-dist/ - 복사된 Web 결과물

2. API 빌드 설정 준비

API 빌드에 사용할 tsdown 설정 파일을 결정합니다.
// 우선순위
// 1. 프로젝트 루트의 tsdown.config.ts (커스텀 오버라이드)
// 2. Sonamu 기본 tsdown API 설정 (없을 경우)
커스텀 설정 사용:
# 프로젝트 루트에 tsdown.config.ts 생성
touch tsdown.config.ts
기본 설정 사용:
Using default tsdown API config from sonamu package...

3. API 프로젝트 빌드

TypeScript를 JavaScript로 컴파일합니다.
1

빌드 시작

📦 API Server Building production-ready API /path/to/project
2

컴파일 실행

bash tsc --noEmit && pnpm exec tsdown --config /path/to/tsdown.config.ts 빌드 도구: tsdown + OXC/Rolldown
3

완료

✓ build completed (2.5s) ✓ API build completed in 2.5s

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

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

빌드 시작

🌐 Web Application Building static web assets /path/to/project/web
2

Vite 빌드

bash vite build 정적 에셋을 최적화하고 번들링합니다.
3

파일 복사

bash web/dist → web-dist API 서버에서 서빙할 수 있도록 복사합니다.
4

완료

✓ build completed (8.2s) ✓ copy completed (0.1s) ✓ Web build completed in 8.3s
Web 빌드 결과물:
  • web/dist/ - 원본 빌드 결과
  • web-dist/ - API 서버에서 서빙할 복사본

빌드 설정

API 빌드 설정 커스터마이징

프로젝트 루트에 tsdown.config.ts 파일을 생성하여 기본 API 빌드를 오버라이드할 수 있습니다.
tsdown.config.ts
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
tsdown.config.ts 파일이 없으면 Sonamu가 제공하는 기본 API 빌드 설정을 사용합니다.

빌드 결과물

API 빌드 결과

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

Web 빌드 결과 (선택)

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

빌드 최적화

1. 타입 체크 분리

빌드 속도를 높이려면 타입 체크를 별도로 수행하세요.
# 타입 체크만 수행 (빠름)
pnpm tsc --noEmit

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

2. 증분 빌드

변경된 파일만 재빌드하려면 개발 서버를 사용하세요.
# 전체 빌드 (느림)
pnpm build

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

3. 캐시 활용

tsdown은 빌드 간 의존성 분석 결과를 재사용합니다.
# 첫 빌드 (느림)
pnpm build  # 5초

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

문제 해결

빌드 실패

문제: TypeScript 에러로 빌드 실패
Error: Cannot find module 'some-module'
해결:
# 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
해결:
# 기본 설정으로 복구
rm tsdown.config.ts
pnpm build

Web 빌드 실패

문제: Vite 빌드 에러
Error: Could not resolve './some-file'
해결:
# Web 프로젝트 디렉토리로 이동
cd web

# 의존성 확인
pnpm install

# Web만 빌드 테스트
pnpm build

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

빌드 후 실행

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

# 실행
pnpm start
프로덕션 실행의 특징:
  • 빠른 시작: 컴파일이 완료된 JavaScript 실행
  • 낮은 메모리: TypeScript 변환 오버헤드 없음
  • 소스맵 지원: 에러 발생 시 원본 파일 위치 표시

직접 실행

pnpm start 대신 Node.js로 직접 실행할 수도 있습니다:
node --enable-source-maps dist/index.js
옵션 설명:
  • --enable-source-maps: 에러 발생 시 원본 TypeScript 파일 위치 표시
  • dist/index.js: 빌드된 엔트리포인트

환경 변수 로드

환경 변수가 필요한 경우:
# 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 파일을 작성하여 워크플로우를 정의합니다.
.github/workflows/deploy.yml
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/
주요 단계 설명:
1

코드 체크아웃

actions/checkout@v3을 사용하여 저장소 코드를 가져옵니다.
2

pnpm 설치

pnpm/action-setup@v2로 pnpm 패키지 매니저를 설치합니다.
3

Node.js 설정

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

의존성 설치

pnpm install로 프로젝트 의존성을 설치합니다.
5

빌드

pnpm build로 프로덕션 빌드를 수행합니다.
6

배포

빌드 결과물을 서버로 업로드합니다. rsync, scp, FTP 등 다양한 방법 사용 가능.

테스트 추가

배포 전에 테스트를 실행하여 버그를 조기에 발견할 수 있습니다:
.github/workflows/deploy.yml
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 환경을 분리할 수 있습니다:
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
# 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를 사용합니다:
docker-compose.yml
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:
실행:
# 빌드 및 실행
docker-compose up --build

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

# 중지
docker-compose down

성능 비교

프로덕션 빌드는 개발 서버보다 훨씬 빠르고 효율적입니다.
측정 항목개발 서버프로덕션 빌드차이
시작 시간2-3초0.5초4-6배 빠름
메모리 사용200MB100MB50% 절감
요청 처리느림빠름2-3배 빠름
파일 크기원본압축됨30-50% 작음
프로덕션이 빠른 이유:
  1. 미리 컴파일됨: TypeScript를 실시간으로 변환하지 않음
  2. 코드 최적화: 불필요한 코드 제거, 압축
  3. HMR 오버헤드 없음: 파일 감시 및 재로딩 비용 없음
  4. 프로덕션 모드: Node.js와 의존성들이 최적화 모드로 실행

실제 성능 측정

개발 서버와 프로덕션 빌드의 성능을 직접 비교해보세요:
# 개발 서버 시작 시간 측정
time pnpm dev

# 프로덕션 빌드 + 시작 시간 측정
time (pnpm build && pnpm start)
API 응답 시간 비교:
# 개발 서버
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초

다음 단계

start

빌드된 서버 실행하기

dev

개발 서버로 돌아가기