자고로 블로그라면, 그래도 댓글로 소통하는 공간이 필요하다고 생각했다.
물론 내 블로그에 와서 누군가 관심 가져주고 댓글을 많이 달아주겠지! 라는 기대는 크게 하지 않고 있지만 말이다.
하지만, 이 블로그는 단순히 나의 기록을 담는 역할 뿐 아니라, 다양한 것을 시도하고 또 녹여내는 공간으로 사용하기로 마음 먹은 만큼, 되든 안되든 이런 저런 요소들로 채워나가 보고 싶었다.
그래서 어쨌든, 댓글을 달 수 있게 했다!
혼자서 신나가지고 글 작성하고 이래저래 테스트해보는데, 기본적으로 SPA 웹페이지에 대해서는 대응이 안되어 있는 탓인지 구조를 약간 수정해야 했다. 자세한 내용은 아래에 추가하였다.
Comentario
그래서 Comentario라는 녀석은 뭐하는 녀석인가?
정적 웹사이트용 오픈소스 댓글 엔진 Comentario - 소개 및 한국어 지원 추가 - inchan.dev
이 블로그에 소개된 것에 의하면, 심플한 디자인에 오픈소스 댓글 엔진인 Commento를 fork하여 만들어진 파생 프로젝트라고 한다. 원본인 Commento 홈페이지에 들어가보니 이미 없어져서 도메인 팔고 있음- 화면이 나를 반기고 있었다.
배경
그럼 왜 나는 Comentario를 선택했는가? 이미 많이들 사용하는 것으로 알려진 Disqus나 LiveRe 같은 소셜 로그인 기능이 추가된 서비스를 왜 사용하지 않았는가?
1. 광고 문제
처음에는 Disqus를 붙일 생각으로 알아보고 있었는데 생각보다 광고 문제가 화제가 되어 있었다.
외부 호스팅 서비스를 무료로 제공하려고 한다면 당연히 서버 유지비가 해당 서비스 측에 부과되기 때문에 어쩔 수 없는 조치라고 이해는 가지만, 이 블로그에 광고를 붙이고 싶지는 않았다. (아직까지는...)

2. 디자인 문제
Disqus는 일단 깔끔하지만 그러한 문제들로 인해 사용을 뒤로 하고, LiveRe를 살펴보았다.
그런데 이거... 디자인이 아무래도 좀 구려보였다. 그리고 어딘가 모르게 인터넷 기사 댓글창에서 많이 보던 레이아웃이라서 뭔가 정이 가질 않았다.
그래서 아쉽지만 소셜 로그인 기능은 포기하고 자체 서버로 돌아가는 Comentario를 선택하게 된 것이다.
물론 이런 제3자 서비스를 이용하지 않고 직접 댓글을 구현할 수 있다. 하지만 가장 먼저 걱정되는 것은 스팸 댓글 필터링 문제와 통합 관리 기능까지 고려하면 너무 고려할 것이 많았다. 그리고 사용자 인증 부분도... 하라면 할테지만 일단 이걸로 댓글 기능 찍먹 해보고 나서 해도 되겠다는 생각이 들었다.
설치 과정
설치 과정은 매우? 간단했다. Docker Compose로 작성하고 이미지를 올려주기만 하면 되었다.
우선 Docker playground | Comentario Documentation 홈페이지에 나와있는대로 Docker Compose 스크립트를 작성해서 실행시켜주었다.
docker-compose.yml:
services:
db:
image: postgres:17-alpine
environment:
POSTGRES_DB: comentario
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
ports:
- "5432:5432"
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
timeout: 5s
retries: 5
start_period: 10s
app:
image: registry.gitlab.com/comentario/comentario
environment:
BASE_URL: http://localhost:8080/
SECRETS_FILE: "/secrets.yaml"
ports:
- "8080:80"
healthcheck:
test: ["CMD", "wget", "-O", "-", "http://localhost/api/user"]
timeout: 5s
retries: 5
start_period: 5s
depends_on:
db:
condition: service_healthy
volumes:
- ./secrets.yaml:/secrets.yaml:ro여기서 주인장은 API를 프록시하여 던질 예정이라 BASE_URL 부분은 프록시 될 주소를 작성해 주었다.
주인장은 라즈베리파이에 OpenMediaVault를 설치하여 사용하고 있고 여기에는 Compose 플러그인이 있어 웹 환경에서 Compose를 작성하고 실행시킬 수 있다.
그리고 DB 관련 설정 파일도 같은 폴더에 만들어 줘야 한다고 한다.
secrets.yaml:
postgres:
host: db
port: 5432
database: comentario # db쪽 설정에서 POSTGRES_DB
username: postgres # db쪽 설정에서 POSTGRES_USER
password: postgres # db쪽 설정에서 POSTGRES_PASSWORD이제 같은 폴더에 만들어 docker compose up 명령어를 실행시키면 컨테이너가 만들어진다.
주인장은 웹 환경에서 작성한 관계로 secrets.yaml 파일을 별도로 만들어 volumes에 직접 위치를 지정해 주었다.
컨테이너가 생성되었고 database, username, password가 정상적으로 입력이 되었다면, 위에 BASE_URL에서 지정한 주소로 접속하면 로그인 페이지가 나온다.
여기에서는 Sign up here를 클릭해 새로운 계정을 만들면, 최초로 만든 그 계정이 관리자 계정이 된다고 한다.
로그인을 해보면,
현재 화면은 이미 계정 생성 및 도메인을 추가하여 보이는 화면이고 처음 설치의 경우에는 이렇게 나오지 않을 것이다.
다음 단계에서 도메인을 추가해보자.
도메인 추가
이제 댓글 기능을 연결할 도메인을 추가해야 한다.
우측에 Domains를 누르면 현재 도메인 목록이 나오는데, 여기에서 New domain을 클릭해주자.
그러면 기본적으로 호스트(Host)를 입력하기만 하면 도메인 추가가 완료되지만, 추가적으로 설정을 바꾸고 싶다면 확인하고 바꿔주면 된다.
인증 방법으로는 SSO도 지원한다고 하는데, 아직 주인장은 아직 본인 이외에 다른 사람을 가입시키거나 할 예정이 없기 때문에 SSO 지원은 일단 비활성화 하였다. 기본적으로 이메일 주소와 비밀번호를 입력하여 가입해야 댓글을 달 수 있게 되어 있는데, 원한다면 가입 없이도 댓글을 달 수 있는 것으로 보인다.
추가가 완료되었으면 이제 스크립트를 원하는 사이트에 설치하면 된다. 주의할 점은, 추가한 도메인과 동일한 사이트에 추가해야 한다는 것이다. 도메인이 다르면 댓글을 달 수가 없게 되어 있다.
Options를 클릭하면 여러가지 관련된 설정을 변경하여 사이트 입맛에 맞게 약간 조절해줄 수 있는데, 자체 폰트를 꺼 사이트를 따르도록 만들 수 있으며, 언어와 스타일시트도 별도로 불러와서 적용되게끔 할 수 있다. 설정을 바꾸면 스크립트도 바뀌게 되니, 바뀐 스크립트로 사이트에 설치하면 된다. CSS URL 부분은 테스트해봤는데 저렇게 상대주소로 하면 경고 표시가 나타나지만, 작동에는 문제가 없었다.
스크립트 설치
스크립트는 원하는 페이지의 원하는 위치에 위 두 코드를 넣어주기만 하면 된다. 웹 프레임워크를 사용하는 경우 <script> 태그는 중간에 삽입하지 못하도록 되어 있는 경우가 있다. Svelte의 경우가 그런데, <svelte:head> 태그를 윗부분에 만들어서 그 안에 넣어주면 문제가 해결된다.
설치 완료!
이게 끝이다. 설치가 완료되면 사이트에 박아뒀던 위치에 이렇게 잘 댓글 기능이 추가된 것을 볼 수 있다.
스타일 관련해서
일단 기본 스타일 자체도 깔끔하고 괜찮긴 한데, 주인장 블로그 기본 글씨 크기랑은 기준이 다른 문제가 있었다.
주인장 블로그는 글씨 크기를 16px(1em)로 설정해 두었는데, Comentario는 15px이었다. 이로 인해 댓글창의 요소가 너무 작게 느껴졌다.
거기다가 댓글 입력 영역과 버튼은 또 HTML의 기본 스타일이 적용되어 있어 더 작게 보였다.
이 문제를 해결하기 위해 위에서 도메인 추가할 때 CSS 옵션을 넣어줬고, 별도의 CSS 파일을 만들어 적용시켰더니, 그제야 통일감 있는 모습으로 보이게 되었다.
.comentario-root,.comentario-root .comentario-add-comment-host, .comentario-root textarea, .comentario-root button {
font-size: 1em;
}
.comentario-root .comentario-toolbar .comentario-btn-tool {
width: 40px;
height: 40px;
}
.comentario-root .comentario-btn {
padding: 0.5em 1em;
}
.comentario-root .comentario-footer {
margin-top: 0
}암튼 이제 댓글 기능도 추가했고, 점차 그럴듯한 블로그 모습이 되어가고 있다.
하루하루 뿌듯함을 느끼고 있다.
SPA 방식의 라우팅의 경우
일단 이렇게까지 하면 최초 게시글에 접속했을 때에는 댓글창이 정상적으로 나타나는데, 다른 게시글로 이동할 때에나 사이트 내에서 다른 곳에 갔다가 오면 댓글이 정상적으로 표시되지 않는 문제가 발생한다.
1. 다른 게시글로 이동할 때
<이동 전>
<이동 후>
2. 다른 페이지 (사이트 내에서) 이동했다가 다시 게시글을 볼 때
따라서 이 문제를 해결하기 위해 구조를 바꿔야 했다.
스크립트 태그는 전역에다가
일단 스크립트를 대충 보니 요소 초기화 후 작동하는 스크립트는 아닌 것으로 보여, 스크립트 태그를 app.html쪽으로 옮겨주었다.
app.html:
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
...
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script defer src="https://comments.hmlee.me/comentario.js"></script>
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>수동으로 초기화되도록
그리고, comments라는 변수를 하나 만들고 comentario-comments 태그에는 auto-init="false" 속성을 넣어주었다.
{#if comments}
<comentario-comments auto-init="false" id="comments" lang="ko" css-override="/comentario.css"></comentario-comments>
{/if}다음으로 스크립트 파트에서는 페이지 마운트 시 요소를 수동으로 초기화하는 코드를 넣고, 게시글->게시글 간 이동의 경우 onMount()가 발동하지 않으므로, 현재 페이지의 pathname이 변경되었는지를 감지하여 발동될 수 있도록 $effect()를 활용하였다. comments 변수를 활용 하여 요소가 파괴되었다가 다시 생성될 수 있도록 하였다.
<script lang="ts">
...
import { onMount } from 'svelte';
import { page } from '$app/state';
...
let comments = $state(false);
...
onMount(()=>{
comments = true;
document.querySelector('comentario-comments')?.main();
});
$effect(()=>{
if (page.url.pathname) {
comments = false;
setTimeout(()=>{
comments = true;
document.querySelector('comentario-comments')?.main();
}, 0);
}
})
</script>타입스크립트 대응
이대로만 하면 작동에는 문제가 없는데, 타입 오류가 발생한다.
Gemini의 도움을 받아 app.d.ts에다가 커스텀 클래스에 대한 속성을 넣어주었다.
declare global {
namespace App {
...
interface HTMLElementTagNameMap {
'comentario-comments': HTMLElement & {
main(): void;
};
}
...
}
export {};이렇게 하고 나서야 비로소 제대로 작동이 되게 되었다.