/api
└── hello.ts → GET /api/hello
└── users/
└── [id].ts → GET /api/users/123 (동적 라우트)// api/hello.ts
// 만약 동적으로 하고 싶다면 api/post/[id].ts 형식으로 지정하면 된다.
import type { VercelRequest, VercelResponse } from '@vercel/node';
export default function handler(req: VercelRequest, res: VercelResponse) {
res.status(200).json({ message: 'Hello!' });
}// app.ts
const response = await fetch('/api/hello');
const data = await response.json();
console.log(data.message);// server/server.cjs
// 아키텍쳐 구조는 분명 express.js의 자율적인 구조
const app = express();
// 프로젝트 루트 경로에서 dist 폴더 제공
const distPath = path.resolve(__dirname, "../dist"); // 절대 경로 사용
app.use(express.static(distPath));
app.get("/space/join/:id", async (req, res) => {
const encryptedId = req.params.id;
const filePath = path.join(distPath, "index.html"); // dist 경로에 있는 index.html 사용
let html;
...
(이하 코드 생략)// vercel.json
{
"version": 2, // 1은 deprecated라서 2버젼이 고정이라고 생각하면 된다.
"builds": [
{
"src": "server/server.cjs",
"use": "@vercel/node"
} // Express 서버를 서버리스 함수로 변환한다,
],
"routes": [
{
"src": "/space/join/(.*)",
"dest": "/server/server.cjs"
}, // 이 경로로 오는 요청만 서버리스 함수로 보낸다.
]
}[일반 서버]
서버 시작 → 계속 대기 중 → 요청 처리 → 계속 대기 중...
(24시간 프로세스가 살아있음)
[서버리스]
요청 들어옴 → 함수 생성 → 요청 처리 → 함수 종료
(요청이 없으면 아무것도 없음)
[콜드 스타트] 첫 요청 or 오래 쉰 후
컨테이너 생성 + 코드 로드 + 실행 → 느림 (수백ms ~ 수초)
[웜 스타트] 연속 요청
이미 떠있는 컨테이너 재사용 → 빠름1. 사용자가 /space/join/abc 요청
↓
2. Vercel 엣지 네트워크가 요청 수신
↓
3. routes 규칙 확인 → server.cjs 매핑됨
↓
4. AWS Lambda 위에서 컨테이너 생성 (콜드 스타트)
↓
5. server.cjs 코드 로드 & 실행
↓
6. 응답 반환
↓
7. 컨테이너 대기 (일정 시간 후 소멸)요청 A ─→ [컨테이너 1] 처리 후 종료
요청 B ─→ [컨테이너 2] 처리 후 종료
요청 C ─→ [컨테이너 1] 재사용 (웜 스타트)