본문으로 건너뛰기
← 포트폴리오로 돌아가기
포트폴리오>개발>웹 개발
Active

White Place 블로그

2026Active

개발 포트폴리오와 기술 블로그를 하나의 사이트로 합치고 싶었습니다. Next.js 14 SSG와 React Three Fiber로 3D 인터랙션을 구현하고, Vercel에 자동 배포 파이프라인을 구성해 빌드 시간을 10초 이내로 유지하고 있습니다.

배경

개발 포트폴리오와 기술 블로그를 하나의 사이트로 합치고 싶었습니다. 기존에는 GitHub Pages에 Jekyll로 운영했지만, 3D 인터랙션이나 동적 필터링 같은 기능을 추가하기 어려웠습니다. 직접 설계한 디자인 시스템 위에서 자유롭게 실험할 수 있는 공간이 필요했습니다.

도전 과제

SSG와 인터랙티브 콘텐츠의 양립

정적 사이트 생성(SSG)의 빠른 로딩 속도를 유지하면서, React Three Fiber 기반의 3D 히어로 씬과 Framer Motion 애니메이션을 매끄럽게 통합해야 했습니다. 3D 컴포넌트는 서버 렌더링이 불가능하므로 dynamic import와 ssr: false 전략이 필수였습니다.

Glassmorphism 디자인 시스템

반투명 유리 질감의 UI를 CSS 변수 기반으로 체계화해야 했습니다. 다크 모드 전환 시에도 일관된 시각 경험을 보장해야 했고, backdrop-filter 성능 이슈와 Safari 호환성 문제를 해결해야 했습니다.

2단계 카테고리 시스템

블로그 포스트가 늘어나면서 단순한 태그 시스템으로는 부족했습니다. category + subcategory 2단계 분류 체계를 설계하고, 필터링과 브레드크럼 내비게이션에 일관되게 적용해야 했습니다.

해결 방법

아키텍처 결정

  • Next.js 14 App Router + SSG: generateStaticParams로 빌드 타임에 모든 페이지를 사전 생성
  • 3D = dynamic import only: ssr: false로 클라이언트에서만 Three.js 로드
  • CSS 변수 중심 디자인 시스템: --bg-primary, --glass-bg, --accent 등 토큰화된 변수로 테마 전환 지원
  • gray-matter + ReactMarkdown: 마크다운 파서와 렌더러를 분리해 빌드 타임 파싱, 클라이언트 렌더링 최적화

핵심 패턴

// 3D 컴포넌트는 항상 dynamic import
const HeroScene = dynamic(() => import("@/components/HeroScene"), {
  ssr: false,
  loading: () => <LoadingSkeleton />,
});
/* Glassmorphism 토큰 */
.glass {
  background: var(--glass-bg);
  backdrop-filter: blur(12px);
  border: 1px solid var(--glass-border);
}

성능 최적화

  • next/image로 모든 이미지 자동 WebP 변환 + lazy loading
  • Vercel Edge 배포로 전 세계 CDN 캐싱
  • 빌드 시간 10초 이내 유지 (ISR 불필요)

결과

  • 20+ 페이지 정적 생성 (블로그 + 포트폴리오 + 유틸리티)
  • 13편 블로그 포스트 마크다운 기반 작성
  • Lighthouse 90+ 전 카테고리 달성
  • 다크 모드 + Glassmorphism 일관된 디자인 시스템
  • Dark Place 별도 테마 사이트 (/dark) 운영

배운 점

SSG 기반 사이트에서도 3D 인터랙션과 풍부한 애니메이션을 충분히 구현할 수 있다는 것을 확인했습니다. 핵심은 서버/클라이언트 경계를 명확히 구분하는 것이었습니다.

CSS 변수 기반 디자인 시스템은 초기 설계에 시간이 걸리지만, 이후 다크 모드 추가나 테마 변경이 놀라울 정도로 간단해집니다. 하드코딩된 색상 값 하나 없이 전체 사이트의 색상을 변경할 수 있는 구조가 되었습니다.

다음에는 Lenis 스무스 스크롤과 더 정교한 페이지 전환 애니메이션을 추가해 프리미엄 경험을 완성할 계획입니다.

기술 스택

Next.jsThree.jsTypeScript

관련 포스트