quartz/components/Head.tsx 파일은 정적 사이트 생성기 Quartz에서 각 HTML 페이지의 <head> 태그를 구성하는 핵심 컴포넌트다. 이 파일은 Markdown 소스 파일의 frontmatter와 빌드 설정(cfg)을 조합하여 브라우저가 인식할 수 있는 메타데이터를 생성한다. 페이지의 구조화 데이터와 메타데이터가 만들어지는 지점은 이 컴포넌트의 렌더링 로직 내부에 위치한다.

페이지 제목과 설명의 우선순위

페이지의 제목(title)과 설명(description)은 서로 다른 소스에서 값을 가져오며, 특정 우선순위 규칙이 적용된다. 이 로직은 Head 함수의 시작 부분에서 정의된다.

const titleSuffix = cfg.pageTitleSuffix ?? ""
const title =
  (fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title) + titleSuffix
const description =
  fileData.frontmatter?.socialDescription ??
  fileData.frontmatter?.description ??
  unescapeHTML(fileData.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description)
  • 제목: 먼저 frontmatter의 title을 확인한다. 없으면 로캘(locale) 설정의 기본 제목을 사용한다. 마지막으로 cfg.pageTitleSuffix가 설정되어 있다면 이를 뒤에 붙인다.
  • 설명: socialDescription이 우선한다. 없으면 description을 사용한다. 이 두 값이 모두 없으면, Markdown 파일의 본문에서 추출된 fileData.description을 사용한다. 마지막으로 기본값을 사용한다.

Canonical URL과 구조화 데이터 판단

Quartz는 각 페이지의 고유 URL을 생성하고, 해당 페이지가 블로그 글인지 아닌지를 판단하여 구조화 데이터(JSON-LD)의 타입을 결정한다.

  • Canonical URL: canonicalUrl 함수는 baseUrl과 slug를 조합하여 절대 URL을 생성한다.
  • Article 판별: isArticlePage 함수는 frontmatter.type이 article 또는 post인지 확인하거나, 슬러그가 날짜 접두사(YYYY-MM-DD-)로 시작하는지 확인하여 블로그 글임을 식별한다.
export function isArticlePage(fileData: QuartzComponentProps["fileData"]): boolean {
  const slug = fileData.slug
  if (!slug || !fileData.frontmatter?.date) {
    return false
  }
  // ... (중략)
  // Existing posts use a date-prefixed slug. This keeps dated utility, policy,
  // and section landing pages from being mislabeled as BlogPosting objects.
  return ARTICLE_SLUG_PATTERN.test(slug)
}

이 판단 결과는 BlogPosting 또는 WebPage 스키마로 구조화 데이터를 주입하는 데 사용된다. 라이브 페이지의 JSON-LD를 확인하면 글 페이지는 "@type":"BlogPosting"으로 나온다.

RSS 피드 및 아이콘 링크

페이지의 루트 경로에 따라 RSS 피드 링크와 아이콘 경로가 동적으로 결정된다.

  • RSS 피드: ContentIndex 플러그인이 /index.xml에 피드를 생성하므로, Head 컴포넌트는 현재 페이지의 베이스 경로를 기준으로 index.xml 링크를 삽입한다. 이는 크롤러와 피드 리더가 피드를 발견할 수 있게 한다.
  • 아이콘: 404 페이지가 아닌 경우, 현재 페이지의 루트 경로에서 static/icon.png를 아이콘 경로로 설정한다.
const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!)
const iconPath = joinSegments(baseDir, "static/icon.png")
const rssPath = joinSegments(baseDir, "index.xml")

외부 리소스 및 OG 이미지

페이지에 필요한 CSS, JS, 그리고 추가적인 헤드 태그는 빌드 과정에서 수집된 externalResources 객체를 통해 주입된다.

  • CSS/JS: externalResources.css와 externalResources.js는 빌드 시 생성된 정적 파일 링크다.
  • OG 이미지: CustomOgImagesEmitterName 플러그인을 통해 생성된 OG 이미지 링크가 추가된다.
  • Google Fonts: googleFontHref와 googleFontSubsetHref 함수를 통해 폰트 리소스가 로드된다.
const { css, js, additionalHead } = externalResources

검증 절차: 메타데이터 생성 확인

quartz/components/Head.tsx의 로직이 실제로 메타데이터를 생성하는지 확인하려면 빌드된 HTML 파일을 직접 검토해야 한다.

  1. 빌드 실행: npx quartz build 명령을 실행한다.
  2. HTML 파일 열기: 빌드 출력 디렉토리(기본적으로 public)에서 임의의 .html 파일을 연다.
  3. <head> 태그 확인:
    • <title> 태그에 frontmatter의 제목과 suffix가 올바르게 결합되었는지 확인한다.
    • <meta name="description"> 태그에 socialDescription 또는 description이 입력되었는지 확인한다.
    • <link rel="canonical"> 태그에 올바른 절대 URL이 있는지 확인한다.
    • <link rel="alternate" type="application/rss+xml"> 태그에 RSS 피드 링크가 있는지 확인한다.
    • <script type="application/ld+json"> 태그에 @type이 Article 또는 WebPage로 설정되었는지 확인한다.
시점실행할 명령결과가 나쁘면 할 일
빌드 전grep -r "socialDescription" content/frontmatter에 socialDescription이 누락되었으면 추가한다.
빌드 후grep -o "<title>.*</title>" public/*.html제목이 중복되거나 누락되었으면 cfg.pageTitleSuffix를 확인한다.
빌드 후grep -o "application/ld+json" public/*.html구조화 데이터가 누락되었으면 isArticlePage 로직을 검토한다.
빌드 후grep -o "rss+xml" public/*.htmlRSS 링크가 누락되었으면 ContentIndex 플러그인 활성화 여부를 확인한다.

공식 문서 참조

Quartz의 메타데이터 처리 로직은 Markdown 파싱과 정적 사이트 생성기의 일반적인 원리를 따르지만, 구체적인 구현은 Quartz의 코드베이스에 의존한다. 관련 표준 및 도구의 공식 문서는 다음과 같다.

적용 범위와 제약

이 분석은 Quartz v4의 Head.tsx 컴포넌트를 기준으로 한다. 다른 버전의 Quartz나 포크된 저장소는 로직이 다를 수 있다. 또한, externalResources의 내용은 빌드 플러그인의 설정에 따라 달라지므로, 커스텀 플러그인을 사용하는 경우 메타데이터 생성 로직이 확장될 수 있다. isArticlePage 함수의 날짜 패턴 매칭은 특정 슬러그 형식을 사용하는 블로그에 최적화되어 있으며, 다른 형식의 콘텐츠에는 적합하지 않을 수 있다.

💎추천 도구🔒 개인정보 수집 없음

Obsidian & Quartz 지식 블로그 자동화

나만의 제2의 뇌(Second Brain)를 구축하고 무료로 웹에 배포하는 가장 완벽한 노트 앱 & 정적 사이트 템플릿입니다.

Obsidian 무료 다운로드 →