블로그: 댓글 기능 붙이기 — Giscus로 5분 만에
블로그: 댓글 기능 붙이기에 대해 "왜?"라고 물으면 답할 수 있으신가요?
\n\n> 블로그: 댓글 기능 붙이기에 대해 "왜?"라고 물으면 답할 수 있으신가요?\n블로그에 댓글이 없으면 좀 허전합니다. 독자 반응도 못 보고, 피드백도 못 받으니까요.
근데 문제는 GitHub Pages에는 서버도 DB도 없다는 겁니다. 댓글을 어디에 저장하죠?
찾아보니 GitHub 자체를 저장소로 쓰는 방법들이 있었습니다.
선택지 비교
| 기능 | Utterances | Giscus | Disqus |
|---|---|---|---|
| 기반 | GitHub Issue | GitHub Discussion | 자체 서버 |
| 대댓글 | X | O | O |
| 리액션 | X | O | O |
| 광고 | 없음 | 없음 | 있음 (무료 플랜) |
| 다크 모드 | 기본만 | 다양한 테마 | 제한적 |
| 업데이트 | 느림 | 활발 | — |
Disqus는 무료 플랜에 광고가 붙어서 바로 탈락. Utterances도 괜찮은데 대댓글이 안 되고, 테마 옵션이 적습니다.
Giscus 가 대댓글 지원, 다양한 테마, 한국어 지원까지 되니까 이걸로 갔습니다.
Giscus 설정
1. 레포지토리 준비
Giscus는 댓글을 GitHub Discussions에 저장합니다. 그래서 댓글용 레포가 필요하고, Public 이어야 하고, Discussions 기능이 켜져 있어야 합니다.
Settings → General → Features에서 Discussions 체크:

2. Giscus 앱 설치
Giscus 앱 페이지에서 Install 클릭:

레포를 선택하고 설치:

3. 스크립트 생성
Giscus 공식 사이트에서 설정합니다.
- ** 저장소 **:
계정/레포이름 - ** 매핑 **:
pathname(URL 경로 기준으로 Discussion을 매칭) - ** 카테고리 **:
General또는 원하는 카테고리 - ** 테마 **: 블로그에 맞는 테마 선택
설정을 마치면 <script> 태그가 생성됩니다.
React 컴포넌트로 만들기
생성된 스크립트 태그를 그대로 붙이면 안 되고, React 컴포넌트로 만들어야 합니다. 저는 별도 파일로 분리하지 않고, PostDetailPage.jsx 안에 PostDetailComment 컴포넌트를 정의했습니다.
import { useEffect, useRef } from 'react';
const PostDetailComment = () => {
const ref = useRef(null);
useEffect(() => {
if (!ref.current || ref.current.hasChildNodes()) return;
const script = document.createElement('script');
script.src = 'https://giscus.app/client.js';
script.async = true;
script.crossOrigin = 'anonymous';
script.setAttribute('data-repo', 'YOUR_USERNAME/YOUR_REPO');
script.setAttribute('data-repo-id', 'YOUR_REPO_ID');
script.setAttribute('data-category', 'General');
script.setAttribute('data-category-id', 'YOUR_CATEGORY_ID');
script.setAttribute('data-mapping', 'pathname');
script.setAttribute('data-strict', '0');
script.setAttribute('data-reactions-enabled', '1');
script.setAttribute('data-emit-metadata', '0');
script.setAttribute('data-input-position', 'bottom');
script.setAttribute('data-theme', 'preferred_color_scheme');
script.setAttribute('data-lang', 'ko');
ref.current.appendChild(script);
}, []);
return <section ref={ref} />;
};
data-repo,data-repo-id,data-category-id값은 Giscus 사이트에서 생성된 값으로 바꿔야 합니다.
useEffect에서 DOM에 스크립트를 직접 삽입하는 방식입니다. hasChildNodes() 체크는 Strict Mode에서 두 번 실행되는 걸 방지하기 위한 가드입니다.
글 상세 페이지에 배치
const PostDetailPage = () => {
const post = ...;
return (
<article>
{/* 본문 */}
<PostDetailBody post={post} />
{/* 댓글 — key로 글 변경 시 리마운트 */}
<PostDetailComment key={post.path} />
</article>
);
};
여기서 key={post.path}가 중요합니다. SPA에서 다른 글로 이동하면 컴포넌트가 재사용되는데, 그러면 이전 글의 댓글이 그대로 남아있게 됩니다. key를 글 경로로 주면 글이 바뀔 때마다 댓글 컴포넌트가 새로 마운트되어서 올바른 Discussion을 로드합니다.
이거 빼먹으면 A 글에서 B 글로 이동해도 A 글 댓글이 보이는 버그가 생깁니다. 처음에 이걸 몰라서 좀 헤맸습니다.
적용 결과

깔끔한 GitHub 스타일 댓글창이 글 하단에 붙습니다. GitHub 계정 로그인이 필요하긴 하지만, 개발 블로그 독자 대부분은 GitHub 계정이 있으니까 큰 문제는 아닙니다.
설정부터 적용까지 실제로 5분이면 됩니다. 무료에 광고도 없고, 이만하면 훌륭하죠.