# 댓글 시스템 연동하기
# 서두
VuePress는 아직까지 기본적으로 댓글 시스템을 연동하는 플러그인이 없다. 하지만 구글링 해보니 컴포넌트를 활용하여 댓글 시스템을 연동하는 hack이 존재하길래 적용해 보려 한다.
TIP
작성 시점의 안정화 버전은 v0.14.8이며, v1 버전에서는 플러그인 기능이 추가될 예정이다.
현재 알파버전 v1.0.0-alpha.27이 개발중이다.
# 댓글 서비스 Disqus
댓글 서비스를 찾아보니(Blog comment hosting service | Wikipedia (opens new window)) 그렇게 경쟁이 치열하진 않은듯 했다. 제대로 홈페이지가 있는 서비스는 두 곳 정도인데, Discourse (opens new window)라는 곳은 서비스는 좋아 보이는데 무료는 Trial 뿐이었다. Disqus (opens new window)는 곳도 괜찮아 보이며 무료가 존재했다.
VuePress와 조합하여 검색해보니 Disqus를 연동했다는 해외 블로거를 찾을 수 있었다. Add Disqus support to VuePress pages | K33G's website (opens new window)
꽤 간단히 해결된 것 같았다. 따라해보자.
# Disqus 가입 및 설정
Disqus 서비스에 가입하고 내 사이트 항목을 추가하자. 이건 어려운 부분이 없으니 생략한다.
중요한 것은 내 사이트를 추가하고 shortname을 획득해야 하는 부분.
# 컴포넌트 작성
매우 간단하다. 해당 블로거의 소스를 긁어다 넣으면 된다.
주의할 점은 소스의 YOURHANDLE
부분에 Disqus의 shortname을 넣으면 된다.
나의 경우는 62che이다. 이로써 모든 작업이 끝났다! 간단하다!
<!-- docs/.vuepress/components/Disqus.vue -->
<template>
<div id="disqus_thread"></div>
</template>
<script>
export default {
mounted() {
if (!/localhost/.test(window.location.origin)) {
let disqus_config = function () {
this.page.url = window.location.origin;
this.page.identifier = window.location.pathname;
};
(function() {
let d = window.document, s = d.createElement('script');
s.src = 'https://YOURHANDLE.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
}
}
}
</script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
TIP
개발중에는 로드되지 않도록 9번 줄처럼 정규식을 추가했다.
# 페이지에 삽입
단순히 페이지에 컴포넌트만 추가하면 된다.
<Disqus />
# 결론
이로써 매우 간단하게 댓글 시스템을 연동할 수 있었다. 다만 매 페이지마다 컴포넌트를 추가하는게 귀찮은 일이다. 태그 시스템도 그렇고 말이다. 다음엔 레이아웃을 수정해서 기본으로 태그 시스템과 댓글 시스템이 추가되도록 해보겠다.
아래는 추가된 내용입니다.
# 문제점을 발견
테스트를 해보다가 댓글이 제대로 로딩되지 않는다는 느낌을 받았다.
댓글 쓰레드는 페이지별로(정확히는 disqus_config.page.identifier
기준으로) 진행되는게 정상일텐데
다른 페이지를 띄워도 이전 댓글이 그대로 유지되는 것을 발견하였다.
그렇다. VuePress는 SPA였다. 즉 페이지를 이동하여도 브라우저 갱신이 일어나지 않는 것이다. disqus 코드는 브라우저 첫 로딩때만 동작하도록 되어있기 때문에 제대로 갱신이 되지 않았던 것이다.
# 해결을 하자
문제는 두가지였다.
- 갱신을 어떻게 할 수 있나?
- 어디에서 호출해야 하나?
disqus refresh
라는 키워드로 정보를 찾다가 힌트를 발견하고, 개발자 도구를 띄우고 방법을 찾아보았다.
찾은 방법은 이렇다.
> DISQUS.reset({ reload: true })
전역변수로 DISQUS라는 객체가 노출되어 있었고, 해당 함수를 호출하니 새로이 로딩이 되었다. 생각보다 빨리 해결이 되었다.
두번째로 어디에서 호출해야 하는지를 생각해보니, 페이지가 변경될때의 후킹 메소드가 있을것 같았다.
몇가지 키워드로 검색해보니, 결국은 Vue Router
의 후킹
(네비게이션 가드#Global After Hooks | Vue Router (opens new window))
을 이용해야 하는 것으로 생각되었다.
VuePress 역시 Vue 앱이고 Vue Router를 이용하기 때문이다.
그런데 VuePress의 라우터 모듈을 변경하려면 소스를 고쳐야 하나? 하고 찾아보니 역시 방법은 존재했다. 해당 링크 (Configuration#App Level Enhancements | VuePress (opens new window)) 를 참고하면 전체 모듈 오버라이딩이 가능하고, 그 중에서 라우터 쪽을 변경해보기로 했다.
// .vuepress/enhanceApp.js
export default ({
// Vue, // the version of Vue being used in the VuePress app
// options, // the options for the root Vue instance
router, // the router instance for the app
// siteData // site metadata
}) => {
// ...apply enhancements to the app
router.afterEach((to, from) => {
if (from.path !== to.path) {
if (typeof window !== 'undefined' && window.DISQUS) {
setTimeout(() => {
console.log('DISQUS is exists and try to load!')
window.DISQUS.reset({ reload: true })
}, 0)
}
} else {
// same page but hash changed
}
})
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
참고로 10번 줄이 없으면, 페이지 내에서도 해시값이 바뀔 때(화면의 헤딩 태그 등장 때)마다 호출되어서 추가해주었다. 그렇지 않으면 화면 내에서 스크롤만 해도 댓글을 다시 로드하기 때문에...
WARNING
11번 줄은 if (window && window.DISQUS)
처럼 하면 빌드시 에러가 난다.
이유는 VuePress가 SSR(Server Side Rendering)이기 때문인데, 서버에서 빌드타임에는 window 객체가 없고 undefined 에러가 난다. undefined이면 false가 되어서 if 구문이 지나갈것 같지만 애초에 빌드 에러가 나버린다.
추측컨대 빌드시 minifying 과정을 거치면서 조건문에 변조가 일어난 것으로 추정한다.
WARNING
또 하나의 주의사항. 12번 줄처럼 바로 호출하지 않고 setTimeout을 한 이유는 해당 훅의 호출 시점에는 window.location 객체가 갱신되기 전의 시점이기 때문이다. DISQUS의 설정값은 window.location을 참조하기 때문에 모든 콜스택이 비워지고 난 후에 실행되도록 하였다.
이것 때문에 몇시간동안 수많은 실험을 해가며 분석을 했다. 다른 분들께서 같은 고민으로 시간 낭비하지 않기를 바라며...
TIP
참고로 해당 파일 작성후, 개발서버를 다시 띄워야 적용된다.
# 진짜 결론
문제점을 발견하게 되어서 결국 VuePress의 후킹까지 건드리게 되었다. 아마도 v1 버전이 출시되고 플러그인 기능이 도입되면 disqus 플러그인도 제공되지 싶다. 아니면 나의 경험을 녹여 플러그인을 만들어야 겠다.