gatsby-starter-blog
지난 포스트에서 설명한 gatsby-starter-blog를 기준으로 포스트에 카테고리를 추가하는 방법에 대해서 설명하려고 한다.
공식 문서에 Creating Tags Pages for Blog Posts라는 제목으로 비슷한 내용에 대한 설명이 있지만, 내 기준으로 처음 Gatsby를 접한 상태에서 보기에는 좀 어렵고 복잡했다. 그래서 카테고리 추가를 위한 최소한의 코드(?)를 소개하는 것을 목표로 포스트를 작성해보려고 한다.
gatsby-transformer-remark
gatsby-transformer-remark는 markdown 본문을 html코드로 변환하고, 해당 코드와 markdown에 포함된 여러 데이터를 우리가 사용하기 편리한 형태로 GraphQL에 추가해주는 플러그인이다. GraphiQL(개발 서버 실행시 사용 가능한 GraphQL 인터페이스)에서 보이는 allMarkdownRemark, markdownRemark가 바로 gatsby-transformer-remark 플러그인에 의해 추가된 것이다.
{
allMarkdownRemark {
nodes {
id
html
frontmatter {
title
date
description
}
}
}
markdownRemark(id: {eq: ""}) {
id
}
}
여기서 id는 각 markdownRemark 노드마다 추가된 값으로 개별 포스트의 id로 사용된다. html은 markdown에서 변환된 것으로, 실제 포스트 내용을 페이지에 삽입할 때 사용된다. 이외에도 다양한 데이터가 gatsby-transformer-remark 플러그인에 의해 자동으로 추가되는데, 그 중에서도 포스트에 카테고리를 추가하기 위해 살펴봐야 할 것은 frontmatter다.
frontmatter
개별 markdown 파일 content\blog\*\index.md
을 보면, 다음과 같은 코드가 상단에 공통적으로 포함되어 있는 것을 확인할 수 있다.
---
title:
date:
description:
---
여기에 작성된 값들이 frontmatter의 title, date, description 값이 되는 것이다. 즉 여기서 다음과 같이 category를 추가하면 GraphQL에서 category값을 사용할 수 있게 된다.
---
title:
date:
description:
category: "개츠비" // 추가
---
각 포스트 상단에 위와 같이 category를 추가했다면 다양한 방법으로 활용할 수 있다. 예를 들어, 특정 카테고리에 포함된 모든 포스트의 id를 불러오고 싶다면 다음과 같이 query를 작성하면 된다.
{
allMarkdownRemark(filter: {frontmatter: {category: {eq: "개츠비"}}}) {
nodes {
id
}
}
}
모든 카테고리 값을 중복없이 나열하고 싶다면 다음과 같이 query를 작성할 수 있다.
{
allMarkdownRemark {
categoryList: distinct(field: frontmatter___category)
}
}
활용 예시
목표
- index 페이지: 모든 카테고리 페이지에 대한 링크 추가
- 카테고리 페이지: 해당 카테고리에 포함된 포스트들만 화면에 표시
포스트에 category 추가
각 markdown 파일에 다음과 같이 category 값을 추가한다.
// hello-world/index.md
---
// ...
category: "Hello"
---
// my-second-post/index.md
---
// ...
category: "Hello"
---
// new-beginnings/index.md
---
// ...
category: "New"
---
처음과 두 번째 포스트에는 "Hello"라는 카테고리를, 마지막 포스트에는 "New"라는 카테고리를 임의로 추가했다.
개별 카테고리 페이지 생성
gatsby-node.js
파일의 createPages 함수에 카테고리 목록을 불러오고, 각 카테고리마다 페이지를 생성하도록 하는 코드를 추가한다.
exports.createPages = async ({ graphql, actions, reporter }) => {
// ...
// 기존 쿼리 수정
const result = await graphql(
`
{
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: ASC }
limit: 1000
) {
// 추가
categoryList: distinct(field: frontmatter___category)
nodes {
// ...
}
}
}
`
)
// ... 에러 처리, 포스트 페이지 생성 코드 생략
// 카테고리 페이지에 사용될 템플릿 (컴포넌트)
const categoryPosts = path.resolve(`./src/templates/category-posts.js`)
// 카테고리 목록을 가져오고, 각 카테고리마다 페이지 생성
const categories = result.data.allMarkdownRemark.categoryList
categories.forEach(category => {
createPage({
path: `/${category}/`,
component: categoryPosts,
context: { category },
})
})
}
카테고리 페이지 템플릿 작성
src\pages\index.js
파일을 부분적으로 수정하여 특정 카테고리의 포스트만 화면에 표시하는 페이지 템플릿을 작성한다.
// src/templates/category-posts.js
const CategoryPost = ({ data, location, pageContext }) => {
// ...
// gatsby-node.js에서 context로 넘겨준 값
const { category } = pageContext
// ...
return (
<Layout location={location} title={siteTitle}>
<Seo title={`Posts in ${category}`} /> {/* 페이지 title 수정 */}
<Bio />
<h3>{`Current: ${category}`}</h3> {/* 현재 카테고리 표시 */}
<ol style={{ listStyle: `none` }}>
{/* 생략 */}
</ol>
</Layout>
)
}
export default CategoryPost
// 페이지 쿼리 수정
export const pageQuery = graphql`
query($category: String!) {
// ...
allMarkdownRemark(
sort: { fields: [frontmatter___date], order: DESC }
// 추가된 필터
filter: { frontmatter: { category: { eq: $category } } }
) {
nodes {
// ...
}
}
}
`
gatsby-node.js
파일에서 context로 넘겨준 category 값이 component 내에서 그리고 page query에서 포스트를 필터링하기 위해서 활용되는 것을 확인할 수 있다.
홈에서 카테고리 목록 표시
다음으로 src\pages\index.js
파일을 수정하여 카테고리 목록과 해당 페이지로의 링크를 보여준다.
const BlogIndex = ({ data, location }) => {
// ...
// 카테고리 목록
const categories = data.allMarkdownRemark.categoryList
// ...
return (
<Layout location={location} title={siteTitle}>
<Seo title="All posts" />
<Bio />
<nav> {/* 카테고리 Nav */}
<ul>
{categories.map(category => (
<li key={category}>
<Link to={`/${category}/`}>{category}</Link>
</li>
))}
</ul>
</nav>
<ol style={{ listStyle: `none` }}>
{/* 생략 */}
</ol>
</Layout>
)
}
export default BlogIndex
export const pageQuery = graphql`
query {
// ...
allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC }) {
// 추가
categoryList: distinct(field: frontmatter___category)
nodes {
// ...
}
}
}
`
완성
개발 서버를 실행시켜보면 홈 화면에는 카테고리 목록이 새롭게 추가되었고,
특정 카테고리 링크를 클릭하면 markdown에 추가했던 category 값에 따라 그 카테고리에 해당되는 포스트만 화면에 나타나는 것을 확인할 수 있다.
'개발' 카테고리의 다른 글
Gatsby 블로그: TOC(목차) 추가하기 (0) | 2022.11.30 |
---|---|
Gatsby 블로그: Pagination 추가하기 (0) | 2022.11.30 |
Gatsby로 블로그 만들기 (0) | 2022.11.30 |
HTTP 세션과 쿠키 (0) | 2022.11.30 |
JavaScript 클로저 (0) | 2022.11.30 |