25 게시글 페이지 구현하기 - Utterances 위젯 추가하기

source: categories/study/gatsby/gatsby_9-16.md

Utterances는 무엇일까?

Utterances는 Github Issue를 통한 댓글 작성 기능을 제공하는 애플리케이션입니다.

사용 방법이 매우 간편하고, 용량도 엄청 가볍기 때문에 정적 사이트에서 되게 많이 사용하는 댓글 위젯입니다.

아래 사진과 같이 마크다운 형식의 댓글을 작성할 수 있고, 여러 감정 표현도 할 수 있습니다.

Utterances을 적용하기 전에

먼저 Utterances를 사용하기 위해서는 Github에 Utterances 애플리케이션을 추가해주고, 블로그 레포지토리에 권한을 설정해주어야 합니다.

이는 Utterances 공식 문서에 해당 과정을 설명해놓았지만, 먼저 Github Utterances 애플리케이션을 설치해줘야 합니다.

Utterances 앱 링크에 접속해 애플리케이션을 Install 버튼을 통해 설치해주세요.

그러면 권한을 설정할 레포지토리를 지정할 수 있는 페이지가 나오는데, 모든 레포지토리에 권한을 부여해도 상관 없지만 해당 블로그 코드를 저장할 레포지토리를 하나 생성한 후에 이 레포지토리에만 권한을 부여하는 것을 추천드립니다.

뒤에서 Github 레포지토리를 생성하는 부분이 나오지만 Utterances를 위해 [username].github.io 이름으로 새로운 레포지토리를 생성해주세요.

React에서 Utterances를 어떻게 불러올까?

공식 문서에서는 Utterances 위젯을 불러오기 위한 스크립트 코드를 자동으로 생성해 제공해주고 있습니다.

하지만 React에서는 이 스크립트를 그대로 복사 붙여넣기 해도 적용이 되지 않습니다.

보안상의 이유도 있을테지만, 어차피 컴포넌트 내에서 그대로 스크립트 태그를 사용할 경우에는 리렌더링될 때마다 리소스를 불러오기 때문에 문제가 발생합니다.

따라서 useRef를 통해 빈 Div 요소에 연결한 다음, useEffect를 통해 컴포넌트 마운트 시에 script 요소를 생성해 이를 추가해주도록 하겠습니다.

그럼 Post 디렉토리에 CommentWidget.tsx 파일을 생성한 다음, 아래와 같이 코드를 추가해주세요.

  • src/components/Post/CommentWidget.tsx
import React, { createRef, FunctionComponent, useEffect } from 'react'

const src = 'https://utteranc.es/client.js'
const repo = '[username]/[username].github.io' // 자신 계정의 레포지토리로 설정

type UtterancesAttributesType = {
  src: string
  repo: string
  'issue-term': string
  label: string
  theme: string
  crossorigin: string
  async: string
};

const CommentWidget: FunctionComponent = function () {
  const element = createRef<HTMLDivElement>()

  useEffect(() => {
    if (element.current === null) return

    const utterances: HTMLScriptElement = document.createElement('script')

    const attributes: UtterancesAttributesType = {
      src,
      repo,
      'issue-term': 'pathname',
      label: 'Comment',
      theme: `github-light`,
      crossorigin: 'anonymous',
      async: 'true',
    }

    Object.entries(attributes).forEach(([key, value]) => {
      utterances.setAttribute(key, value)
    })

    element.current.appendChild(utterances)
  }, [])

  return <div ref={element} />
}

export default CommentWidget

이 코드를 추가한 다음, 상단의 repo 변수에 블로그 코드를 업로드할 레포지토리 이름을 작성해주어야 하는데 계정명/레포지토리명 과 같은 형태로 지정해주어야 합니다.

그럼 Script 코드를 추가하는 과정을 알아봅시다.

useEffect Hook을 통해 컴포넌트 마운트 시에 빈 스크립트 태그를 생성해주고, 필요한 속성들을 setAttribute 메서드로 추가해주었습니다.

그리고 필요한 속성이 추가된 스크립트 태그를 appendChild 메서드를 통해 빈 div 태그 내에 추가해주었습니다.

React에서는 이런 방식으로 스크립트 태그를 삽입할 수 있습니다.

이제 템플릿 컴포넌트에서 CommentWidget 컴포넌트를 불러와 적용해봅시다.

  • src/templates/post_template.tsx
// ...

import CommentWidget from 'components/Post/CommentWidget'

// ...

const PostTemplate: FunctionComponent<PostTemplateProps> = function ({
  data: {
    allMarkdownRemark: { edges },
  },
}) {
  const {
    node: { html, frontmatter },
  } = edges[0];

  return (
    <Template>
      <PostHead {...frontmatter} />
      <PostContent html={html} />
      <CommentWidget />
    </Template>
  )
}

// ...

이제 각 게시글 페이지에서 Utterances 위젯을 확인할 수 있습니다.

댓글이 잘 작성되는지 확인해주세요.

그리고, 다음과 같이 Issue가 잘 생성되는지 Github 레포지토리 페이지에 접속해 확인해보세요.

(음.. 생성이 안되는데..)
(아! public 저장소여야하는 건가?)

(맞네.. 댓글은 public 저장소여야만 가능)

Github Issue Mapping 방식

위의 코드를 살펴보면 Utterances 스크립트 태그에 지정해주는 속성 중 issue-term 이라는 속성을 확인하실 수 있습니다.

Utterances에서는 이렇게 6가지의 매핑 방식을 제공하는데, 저희가 지정한 방식인 pathname 방식은 위의 사진에서 첫 번째 방법에 해당됩니다.

이는 포스트 경로 별로 Issue가 생성된다는 말인데, 저는 제목으로 분류되도록 지정하고 싶습니다.

그러기 위해서는 3번째 옵션을 선택하면 되는데, 이를 위해 issue-term 프로퍼티의 값을 title 설정해주면 됩니다.

하지만, title Meta Tag가 존재하지 않아 실제로 적용하면 에러가 발생하면서 Utterances 위젯이 뜨지 않습니다.

따라서 이 방법은 나중에 검색 엔진 최적화를 진행하며 설정하겠습니다.