pnpm build 명령어는 프로젝트를 프로덕션 환경에 배포할 수 있도록 최적화된 코드로 빌드합니다. TypeScript를 JavaScript로 컴파일하고, 불필요한 코드를 제거하여 실행 속도를 높입니다.
기본 사용법
빌드가 완료되면 dist 디렉토리에 최적화된 JavaScript 파일이 생성됩니다.
하위 명령어
API와 Web을 분리해서 빌드할 수 있습니다.
| 명령어 | 설명 |
|---|
pnpm build | API + Web 전체 빌드 (기본, Web 디렉토리가 없으면 Web 빌드 스킵) |
pnpm build api | API 프로젝트만 빌드 |
pnpm build web | Web 프로젝트만 빌드 |
빌드 과정
빌드는 다음 단계로 진행됩니다:
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로 컴파일합니다.
빌드 시작
📦 API Server Building production-ready API /path/to/project
컴파일 실행
bash tsc --noEmit && pnpm exec tsdown --config /path/to/tsdown.config.ts 빌드 도구:
tsdown + OXC/Rolldown
완료
✓ build completed (2.5s) ✓ API build completed in 2.5s
4. Web 프로젝트 빌드 (선택)
Web 프로젝트가 있는 경우 빌드하고 API 프로젝트로 복사합니다.
빌드 시작
🌐 Web Application Building static web assets /path/to/project/web
Vite 빌드
bash vite build 정적 에셋을 최적화하고 번들링합니다.
파일 복사
bash web/dist → web-dist API 서버에서 서빙할 수 있도록 복사합니다.
완료
✓ 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 빌드를 오버라이드할 수 있습니다.
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/
주요 단계 설명:
코드 체크아웃
actions/checkout@v3을 사용하여 저장소 코드를 가져옵니다.
pnpm 설치
pnpm/action-setup@v2로 pnpm 패키지 매니저를 설치합니다.
Node.js 설정
actions/setup-node@v3으로 Node.js를 설치하고 pnpm 캐시를 활성화합니다. 캐시 덕분에 의존성 설치가
훨씬 빠릅니다.
의존성 설치
pnpm install로 프로젝트 의존성을 설치합니다.
빌드
pnpm build로 프로덕션 빌드를 수행합니다.
배포
빌드 결과물을 서버로 업로드합니다. 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를 사용하면 일관된 실행 환경을 보장할 수 있습니다. 개발, 스테이징, 프로덕션 모두 같은 환경에서 실행됩니다.
# 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를 사용합니다:
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배 빠름 |
| 메모리 사용 | 200MB | 100MB | 50% 절감 |
| 요청 처리 | 느림 | 빠름 | 2-3배 빠름 |
| 파일 크기 | 원본 | 압축됨 | 30-50% 작음 |
프로덕션이 빠른 이유:
- 미리 컴파일됨: TypeScript를 실시간으로 변환하지 않음
- 코드 최적화: 불필요한 코드 제거, 압축
- HMR 오버헤드 없음: 파일 감시 및 재로딩 비용 없음
- 프로덕션 모드: 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초
다음 단계