pnpm build 명령어는 프로젝트를 프로덕션 환경에 배포할 수 있도록 최적화된 코드로 빌드합니다. TypeScript를 JavaScript로 컴파일하고, 불필요한 코드를 제거하여 실행 속도를 높입니다.
기본 사용법
빌드가 완료되면 dist 디렉토리에 최적화된 JavaScript 파일이 생성됩니다.
빌드 과정
빌드는 다음 단계로 진행됩니다:
1. 기존 빌드 결과물 제거
이전 빌드의 잔여 파일을 깨끗하게 제거합니다.
✓ Build artifacts removed successfully.
제거되는 디렉토리:
dist/ - API 빌드 결과물
web/dist/ - Web 빌드 결과물
web-build/ - 복사된 Web 결과물
2. SWC 설정 파일 준비
빌드에 사용할 SWC 설정 파일을 결정합니다.
// 우선순위
// 1. 프로젝트 루트의 .swcrc (커스텀 설정)
// 2. Sonamu 기본 .swcrc (없을 경우)
커스텀 설정 사용:
# 프로젝트 루트에 .swcrc 생성
touch .swcrc
기본 설정 사용:
Using default .swcrc from sonamu package...
3. API 프로젝트 빌드
TypeScript를 JavaScript로 컴파일합니다.
빌드 시작
📦 API Server
Building production-ready API
/path/to/project
컴파일 실행
swc src -d dist --config-file .swcrc
빌드 도구: SWC - Rust 기반 초고속 TypeScript 컴파일러완료
✓ build completed (2.5s)
✓ API build completed in 2.5s
4. Web 프로젝트 빌드 (선택)
Web 프로젝트가 있는 경우 빌드하고 API 프로젝트로 복사합니다.
빌드 시작
🌐 Web Application
Building static web assets
/path/to/project/web
파일 복사
API 서버에서 서빙할 수 있도록 복사합니다. 완료
✓ build completed (8.2s)
✓ copy completed (0.1s)
✓ Web build completed in 8.3s
Web 빌드 결과물:
web/dist/ - 원본 빌드 결과
web-build/ - API 서버에서 서빙할 복사본
빌드 설정
SWC 설정 커스터마이징
프로젝트 루트에 .swcrc 파일을 생성하여 빌드를 커스터마이징할 수 있습니다.
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": false,
"decorators": true
},
"target": "es2022",
"loose": false,
"externalHelpers": false,
"keepClassNames": true,
"transform": {
"legacyDecorator": true,
"decoratorMetadata": true
}
},
"module": {
"type": "es6"
},
"sourceMaps": true
}
주요 옵션:
| 옵션 | 설명 | 기본값 |
|---|
target | 컴파일 타겟 | es2022 |
decorators | 데코레이터 지원 | true |
sourceMaps | 소스맵 생성 | true |
keepClassNames | 클래스명 보존 | true |
.swcrc 파일이 없으면 Sonamu가 제공하는 최적화된 기본 설정을 사용합니다.
빌드 결과물
API 빌드 결과
📁dist/
📁practices/ - Practice 스크립트
특징:
- TypeScript → JavaScript 변환
- 데코레이터 변환 완료
- 소스맵 포함 (
.js.map)
- Import 경로 해석 완료
Web 빌드 결과 (선택)
📁web-build/
📄HTMLindex.html - HTML 엔트리
특징:
- 코드 압축 (minification)
- 에셋 해싱 (cache busting)
- Tree shaking (사용하지 않는 코드 제거)
빌드 최적화
1. 타입 체크 분리
빌드 속도를 높이려면 타입 체크를 별도로 수행하세요.
# 타입 체크만 수행 (빠름)
pnpm tsc --noEmit
# 빌드만 수행 (타입 체크 없음)
pnpm build
2. 증분 빌드
변경된 파일만 재빌드하려면 개발 서버를 사용하세요.
# 전체 빌드 (느림)
pnpm build
# HMR 개발 서버 (빠름)
pnpm dev
3. 캐시 활용
SWC는 자동으로 빌드 캐시를 사용합니다.
# 첫 빌드 (느림)
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
SWC 설정 에러
문제: .swcrc 설정 오류
Error: Invalid .swcrc configuration
해결:
# 기본 설정으로 복구
rm .swcrc
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초
다음 단계