Giscus로 블로그 댓글 시스템 설정 및 Utterances 마이그레이션 하기

Develop
Giscus로 블로그 댓글 시스템 설정 및 Utterances 마이그레이션 하기

안녕하세요! 오늘은 Giscus를 사용하여 블로그 댓글 시스템을 제공하는 방법에 대해서 알아보겠습니다. 최근에 블로그를 보면 아시겠지만 얼마부터 제 블로그에도 Giscus를 사용하여 댓글 시스템을 제공하고 있는데요, 제가 실제로 구축해보면서 알게된 정보들을 공유드리려고 합니다. 😀

1. Giscus vs Utterances

Giscus는 깃허브의 Discussions(토론) 기능을 사용하여 손쉽고, 무료로 웹 사이트 내에 설정이 가능한 댓글 시스템입니다.


이와 유사한 시스템은 GitHub Utterances가 있는데요, Utterances도 깃허브 계정만 있다면 누구나 댓글을 작성할 수 있는 유명한 댓글 시스템입니다.


그렇다면, 이 두 시스템의 차이점은 어떤것이 있을까요? 아래 표를 통해서 비교해보겠습니다.

대표 기능UtterancesGiscus
오픈 소스OO
무료 여부OO
답글 달기닉네임을 언급하여 댓글로 작성O
블로그 글 이모지 반응XO
댓글 이모지 반응OO
저장 위치IssuesDiscussions
마지막 업데이트2022년 2월최근

기본적인 기능들은 유사하나 답글 제공 및 블로그 글에 대한 기능도 제공한다는 점에서 되게 마음에 들었고, 블로그에 Giscus 시스템을 사용해야겠다고 생각했습니다. 추가적으로, 댓글이라는 기능은 Issues (이슈) 보다는 Discussions (토론)에서 관리되는것이 좋다고 생각드네요.


그리고 최근에 저도 발견했던 Utterances의 보안 문제가 하나 있었는데요, 마지막 업데이트일을 봤을때 해결되지 않을 이슈여서 Utterances를 놔주기로 했습니다.

보안문제 관련 링크 https://github.com/utterance/utterances/issues/649

2. Giscus 설정하기

2-1. 토론 카테고리 추가 및 앱 설치

Giscus는 앞서 말씀드렸다시피 Discussions 기능으로 관리가 되는 시스템입니다. 그리고 Discussions에서 댓글로 저장하려는 토론의 카테고리를 설정해줘야 합니다.


Discussion 활성화

가장 먼저 Giscus를 등록할 Repository의 Discussions를 활성화 해주어야 합니다. 기본적으로 체크가 해제된 상태일텐데요, 이를 체크해주도록 합니다.


그리고 새로고침을 하고나면, Repository 탭에 Discussions 라는 탭이 새로 생긴걸 보실 수 있습니다. Discussions 탭을 누르고, 카테고리 메뉴로 들어갑니다.

Discussions 카테고리 메뉴

Discussions의 카테고리 메뉴로 들어오시면 기본적으로 생성된 카테고리들이 쭉 보이는데요, 새로운 카테고리를 생성하기 위해 New Category 버튼을 눌러줍니다.

Discussions 카테고리 설정

위 사진처럼 카테고리를 생성하는 페이지가 나오는데요. 카테고리 이름과 설명은 자유롭게 하되, Discussion FormatAnnouncement로 설정하는것을 추천드립니다. Announcement는 누구나 토론에 대해 댓글을 작성할 수 있지만, 토론을 생성하는것은 오직 Repository Owner만 가능한 권한 시스템입니다.


이렇게 카테고리 설정을 모두 끝냈다면, Giscus 앱 설치 페이지로 가셔서 원하는 Repository에 설치를 해주시면 됩니다. 설치하는것은 되게 쉬워서 추가적인 설명은 생략하겠습니다.

2-2. 프로젝트 연동 ⚙️

이제 본격적으로 Giscus를 설치 및 설정을 해보도록 하겠습니다. 먼저 공식 사이트에 들어갑니다.

맨 처음에는 소개글과 작동원리 등이 적혀져있는데요, 스크롤을 조금 내리면 저장소 설정란이 보입니다.

Giscus 저장소 설정

저장소 입력 형식은 사용자 이름/레포지토리 이름으로 작성해주시면 됩니다. 저의 경우엔 yiyb0603/yiyb-blog로 작성을 해주었습니다.

Discussions 설정

다시 아래로 스크롤을 내리면 페이지 - Discussions 연결 설정이 있는데요. 이 설정은 어떤 값으로 Discussions 토론을 생성할것인지를 고르는 설정입니다.

저는 페이지 title 포함을 설정하였습니다만, 주로 사용하는 설정에 대해서 간단하게 설명드리자면

  • 페이지 경로를 포함: 글의 웹 주소가 /js-async-and-defer 일때, js-async-and-defer라는 이름으로 토론이 생성됨 (쿼리 스트링 무시)
  • 페이지 title 포함: 웹 페이지 제목(HTML title 태그) 이름으로 토론이 생성됨

Discussions 연결 설정을 끝내고나면 Discussion 카테고리 선택 박스가 있는데요. 이는 아까 만들었던 카테고리를 선택하시면 됩니다.

Giscus 기능, 테마 설정

마지막으로 편의 기능 및 테마를 설정하는란이 나오는데요. 이부분은 취향껏 선택하시면 됩니다. 저는 기본 기능을 사용하였고, 테마는 라이트 모드일때는 GitHub Light, 다크모드일때는 RStudio Cobalt 테마를 사용했습니다.

2-3. Next.js 코드 연동 📜

Giscus 설치 스크립트

모든 과정을 끝내고 밑으로 스크롤 하시면 위처럼 script 코드가 자동으로 생성 되었는데요. 이 코드를 웹 페이지에 등록하면 Giscus 설치는 끝이 납니다. 저는 Next.js에서 연동했기 때문에, Next.js 코드를 작성해보겠습니다. (React.js에서도 거의 동일합니다.)


일단은 댓글을 렌더링 할 컴포넌트 파일을 아래처럼 작성해줍니다. useGiscus 라는 커스텀 훅은 다음 단계에서 작성하니, 오류가 뜨더라도 괜찮습니다.

import { useRef } from 'react';
import useGiscus from '@/hooks/giscus/useGiscus';

const PostComment = (): JSX.Element => {
  const commentRef = useRef<HTMLDivElement>(null);

  useGiscus(commentRef);

  return (
    <div
      ref={commentRef}
      margin='6rem 0 0 0'
    ></div>
  );
};

export default PostComment;

그 다음으로 useGiscus라는 이름의 커스텀 훅을 아래처럼 작성해줍시다.

import { RefObject, useRef, useEffect } from 'react';

// Giscus 설정 페이지에서 만들어준 Script 태그의 속성들을 object로 만들었습니다.
const giscusSetup = {
  id: 'giscus-comment',
  src: 'https://giscus.app/client.js',
  'data-repo': 'yiyb0603/yiyb-blog',
  'data-repo-id': 'R_kgDOJB64hA',
  'data-category': 'Blog Comment',
  'data-category-id': 'DIC_kwDOJB64hM4CaASM',
  'data-mapping': 'title',
  'data-strict': '0',
  'data-reactions-enabled': '1',
  'data-emit-metadata': '0',
  'data-theme': 'light',
  'data-input-position': 'bottom',
  'data-lang': 'ko',
  crossorigin: 'anonymous',
  async: 'true',
};

const useGiscus = <T extends HTMLElement>(giscusRef: RefObject<T>): void => {
  const initializedRef = useRef<boolean>(false);

  useEffect(() => {
    if (giscusRef.current === null || initializedRef.current) {
      return;
    }

    const giscusScript = document.createElement('script');

    for (const [key, value] of Object.entries(giscusSetup)) {
      giscusScript.setAttribute(key, value);
    }

    giscusRef.current.append(giscusScript);

    initializedRef.current = true;
  }, [giscusRef]);
};

export default useGiscus;

참고로 next/script의 Script 태그를 사용하면 타입 오류가 발생하기 때문에, setAttribute 메소드를 사용하여 타입 오류없이 태그를 설정할 수 있도록 적용했습니다. 다수의 setAttribute 메소드를 사용하면 가독성이 떨어질 수 있으므로 객체를 순회하여 설정하는 코드를 작성해주었습니다.

2-4. 테마 변경기능 구현하기 🌙

대다수의 분들은 위 과정에서 끝! 이지만 제 블로그는 자체적인 테마 변경 기능을 지원하고 있습니다. 그래서 블로그 테마가 라이트모드일때와 다크모드일때 각각 Giscus의 테마를 변경하고 싶어서 찾아보았습니다.


그리고 마침내! 방법을 찾을 수 있었습니다. Giscus를 개발자 도구로 보시면 iframe 태그를 사용해서 보여주고 있음을 알 수 있는데요. postMessage 메소드를 사용하여 iframe 윈도우와 통신할 수 있도록 Giscus에서 제공합니다. 😀


테마 뿐만 아니라 이것저것 통신할 수 있도록 제공하는 것 같습니다.

관련 글 링크 https://github.com/giscus/giscus/issues/336

그렇게 라이트 모드일때는 GitHub Light 다크 모드일때는 RStudio Cobalt 테마를 사용하도록 구현할 수 있었고, useGiscus 커스텀 훅의 코드는 최종적으로 아래처럼 작성할 수 있었습니다.

import { RefObject, useRef, useEffect } from 'react';
import { SystemTheme } from '@/enums/theme';
import useTheme from '../theme/useTheme';

const giscusSetup = {
  id: 'giscus-comment',
  src: 'https://giscus.app/client.js',
  'data-repo': 'yiyb0603/yiyb-blog',
  'data-repo-id': 'R_kgDOJB64hA',
  'data-category': 'Blog Comment',
  'data-category-id': 'DIC_kwDOJB64hM4CaASM',
  'data-mapping': 'title',
  'data-strict': '0',
  'data-reactions-enabled': '1',
  'data-emit-metadata': '0',
  'data-theme': 'light',
  'data-input-position': 'bottom',
  'data-lang': 'ko',
  crossorigin: 'anonymous',
  async: 'true',
};

const useGiscus = <T extends HTMLElement>(giscusRef: RefObject<T>): void => {
  const { theme } = useTheme();

  const initializedRef = useRef<boolean>(false);

  useEffect(() => {
    if (
      giscusRef.current === null ||
      initializedRef.current ||
      theme === SystemTheme.DEFAULT
    ) {
      return;
    }

    const giscusScript = document.createElement('script');

    for (const [key, value] of Object.entries(giscusSetup)) {
      giscusScript.setAttribute(key, value);
    }

    if (theme === SystemTheme.LIGHT) {
      giscusScript.setAttribute('data-theme', 'light');
    } else {
      giscusScript.setAttribute('data-theme', 'cobalt');
    }

    giscusRef.current.append(giscusScript);

    initializedRef.current = true;
  }, [giscusRef, theme]);

  useEffect(() => {
    if (theme === SystemTheme.DEFAULT) {
      return;
    }

    const giscusIframe =
      document.querySelector<HTMLIFrameElement>('.giscus-frame');

    if (giscusIframe === null) {
      return;
    }

    giscusIframe.contentWindow?.postMessage(
      {
        giscus: {
          setConfig: {
            theme: theme === SystemTheme.LIGHT ? 'light' : 'cobalt',
            // 라이트 모드일때는 GitHub Light, 다크 모드일때는 RStudio Cobalt 테마 사용
          },
        },
      },
      'https://giscus.app',
    );
  }, [theme]);
};

export default useGiscus;

3. Utterances에서 마이그레이션 🛻

이번 섹션은 기존에 Utterances를 사용하다가 Giscus로 마이그레이션 하는분들을 위한 섹션인데요. Issues에 등록되어 있는 댓글을 Discussions로 옮기는 방법에 대해서 알려드리겠습니다.

Issues -> Discussions 옮기기

먼저 옮기고자 하는 Issue로 들어간다음 오른쪽 하단의 Convert to discussion을 누르고, 처음에 생성한 Discussions 카테고리를 선택하면 끝입니다.


만약 블로그 댓글이 많지 않으신분은 몇번 딸깍만 하면 끝이납니다만, 댓글들이 수많은 글에 작성되어있는 분이라면 자동화 스크립트로 하는것이 나을 것 같네요. 저는 댓글이 별로 없어서 그냥 1분만에 옮길 수 있었습니다.

4. 마치며 📌

오늘은 Giscus 댓글 시스템을 설정하여 웹에 게시하는 방법을 알아보았는데요. 기존에 Utterances만 사용하던 저에게는 정말 좋은 시스템이라고 생각드네요.👍 많은 분들이 Giscus 시스템을 설정하는데 제 글이 도움이 된다면 좋겠습니다.


이상으로 글을 마치도록 하겠습니다. 읽어주셔서 감사합니다!

타입스크립트의 공변성과 반공변성
이전글

타입스크립트의 공변성과 반공변성

타입스크립트의 타입 할당관계 규칙인 공변성과 반공변성에 대해서 알아봅시다.

Reusable Workflow로 GitHub Actions 워크플로우 재사용하기
다음글

Reusable Workflow로 GitHub Actions 워크플로우 재사용하기

GitHub Actions의 재사용 가능한 워크플로우를 사용하여 로직을 재사용 해보겠습니다.