GitHub Pages와 같은 플랫폼에서 가벼운 정적 블로그를 호스팅하면 수많은 장점이 있지만, 일부 상호작용 기능을 사용할 수 없게 됩니다. 다행히 Giscus가 있어 정적 사이트에 사용자 댓글을 삽입할 수 있는 방법을 제공합니다.
Giscus 작동 원리
Giscus는 GitHub API를 사용하여 리포지토리에 연결된 Discussions에 GitHub 사용자가 작성한 댓글을 읽고 저장합니다.
사이트에 Giscus 클라이언트 사이드 스크립트 번들을 삽입하고, 올바른 리포지토리 URL로 설정하면 사용자가 (GitHub에 로그인한 상태에서) 댓글을 보고 작성할 수 있습니다.
이 방식은 서버리스입니다. 댓글이 GitHub에 저장되고 클라이언트 사이드에서 동적으로 로드되므로, AstroPaper와 같은 정적 블로그에 완벽합니다.
Giscus 설정하기
Giscus는 giscus.app에서 쉽게 설정할 수 있지만, 여기서도 과정을 간략히 설명하겠습니다.
사전 요구 사항
Giscus가 작동하기 위한 사전 요구 사항은 다음과 같습니다:
- 리포지토리가 공개되어 있어야 합니다
- Giscus 앱이 설치되어 있어야 합니다
- 리포지토리에서 Discussions 기능이 활성화되어 있어야 합니다
이러한 조건 중 하나라도 충족할 수 없다면, 안타깝게도 Giscus를 통합할 수 없습니다.
Giscus 구성하기
다음으로 Giscus를 구성해야 합니다. 대부분의 경우 미리 선택된 기본값이 적합하며, 특별한 이유가 있고 무엇을 하는지 알고 있는 경우에만 수정해야 합니다. 잘못된 선택을 하더라도 걱정하지 마세요. 나중에 언제든지 설정을 조정할 수 있습니다.
하지만 다음 항목은 반드시 설정해야 합니다:
- UI에 적합한 언어 선택
- 연결할 GitHub 리포지토리 지정. 일반적으로 GitHub Pages에서 정적으로 호스팅되는 AstroPaper 블로그가 포함된 리포지토리입니다
- GitHub에서 누구도 무작위 댓글을 직접 생성할 수 없도록 하려면
Announcement유형의 Discussion을 생성하고 설정합니다 - 색상 스킴 정의
설정을 구성한 후, Giscus는 다음 단계에서 필요한 <script> 태그를 생성해 줍니다.
간단한 script 태그
이제 다음과 같은 script 태그가 있을 것입니다:
<script
src="https://giscus.app/client.js"
data-repo="[ENTER REPO HERE]"
data-repo-id="[ENTER REPO ID HERE]"
data-category="[ENTER CATEGORY NAME HERE]"
data-category-id="[ENTER CATEGORY ID HERE]"
data-mapping="pathname"
data-strict="0"
data-reactions-enabled="1"
data-emit-metadata="0"
data-input-position="bottom"
data-theme="preferred_color_scheme"
data-lang="en"
crossorigin="anonymous"
async
></script>
이것을 사이트 소스 코드에 추가하기만 하면 됩니다. AstroPaper를 사용하고 있고 글에 댓글을 활성화하고 싶다면, PostDetails.astro로 이동하여 댓글이 표시되길 원하는 위치에 붙여넣으세요. 이 글 공유하기: 버튼 아래가 적당할 것입니다.
<Layout {...layoutProps}>
<main>
<ShareLinks />
<script
src="https://giscus.app/client.js"
data-repo="[ENTER REPO HERE]"
data-repo-id="[ENTER REPO ID HERE]"
data-category="[ENTER CATEGORY NAME HERE]"
data-category-id="[ENTER CATEGORY ID HERE]"></script>
</main>
<Footer />
</Layout>src/layouts/PostDetails.astro
완료입니다! AstroPaper에 댓글 기능을 성공적으로 통합했습니다!
라이트/다크 테마를 지원하는 React 컴포넌트
레이아웃에 삽입된 script 태그는 상당히 정적이며, 테마를 포함한 Giscus 설정이 레이아웃에 하드코딩되어 있습니다. AstroPaper에는 라이트/다크 테마 토글이 있으므로, 댓글도 사이트의 나머지 부분과 함께 라이트와 다크 테마 사이를 자연스럽게 전환하면 좋을 것입니다. 이를 위해서는 Giscus를 삽입하는 더 정교한 방식이 필요합니다.
먼저 Giscus용 React 컴포넌트를 설치합니다:
npm i @giscus/react && npx astro add react
그런 다음 src/components에 새 Comments.tsx React 컴포넌트를 생성합니다:
import Giscus, { type Theme } from "@giscus/react";
import { GISCUS } from "@/constants";
import { useEffect, useState } from "react";
interface CommentsProps {
lightTheme?: Theme;
darkTheme?: Theme;
}
export default function Comments({
lightTheme = "light",
darkTheme = "dark",
}: CommentsProps) {
const [theme, setTheme] = useState(() => {
const currentTheme = localStorage.getItem("theme");
const browserTheme = window.matchMedia("(prefers-color-scheme: dark)")
.matches
? "dark"
: "light";
return currentTheme || browserTheme;
});
useEffect(() => {
const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
const handleChange = ({ matches }: MediaQueryListEvent) => {
setTheme(matches ? "dark" : "light");
};
mediaQuery.addEventListener("change", handleChange);
return () => mediaQuery.removeEventListener("change", handleChange);
}, []);
useEffect(() => {
const themeButton = document.querySelector("#theme-btn");
const handleClick = () => {
setTheme(prevTheme => (prevTheme === "dark" ? "light" : "dark"));
};
themeButton?.addEventListener("click", handleClick);
return () => themeButton?.removeEventListener("click", handleClick);
}, []);
return (
<div className="mt-8">
<Giscus theme={theme === "light" ? lightTheme : darkTheme} {...GISCUS} />
</div>
);
}src/components/Comments.tsx
이 React 컴포넌트는 네이티브 Giscus 컴포넌트를 래핑할 뿐만 아니라, lightTheme과 darkTheme이라는 추가 props를 도입합니다. 두 개의 이벤트 리스너를 활용하여, Giscus 댓글이 사이트의 테마와 일치하도록 사이트나 브라우저 테마가 변경될 때마다 다크와 라이트 테마 사이를 동적으로 전환합니다.
또한 GISCUS 설정을 정의해야 하는데, 최적의 위치는 constants.ts입니다:
import type { GiscusProps } from "@giscus/react";
...
export const GISCUS: GiscusProps = {
repo: "[ENTER REPO HERE]",
repoId: "[ENTER REPO ID HERE]",
category: "[ENTER CATEGORY NAME HERE]",
categoryId: "[ENTER CATEGORY ID HERE]",
mapping: "pathname",
reactionsEnabled: "0",
emitMetadata: "0",
inputPosition: "bottom",
lang: "en",
loading: "lazy",
};src/constants.ts
여기서 theme을 지정하면 lightTheme과 darkTheme props가 덮어씌워져, 이전의 <script> 태그로 Giscus를 삽입하는 방식과 유사하게 정적 테마가 설정됩니다.
마지막으로 새 Comments 컴포넌트를 PostDetails.astro에 추가합니다(이전 단계의 script 태그를 대체합니다).
import Comments from "@/components/Comments";
<ShareLinks />
<Comments client:only="react" />
<hr class="my-6 border-dashed" />
<Footer />src/layouts/PostDetails.astro
이것으로 완료입니다!