마크다운 블로그 (다국어, 태그 기반)
내용이 행이 아닌 파일인 블로그. 전체 설계는 하나의 아이디어를 중심으로 돌아갑니다.
게시물의 정체성은 translationKey이지 슬러그가 아닙니다. 슬러그는 SEO를 위해
로컬라이즈되며 언어마다 다릅니다. 키는 세 개의 파일을 하나의 기사로 연결하며,
hreflang, 언어 전환기, 관련 게시물 및
교차 로케일 리디렉션을 지원합니다. 이 필드 하나만 올바르게 설정하면 나머지는 모두 조회입니다.
이 모듈을 출시한 엔지니어가 작성했습니다. 감사 대상이 된 이전 구현은
사이트맵과 SEO 표면을 갖춘 다국어, 정적 생성 마케팅 블로그였습니다.
아래의 사실과 규칙은 콘텐츠 레이어 제품군과 빌드가 검증하는 것입니다. references/provenance.md에 기록이 있습니다.
사용 시기
- 콘텐츠가 리포지토리의 마크다운으로 작성되고 앱과 함께 배포됨
- 두 개 이상의 언어, 언어마다 다른 슬러그 사용
- 태그 페이지, 관련 게시물, 피드 또는 hreflang이 범위에 포함됨
- 전체를 빌드 시 정적으로 생성하려는 경우
사용하지 말아야 할 시기
| 이 대신 | 사용 |
|---|---|
| 호스팅된 CMS가 진실 공급원인 경우 | 해당 CMS의 SDK 사용; references/content-model.md만 유지 |
| 문서 사이트 / 도움말 센터 (카테고리, 사이드바, 검색) | 도움말 센터 스킬 — 다른 탐색 모델 |
| 10개 미만 게시물의 단일 로케일 블로그 | 인라인 fs + gray-matter; 이 스킬은 오버헤드 |
| 사용자 제출 마크다운 렌더링 | 살균 렌더러 사용; references/rendering.md의 XSS 참고 참조 |
아키텍처
content/blog/<locale>/<localized-slug>.md # frontmatter + body
|
v
parseFrontmatter --YAML, 잘못된 따옴표에 대해 라인 파서로 폴백
|
v
getAllPosts(locale) <-- 프로덕션에서 로케일별로 메모이즈
|
+--> translationKey ----> 대안 / hreflang / 언어 전환
+--> tags -> 태그 SLUG ---> 태그 페이지 (슬러그가 정체성, 레이블이 아님)
+--> related (EN 슬러그) -> 관련 게시물, EN 폴백 포함
|
v
/blog /blog/[slug] /blog/tag/[slug] sitemap.xml feed.xml
중요한 사실
- 관계는 기본 로케일에서 기본 로케일 슬러그로 한 번만 작성됩니다. 번역된 파일은
related를 완전히 생략할 수 있으며 여전히 올바른 관련 게시물을 가져옵니다.translationKey를 통해 해결되므로 모든 번역이 동일한 관련 섹션을 렌더링합니다. 폴백 테스트가 이를 유지합니다. - 태그의 정체성은 슬러지가 아니라 슬러그입니다.
"AI Agents"와"AI agents"는 동일한 URL로 슬러그됩니다. 슬러그별로 그룹화하고 슬러그별로 게시물을 매칭하므로 모든 철자 변형의 게시물이 하나의 태그 페이지에 나타납니다. 두 개의 테스트가 이를 유지합니다. gray-matter는 원시 따옴표 문자를 포함하는 이중 따옴표 YAML 스칼라에서 오류를 발생시킵니다. 번역된 발췌문의 타이포그래피 따옴표가 그 예입니다. 폴백 파서가 없으면 빌드가 해당 파일 하나에서 중단됩니다. 라인별 폴백이 로딩을 계속 유지합니다. 라이브러리에 대해 확인되었으며 테스트로 다루어집니다.gray-matter는 실패한 구문 분석을 빈 결과로 캐시합니다. 구문 분석 전에 캐시 항목을 쓰므로 오류가 발생한 파일의 두 번째 및 이후 모든 구문 분석은{}를 반환합니다. 오류 없음, frontmatter 없음. 항상matter(contents, {})를 호출하세요. 모든 옵션 객체는 캐시를 선택 해제합니다.- 로딩은 페이지당 O(게시물 수 x 로케일 수)입니다. 메모이즈하지 않으면 그렇습니다. 로케일별로 메모이즈하여 각 콘텐츠 파일이 빌드당 한 번만 읽히도록 합니다. 그렇지 않으면
generateMetadata에서 대안을 해결하는 것이 이전 구현에서 측정된 71배 파일 읽기 증폭입니다. getPostSlugs는.md를 필터링해야 합니다. 필터는 잘못된.DS_Store가.DS_Store.md읽기 및ENOENT가 되는 것을 방지합니다. 테스트가 이를 유지합니다.- 태그 페이지에는 교차 로케일 정체성이 없습니다. 태그는 로케일별 자유 텍스트이므로 언어 전환기는 404가 발생하는 URL을 빌드하는 대신 태그 URL에서 블로그 인덱스로 폴백해야 합니다.
엄격한 규칙
교차 로케일 조회를 슬러그로 키 지정하지 마십시오. 슬러그는 의도적으로 로컬라이즈됩니다.
translationKey가 조인 열입니다. 로케일 간 슬러그 일치는 우연일 뿐 관계가 아닙니다.
getPostBySlug가 초안 가시성을 암시적으로 결정하도록 두지 마십시오. 로더에서 초안을 필터링하십시오.dynamicParams = false는 부작용으로만 초안을 숨기며 플래그가 변경되는 즉시 그렇게 하지 않습니다. 초안 테스트가 필터를 유지합니다.
"5분 읽기" 상수를 렌더링하지 마십시오. 본문에서 계산하십시오. 하나의
split비용이 들며 읽기 시간 테스트가 이를 유지합니다.
충돌 검사 없이 읽기 시간에 레이블에서 태그 페이지 URL을 파생시키고 렌더링 시간에 URL에서 레이블을 파생시키지 마십시오. 이 왕복은 모든 레이블이 고유하게 슬러그되는 경우에만 무손실입니다.
빠른 시작
- 로케일 계약 및 frontmatter 스키마 설정 — content-model.md
- 로더 구축 (메모이즈됨,
.md필터링됨, 폴백 파서) — content-loader.md - 로케일, 대안 및 교차 로케일 리디렉션 연결 — i18n-and-routing.md
- 태그 그룹화 및 태그 페이지 추가 — tags.md
- 세 가지 경로, 메타데이터 및 JSON-LD 구축 — pages-and-seo.md
- 본문 및 커버 렌더링 — rendering.md
- 검증 스크립트 추가 및 운영자 격차 읽기 — operations.md
- 픽스처 및 테스트 실행 — testing.md
기존 앱에 이식 중입니까? 먼저 adaptation.md의 연결 테이블을 작성하십시오 — 10분이 걸리며 이름 변경을 절약합니다.
참조 디렉토리
| 시나리오 | 트리거 키워드 | 참조 |
|---|---|---|
| Frontmatter 필드, 초안, 번역 키, 관계 | frontmatter, schema, translationKey, draft, related, excerpt | content-model.md |
| 파일 읽기, 캐싱, YAML 실패, 읽기 시간 | gray-matter, fs, cache, memoize, ENOENT, YAMLException, parse | content-loader.md |
| 로케일, hreflang, 대안, 잘못된 로케일 링크 | i18n, locale, hreflang, alternates, canonical, language switcher, redirect | i18n-and-routing.md |
| 태그 URL, 충돌, 얇은 태그 페이지 | tag, slug, diacritics, collision, tag page, taxonomy | tags.md |
| 경로, 메타데이터, JSON-LD, 사이트맵, RSS | page.tsx, generateStaticParams, generateMetadata, dynamicParams, sitemap, RSS, feed, BlogPosting | pages-and-seo.md |
| 마크다운을 React로, 코드 블록, 커버 이미지 | react-markdown, remark-gfm, syntax highlighting, cover, motif, accent, XSS | rendering.md |
| 콘텐츠 검증, 빌드 비용, 편집기 워크플로우 | validation, CI check, build time, drafts, authoring, operator | operations.md |
| 픽스처 및 통과 테스트 스위트 | test, fixture, vitest, node:test, regression, assert | testing.md |
| 호스트 앱에 맞추기: 연결점, 이름 변경, 프로브 | adapt, port, host, seam, rename, CMS, integrate | adaptation.md |
| 감사 원장: 변경된 사항, 유지된 사항 및 이전 구현 대비 추가된 사항 | provenance, deviations, fidelity, audit, ledger | provenance.md |