블로그에 댓글 시스템 추가하기

뭔가 휑한 블로그

Next.js 로 블로그를 어느정도 만든 뒤 블로그를 천천히 훑어보니 너무 휑했습니다.
사실 정보의 전달이 블로그의 기본적인 목적이긴 하지만, 다양한 사람들과 의견을 나누고 얘기를 나눔으로써 시야를 넓히는 것도 중요한 기능 중 하나라고 생각하기 때문에 댓글 시스템을 추가하기로 마음먹었습니다. (물론 참여율은 극히 낮을 것 같지만요.. 😅)
어떤 댓글 시스템을 달 지 고민을 했는데, Frontend Fundamental에 사용되는 Giscus가 떠올랐습니다.

Giscus

Giscus란 GitHub Discussions를 기반으로 동작하는 댓글 시스템입니다. 나중에 동작하는 것을 보면 아시겠지만, 사용자가 반응이나 댓글을 남기면 해당 내용이 GitHub 레포지토리의 Discussions 탭에 추가됩니다.
현재 저의 블로그는 기술 블로그로써, 대부분의 방문객은 개발자 혹은 유관업무 종사자일 것이라 GitHub 기반 댓글 시스템이 큰 장벽은 아니라고 판단했습니다.
해당 웹 사이트에서 강조하는 장점은 다음과 같습니다.
  • 사용자 추적도, 광고도 없습니다. 항상 무료입니다. 📡 🚫
  • 데이터베이스가 필요 없습니다. 모든 데이터는 GitHub Discussions에 저장됩니다. 🐙🐈‍⬛
  • 자동으로 GitHub에서 새로운 댓글과 수정 사항을 반영합니다. 🔃
문서에는 간단한 작동 원리도 기술되어 있습니다. GitHub Discussions API를 활용하여 페이지와 연관된 논의를 찾고, 없다면 새롭게 논의를 만듭니다. 방문자는 GitHub OAuth를 이용해 로그인하면 Giscus App이 방문자를 대신해 댓글을 등록하도록 Giscus App에 권한을 위임합니다.

블로그에 도입해보자!

Giscus 홈페이지에는 설치 방법이 친절히 안내되어있습니다. 언어, 저장소, Discussion 연결 방법을 포함해 여러가지 설정을 고르면 <script> 태그를 만들어줍니다. 이 코드를 복사하여 댓글을 보여주고 싶은 페이지 내에 삽입하면 끝!
단, 설정을 하는 과정에서 GitHub 레포지토리를 Giscus 앱과 연결을 해야 합니다. 해당 내용은 Giscuss 홈페이지에 잘 설명되어 있으니, 보고 따라해주시면 됩니다.
이제 실제 코드를 삽입해야 하는데, React 혹은 Vue 처럼 컴포넌트 기반 개발 시스템이라면 giscus-component 라이브러리를 활용하시는 것을 추천드립니다. 저는 React 환경이기 때문에 @giscus/react 패키지를 설치했습니다.
현재 제 기록 페이지의 구성은 다음과 같습니다.
// [slug]/page.tsx // 메타데이터 설정 export async function generateMetadata({ params }: Props): Promise<Metadata> { ... } // ISR 적용 export const revalidate = 3600; export const dynamicParams = true; export async function generateStaticParams() { ... } type RecordPageProps = { params: Promise<{ slug: string }> }; export default async function RecordPage({ params }: RecordPageProps) { const { slug } = await params; const recordMap = await getPageByPageId(slug); return ( <RecordPageLayout> <NotionPage recordMap={recordMap} /> </RecordPageLayout> ); } // Notion API로 글 내용 가져오기 function getPageByPageId(pageId: string) { return notionAPI.getPage(pageId); }
// NotionPage.tsx "use client"; type NotionPageProps = { recordMap: ExtendedRecordMap }; export function NotionPage({ recordMap }: NotionPageprops) { // ... return ( <NotionRenderer recordMap={recordMap} // ... /> ); }
기록 페이지([slug]/page.tsx)는 현재 서버 컴포넌트로서, Notion API를 이용해 글 데이터를 가져온 뒤, NotionPage 라는 컴포넌트로 렌더링을 하고 있습니다. NotionPage 컴포넌트는 동적 렌더링 특성 상, 클라이언트 컴포넌트입니다.
Comments 라는 컴포넌트를 별도의 파일로 구현해줍니다.
// Comments.tsx "use client"; import Giscus from "@giscus/react"; export function Comments() { return ( <Giscus id="comments" repo="..." repoId="..." category="Announcements" categoryId="..." mapping="title" strict="0" reactionsEnabled="1" emitMetadata="0" inputPosition="top" theme="noborder_light" lang="ko" loading="lazy" /> ); }
Giscus 댓글도 동적으로 렌더링되는 녀석이다보니, 동일하게 클라이언트 컴포넌트로 구현해줍니다.
Comments 컴포넌트를 RecordPage 컴포넌트에 추가해줍니다.
// [slug]/page.tsx // ... export default async function RecordPage({ params }: RecordPageProps) { // ... return ( <RecordPageLayout> <NotionPage recordMap={recordMap} /> <Comments /> {/* 여기에 댓글을 보여줍니다. */} </RecordPageLayout> ); }
Next.js 에 Giscus 추가하는 방법을 찾아보면 어떤 글에서는 레이아웃 컴포넌트에 추가하는 경우가 있던데, 그건 올바른 구현이 아닌 것 같습니다.
  • RecordPage 가 있는 파일은 generateMetadatagenerateStaticParams 를 활용하고 있으므로, 서버 컴포넌트여야 함.
  • NotionPage 는 동일한 클라이언트 컴포넌트이고 글 내용과 댓글이 UI 상으로는 붙어있기는 해도, 서로 같이 붙어있어야 할 이유는 없고 단일 책임을 위반하기 때문에 해당 위치에 Giscus 컴포넌트를 구현하지 않음.
  • 레이아웃 컴포넌트 파일에 Giscus 컴포넌트가 있는 것 또한 위와 같은 사유로 옳지 않아보임.
처음에 저도 레이아웃 컴포넌트에 Giscus 컴포넌트 넣었는데 서버/클라 컴포넌트 관련 에러가 터지거나 노션 API에서 CORS 발생하는 등 문제가 좌라락 터지더라구요…ㅎㅎ
그냥 간단하게 위와 같이 구성하면 별다른 에러 없이 댓글 시스템을 추가하실 수 있을 것입니다.

댓글 시스템 추가 후

 
notion image
Giscus 댓글 시스템을 추가한 후, 따봉을 하나 눌러보았습니다.
notion image
그러면 GitHub Discussions 탭에 요렇게 글 제목으로 논의가 하나 생긴 것을 확인할 수 있습니다.

후기

이렇게 블로그에 간단하게 댓글 시스템을 추가하였습니다.
글을 작성하는 이 시점까지는 딱히 저 말고 다른 분들의 댓글이나 반응은 전무하지만, 언젠가 기념비적인 첫번째 교류자가 나타나기를 기대하며 글을 마무리합니다.