개발 slecs

빌드 타임 어드민 DB 의존성을 stub으로 분리해 빌드 오류 해결

목차

빌드 파이프라인이 admin_db 의존성을 만날 때마다 터지던 문제를 오늘 정리했다.

왜 stub이 필요했나

db.ts가 admin 전용 DB 연결을 직접 import하는 구조였고, 이 파일을 참조하는 컴포넌트들(MobonSlot.astro, PostMetrics.astro)이 정적 빌드 타임에도 해당 연결을 시도하고 있었다. SSR 런타임에서만 필요한 의존성이 빌드 단계까지 끌려 들어오는 전형적인 패턴이다.

문제는 여기서 끝이 아니었다. rss.xml.jssitemap-index.xml.ts 같은 정적 생성 페이지들도 결국 같은 import 체인 위에 얹혀 있었다. RSS 피드나 사이트맵은 DB 접근이 전혀 필요 없는데, 빌드 단계에서 admin_db 연결 실패로 인해 덩달아 죽어버리는 상황이었다. author/money-team.astro도 마찬가지였다.

팀 입장에서 이건 꽤 치명적이다. 로컬 개발 환경이나 CI에서 admin DB 크리덴셜이 없는 경우(당연히 그래야 하는 경우가 많다), 전체 빌드가 뻗어버린다. 신규 팀원이 로컬 세팅할 때마다 "왜 빌드가 안 되냐"는 질문이 나올 수밖에 없는 구조.

작업 내용

파일 변경 방향
src/lib/db.ts admin_db 연결을 stub 처리 — 빌드 타임에는 null/mock으로 대체
src/components/MobonSlot.astro db 의존성 분리, stub 경계 내에서 동작하도록 수정
src/components/PostMetrics.astro 동일하게 stub 대응, 빌드 타임 렌더링 안전하게 처리
src/pages/author/money-team.astro admin_db 직접 참조 제거 또는 guard 추가
src/pages/rss.xml.js DB import 체인 끊기
src/pages/sitemap-index.xml.ts DB import 체인 끊기

db.ts에서의 stub 패턴은 대략 이런 식이다:

// before: 빌드 타임에도 실제 연결 시도
import { adminPool } from './admin_db'

// after: 환경 분기 또는 런타임 lazy import
const getAdminDb = async () => {
  if (import.meta.env.SSR) {
    const { adminPool } = await import('./admin_db')
    return adminPool
  }
  return null
}

컴포넌트 레벨에서도 비슷하게, Astro.request 컨텍스트 안에서만 DB를 실제로 불러오도록 범위를 좁혔다. 빌드 타임 렌더링 중엔 빈 상태나 fallback을 보여주는 방식.

회고

솔직히 이런 문제는 초기 설계 시점에서 "어떤 컴포넌트가 런타임 의존성을 갖는지" 명확히 구분했어야 했다. Astro처럼 정적/SSR 혼합 빌드를 하는 프레임워크에서는 이 경계가 특히 중요하다. 컴포넌트가 DB에 접근한다는 사실이 명시적으로 드러나지 않으면, 나중에 해당 컴포넌트를 다른 페이지에 갖다 붙이는 사람이 "왜 빌드가 터지지?"를 한참 디버깅하게 된다.

팀 리딩 관점에서 더 신경 쓰이는 부분은, 이런 암묵적 의존성이 코드리뷰 때 잘 안 잡힌다는 거다. 컴포넌트 파일만 보면 별 문제 없어 보이고, 실제로 빌드를 돌려봐야 터지는 경우가 많다. 앞으로는 admin_db를 건드리는 모듈은 파일 상단에 주석이든 타입이든 명시적으로 "이 모듈은 SSR only" 표시를 달기로 했다. 컨벤션 하나가 나중에 디버깅 시간 몇 시간을 아껴준다.

RSS랑 sitemap이 DB 의존성 때문에 안 나온다는 건 SEO 쪽에서도 직격이라 이번에 빠르게 처리한 거지만, 근본적으로는 의존성 그래프를 좀 더 자주 들여다봐야겠다는 교훈이 남는다.


다음은 stub 처리된 컴포넌트들에 실제 데이터 패칭 로직을 제대로 붙이는 작업이다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.