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๋ฅผ ์ฌ์ฉํ๋ฉด ์ผ๊ด๋ ์คํ ํ๊ฒฝ์ ๋ณด์ฅํ ์ ์์ต๋๋ค. ๊ฐ๋ฐ, ์คํ
์ด์ง, ํ๋ก๋์
๋ชจ๋ ๊ฐ์ ํ๊ฒฝ์์ ์คํ๋ฉ๋๋ค.
# 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์ด
๋ค์ ๋จ๊ณ
start
๋น๋๋ ์๋ฒ ์คํํ๊ธฐ
dev
๊ฐ๋ฐ ์๋ฒ๋ก ๋์๊ฐ๊ธฐ