출력 포맷
모든 페이지와 섹션이 항상 렌더링하는 HTML 페이지 외에, Hwaro는 나란히 놓이는 비HTML 파일도 추가로 렌더링할 수 있습니다 — 글의 JSON 표현, 섹션의 피드 형태 XML 목록, 일반 텍스트 내보내기 등. HTML 렌더링에는 영향이 없으며, 추가 포맷은 어디까지나 덧붙는 것입니다.
사이트의 RSS/Atom 피드 마크업을 커스터마이즈하려는 거라면, 그건 출력 포맷이 아니라 커스텀 피드 템플릿(templates/rss.xml.jinja)입니다.
설정
[outputs]
page = [] # 예: ["json"] — 모든 일반 페이지가 내보내는 포맷
section = ["json"] # 모든 섹션 인덱스가 내보내는 포맷
sections = [] # 선택적 섹션 이름 허용 목록. 비어 있으면 전체
| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
| page | array | [] | 모든 일반 페이지가 내보내는 포맷 |
| section | array | [] | 모든 섹션 인덱스가 내보내는 포맷 |
| sections | array | [] | section 출력을 제한할 섹션 이름(과 그 하위). 비어 있으면 모든 섹션 |
지원되는 포맷은 네 가지뿐이며, 포맷 이름이 곧 파일 확장자입니다.
json txt xml csv
[outputs]에 알 수 없는 포맷 이름이 있으면 조용히 아무것도 출력하지 않는 대신, 분류된 설정 오류와 함께 빌드가 즉시 실패합니다.
sections는 섹션 이름 자체 또는 그 하위 어느 것과도 매칭됩니다("posts" 값은 "posts/reviews"에도 매칭). [feeds].sections와 같은 규칙입니다.
프론트 매터 오버라이드
페이지(또는 섹션)는 프론트 매터의 최상위 outputs 키로 설정 기본값을 덮어쓸 수 있습니다.
+++
title = "My Post"
outputs = ["json"]
+++
outputs는 일급 프론트 매터 필드가 아닙니다 — 다른 알 수 없는 최상위 키처럼 page.extra["outputs"]에 담기고 템플릿에는 page.extra.outputs로 노출됩니다. 프론트 매터에 이 키가 존재하기만 하면 명시적인 빈 목록을 포함해 항상 설정 기본값을 이깁니다.
+++
title = "Opt this page out"
outputs = []
+++
이렇게 하면 config.toml의 [outputs].page가 비어 있지 않더라도 그 한 페이지의 모든 포맷이 억제됩니다. 키가 아예 없으면 설정 기본값(섹션의 경우 sections 허용 목록 포함)이 적용됩니다.
일반적인 extra 값이므로 다른 extra 필드처럼 섹션의 [cascade.extra] 테이블을 통해 캐스케이드되기도 합니다.
+++
title = "Blog"
[cascade.extra]
outputs = ["json"]
+++
이렇게 하면 페이지가 직접 설정하지 않는 한 모든 하위 페이지가 outputs = ["json"]을 갖습니다. 형식이 잘못된 오버라이드(배열이 아니거나 json/txt/xml/csv 밖의 이름을 포함)는 1회성 빌드 경고와 함께 무시됩니다 — 빌드를 실패시키는 대신 해당 페이지는 추가 포맷 없음으로 처리됩니다.
템플릿
활성화된 각 포맷은 전용 Crinja 템플릿에서 렌더링됩니다. 템플릿 이름은 page.html/section.html과 같은 관례로 확장자를 따릅니다.
templates/page.json.jinja
templates/section.json.jinja
templates/page.xml.jinja
Hwaro가 템플릿을 로드할 때는 마지막의 인식되는 템플릿 확장자(.html, .j2, .jinja2, .jinja, .ecr)만 제거합니다 — .json/.xml 부분은 템플릿 이름의 일부로 남습니다. 예를 들어 templates/page.json.jinja는 page.json으로 로드됩니다.
페이지 자신의 본문 마크다운/콘텐츠, toc, 그리고 page.html/section.html에서 평소 쓸 수 있는 다른 모든 값(page, section, site, config, …)을 포맷 템플릿에서도 쓸 수 있습니다. 포맷에 필요한 것을 자유롭게 작성하면 됩니다. 예:
{# templates/page.json.jinja #}
{
"title": {{ page.title | tojson }},
"url": "{{ page.url }}",
"date": "{{ page.date }}"
}
{# templates/section.json.jinja #}
{
"title": {{ section.title | tojson }},
"pages": [
{% for p in section.pages %}
"{{ p.url }}"{% if not loop.last %},{% endif %}
{% endfor %}
]
}
템플릿 선택 체인
주어진 페이지/섹션과 활성화된 포맷 <fmt>에 대해 Hwaro는 다음 순서로 시도합니다.
<entry-template>.<fmt>— 페이지가 실제로 해석되는 템플릿의 포맷별 형제(프론트 매터가template = "post"라면post.json을 먼저 찾음)section.<fmt>— 섹션만page.<fmt>— 최종 폴백
활성화된 포맷의 템플릿이 없으면 하드 빌드 오류입니다. 후보가 하나도 없으면 빌드가 즉시 실패하고 시도한 템플릿 이름을 모두 나열합니다. 예:
Error [HWARO_E_TEMPLATE]: No template found for output format 'txt' on about.md. Tried: page.txt.
Create one of: templates/page.txt.jinja.
이는 의도된 동작입니다. 설정이나 프론트 매터에서 켠 포맷이 조용히 아무것도 만들지 않는 것이, 시끄럽게 실패하는 것보다 더 나쁜 실패 방식이기 때문입니다.
출력 위치
포맷은 페이지의 index.html 옆에 나란히 index.<fmt>로 렌더링됩니다.
public/
posts/hello/index.html
posts/hello/index.json <- [outputs].page = ["json"]
페이지네이션
포맷은 페이지/섹션당 한 번만 — 1페이지에만 적용됩니다. 페이지네이션된 섹션의 /page/2/, /page/3/, …는 평소처럼 HTML을 출력하지만 자체 index.<fmt>는 절대 생기지 않습니다. 섹션 자신의 URL에만 생성됩니다.
alternate_output_tags
활성화된 모든 포맷은 <link rel="alternate" type="…"> 태그를 얻으며, page.html/section.html에서 {{ alternate_output_tags }}로 쓸 수 있습니다(포맷이 없는 페이지에서는 빈 문자열).
<head>
{{ alternate_output_tags }}
</head>
outputs = ["json"]인 페이지에서는 다음과 같이 렌더링됩니다.
<link rel="alternate" type="application/json" href="https://example.com/posts/hello/index.json">
href는 canonical/hreflang 링크와 같은 방식으로 base_url을 거쳐 해석되므로, 서브패스 배포(base_url = "https://user.github.io/repo")에서도 올바릅니다.
결정성
포맷 템플릿은 page.html과 같은 렌더링 파이프라인을 거칩니다 — 빌드 간에 바이트 단위로 동일한 출력을 원한다면 포맷 템플릿에서 now() 같은 비결정적 값을 피합니다(증분 빌드 참고).
알려진 제한: --cache에서 포맷 비활성화
[outputs](또는 페이지 프론트 매터)에서 포맷을 제거해도 이전 빌드가 --cache로 이미 써 둔 파일이 소급해서 삭제되지는 않습니다 — 증분 빌드는 변경으로 감지된 페이지만 다시 렌더링하는데, "설정에서 포맷이 제거됨"은 파일별 변경으로 추적되지 않기 때문입니다. 포맷을 끈 뒤에는 전체(비증분) 빌드를 실행해 남아 있는 index.<fmt> 파일을 정리합니다.