마크다운쇼(Marp Editor) 만들기 (3) - 배포
마크다운쇼(Marp Editor) 만들기 (3) - 배포
마크다운쇼(Marp Editor) 만들기 (2) - 개발이 완료된 프로젝트를 Vercel에 배포하는 과정
배포 환경
| 항목 | 값 |
|---|---|
| 플랫폼 | Vercel |
| 프레임워크 | Next.js 15 |
| 런타임 | Node.js 20 (Edge 호환) |
| 도메인 | Vercel 기본 도메인 |
Vercel 배포 설정
1. 프로젝트 연결
# Vercel CLI 설치
npm i -g vercel
# 프로젝트 연결 및 배포
vercel
GitHub 저장소를 연결하면 main 브랜치 푸시 시 자동 배포됩니다.
2. vercel.json 설정
{
"framework": "nextjs",
"buildCommand": "npm run build",
"outputDirectory": ".next"
}
3. 환경 변수
이 프로젝트는 외부 API 없이 클라이언트 사이드로 동작하므로 별도의 환경 변수가 필요하지 않습니다.
서버리스 제약 극복
문제: Puppeteer 사용 불가
처음에는 서버 사이드에서 Puppeteer로 PDF를 생성하려 했습니다.
// 원래 계획 (실패)
import puppeteer from 'puppeteer-core';
import chromium from '@sparticuz/chromium';
export async function generatePDF(html: string) {
const browser = await puppeteer.launch({
executablePath: await chromium.executablePath(),
// ...
});
}
하지만 Vercel 서버리스 환경에서 spawn ENOEXEC 에러가 발생했습니다. Chromium 바이너리가 제대로 실행되지 않는 문제입니다.
해결: 클라이언트 사이드 내보내기
PDF: 브라우저 인쇄 다이얼로그 활용
- 장점: Marp CSS가 완벽하게 적용됨
- 장점: 서버 부하 없음
- 단점: 사용자가 “PDF로 저장” 선택 필요
PPTX: pptxgenjs로 클라이언트에서 직접 생성
- 장점: 네이티브 텍스트로 편집 가능
- 장점: 서버 의존성 없음
// 현재 구현 (클라이언트 사이드)
const handleExportPDF = async () => {
const { exportToPDFViaPrint } = await import('@/lib/export-pdf');
await exportToPDFViaPrint(markdown);
};
const handleExportPPTX = async () => {
const { exportToPPTXNative } = await import('@/lib/export-pptx');
await exportToPPTXNative(markdown);
};
빌드 최적화
Dynamic Import로 번들 분리
PDF/PPTX 라이브러리는 용량이 크므로 필요할 때만 로드합니다.
// 동적 임포트로 초기 로딩 최적화
const handleExportPDF = async () => {
const { exportToPDFViaPrint } = await import('@/lib/export-pdf');
await exportToPDFViaPrint(markdown);
};
빌드 결과
Route (app)
┌ ○ / (Static)
├ ○ /_not-found (Static)
└ ƒ /api/export (Dynamic)
○ (Static) prerendered as static content
ƒ (Dynamic) server-rendered on demand
메인 페이지는 정적으로 빌드되어 CDN에서 빠르게 서빙됩니다.
배포 파이프라인
[코드 작성] → [커밋/푸시] → [Vercel 자동 감지]
↓
[빌드 & 배포]
↓
[프리뷰 URL 생성]
↓
[프로덕션 배포]
프리뷰 배포
PR을 열면 자동으로 프리뷰 환경이 생성됩니다.
https://marp-editor-git-feature-xxx.vercel.app
프로덕션 배포
main 브랜치에 머지되면 자동으로 프로덕션에 배포됩니다.
모니터링
Vercel 대시보드에서 확인 가능한 항목:
- 빌드 로그: 빌드 성공/실패 여부
- 함수 로그: API 호출 로그
- 분석: 방문자 수, 페이지 조회 수
- 성능: Core Web Vitals
트러블슈팅
1. 폰트 로딩 이슈
Marp 슬라이드에서 한글 폰트가 제대로 표시되지 않는 문제가 있었습니다.
해결: Google Fonts를 HTML에 직접 포함
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@300;400;500;600;700&display=swap" rel="stylesheet">
2. SVG foreignObject 렌더링
html2canvas로 SVG를 캡처할 때 foreignObject 내부 요소가 렌더링되지 않는 문제가 있었습니다.
해결: 브라우저 인쇄 기능 사용
브라우저 렌더링 엔진이 직접 처리하므로 모든 CSS가 정확하게 적용됩니다.
3. CORS 이슈
외부 이미지를 슬라이드에 포함할 때 CORS 에러가 발생할 수 있습니다.
권장: 이미지는 Base64로 인라인 삽입하거나 같은 도메인에서 호스팅
완성된 프로젝트

- 테스트 URL: https://md.takjakim.kr
🔗 연결 (백링크용)
- Part 1: 마크다운쇼(Marp Editor) 만들기 (1) - 기획
- Part 2: 마크다운쇼(Marp Editor) 만들기 (2) - 개발
- 허브: 개발 노트 시작하기