블로그 포스트에 댓글 기능 추가하기

2024년 1월 31일

intro

jomoo.dev 포스트에 댓글 기능을 추가하려고 한다. 현재 방문자는 없지만 블로그라면 역시 댓글 기능이 있어야 할 거 같다.

데이터베이스에 포스트 title을 key로 하여 댓글들을 배열의 형태로 저장하여 댓글 기능을 구현할까 했지만 Utterances라는 편리한 앱이 있어 이를 이용하기로 했다.

Utterances

Utterancess는 GitHub issues를 기반으로 구축된 댓글 위젯이다.
Utterances 로드 시 GitHub search API를 사용해 url, pathname, title을 기반으로 페이지와 관련된 issue를 찾아 보여 준다. GitHub에 페이지의 issue가 없는 경우 Utterances bot이 자동으로 만들어 준다.

Utterances 사이트

설치

market

GitHub의 Marketplace App에서 Utterances를 설치하고, GitHub의 모든 저장소에서 사용할지 선택한 저장소에서만 사용할지 결정한다. 선택한 저장소에서만 사용한다를 고른다.

repo 그다음 issue를 다룰 저장소를 입력해야 하는데, 저장소는 아래와 같아야 한다.

  1. public 공개 저장소여야 한다.
  2. Utterances App이 설치된 저장소여야 한다.
  3. issue 기능이 활성화되어 있어야 한다.

issue만을 다룰 저장소를 새로 만드는 게 관리하기 더 편하다고 생각해 새로 만들어 입력했다.

또한, 블로그의 포스트와 issue의 mapping을 어떤 것을 이용할지 결정해야 한다. pathname, URL, title, og:title number, term 중에 선택할 수 있다.
이 중 포스트의 pathname은 유일하면서 GitHub issue에서 봤을 때 어떤 포스트인지 알기 쉽기에 이를 선택했다.

enable 위의 과정들을 마치면 이와 같은 script 코드가 나온다. 순수 html, js로 만들어진 app은 복사 붙여넣기로 바로 이용할 수 있지만, jomoo.dev 블로그는 nuxt 프레임워크를 이용했기에 코드를 조작해줘야 한다.

components/Comments.vue

위 script 코드를 조작한 댓글 컴포넌트

components/Comments.vue
<script setup>
const utterancMap = [
  { attribute: 'type', value: 'text/javascript' },
  { attribute: 'src', value: 'https://utteranc.es/client.js' },
  { attribute: 'async', value: true },
  { attribute: 'crossorigin', value: 'anonymous' },
  { attribute: 'issue-term', value: 'pathname' },
  { attribute: 'repo', value: 'jomoo02/jomoo.dev-comments' },
  { attribute: 'theme', value: 'github-light' },
];

const comments = ref();

onMounted(() => {
  const utterances = document.createElement('script');
  utterancMap.forEach(({ attribute, value }) => utterances.setAttribute(attribute, value));

  comments.value.appendChild(utterances);
});
</script>

<template>
  <div ref="comments" class="mt-20 md:mt-28">
    <h2 class="font-medium text-slate-900 text-lg">댓글</h2>
  </div>
</template>

일단 위의 Utterances의 script 코드를 { 속성: 값 } 형태의 객체로 변환하여 담은 배열 utteranceMap을 선언한다.

onMounted 훅에서 script element를 만들어 utteranceMap 배열에 담긴 모든 속성과 값을 setAttribute 메서드로 추가한 뒤 div element comments의 자식 요소로 추가한다.
(comments는 vue의 template ref로 참조한 div 요소로, 컴포넌트가 마운트된 이후에만 접근할 수 있다.)

이제 Comments.vue 컴포넌트를 post 페이지에 추가하면 끝이다.

pages/[category]/[detail]/[post].vue

pages/[category]/[detail]/[post].vue
<template>
  <NuxtLayout name="side-bar">
    <!--  -->
    <Comments />
  </NuxtLayout>
</template>

post 페이지에 Comments.vue 컴포넌트를 NuxtLayout 태그 안 맨 뒤에 추가한다.

결과

result

정상적으로 post 페이지 맨 아래 댓글 창이 추가되어 댓글을 달 수 있게 되었다.

큰 노력 없이 댓글 기능을 추가해 만족스럽다. 하지만 불만스러운 점이 있었다.

불만과 해결

불만

dissatisfaction

위와 같이 화면이 클 때 댓글 창의 넓이가 부모 요소의 넓이에 따르질 않는다.
화면이 작을 때는 부모 요소의 넓이와 같다가 화면이 특정 넓이 이상이면 댓글 창이 더 이상 넓어지지 않는다.

Comments.vue의 css 값을 조작해도 적용되지 않았다...

해결

개발자 도구를 이용해 댓글 창의 요소들을 봤더니 댓글 창 컨테이너 요소에 max-width css style 값이 설정되어 있었다. maxWidth

댓글 창의 상위 요소에서 css 값을 설정해도 자식 요소에서 새로 css 값을 설정하기에 덮어쓰기 되어 무시되었다.
따라서 .utterances 클래스에 max-width: 760px 값을 변경하면 해결된다.

assets/css/style.css

assets/css/style.css
.utterances {
  max-width: none;
}

마무리

빠르게 댓글 기능을 추가했다. 점점 블로그다워져 가 jomoo.dev에 애착이 생기는 거 같다.
다음에는 목차 기능을 추가할 생각이다.


댓글