birchholt 직접 해보고 남기는 기록

댓글창이 4주 동안 비어 있었습니다 — 스피너가 멈춘 걸 위젯이 떴다고 읽었습니다

티스토리 스킨을 직접 만들어 쓰는 블로그 두 개에서, 글 페이지의 댓글창이 4주 동안 화면에 없었습니다. 댓글을 쓸 수 없던 게 아니라 댓글 영역 자체가 렌더되지 않았습니다. 그 자리에 아무것도 없으니 빈 공간처럼 보였고, 저는 그게 정상인 줄 알았습니다.

더 나쁜 건, 그동안 제가 댓글 문제를 이미 해결했다고 믿고 그 내용을 글로 써서 발행해뒀다는 것입니다. 스킨을 직접 만들며 깨진 것들에서 글 페이지 무한 로딩의 원인을 「댓글 마운트 자리 부재」로 단정했습니다. 그 진단은 틀렸고, 고쳤다고 생각한 것도 안 고쳐져 있었습니다.

무엇을 잘못 읽었나

당시 증상은 글 페이지만 무한 로딩이었습니다. 스피너가 계속 돌고 본문이 안 떴습니다. 스킨에 댓글 치환자를 넣었더니 로딩이 풀렸고, 저는 두 가지를 한꺼번에 해결했다고 판단했습니다 — 로딩이 풀렸으니 댓글 위젯도 떴을 것이다.

앞은 맞고 뒤는 틀렸습니다. 그리고 앞도 이유가 달랐습니다.

당시 메모에는 무한 로딩의 후보를 두 개 적어뒀습니다. (a) 댓글 마운트 자리 부재, (b) 발행 글 0개. 로딩을 실제로 푼 것은 (b) 였습니다. 글을 하나 발행하니 로딩이 끝났습니다. 같은 시점에 넣은 (a)의 치환자는 아무것도 렌더하지 않는 상태 그대로 4주를 갔습니다.

증상이 사라진 것과 기능이 살아난 것은 다른 사건인데, 같은 시각에 일어나면 하나로 보입니다. 저는 스피너가 멈춘 것을 위젯이 떴다고 읽었습니다. 그리고 확인을 안 했습니다 — 글 페이지를 열어 아래로 내려보기만 했어도 5초면 알았을 일입니다.

세 층으로 다시 쟀습니다

의심이 든 뒤에는 눈으로 보지 않고 세 군데서 따로 쟀습니다. 같은 화면을 보는 방법이 세 가지고, 셋이 서로를 검증합니다.

① 서버가 내려주는 HTML. 브라우저를 거치지 않고 curl 로 받았습니다. 댓글 영역으로 잡아둔 <div class="area-reply"> 안이 완전히 빈 문자열이었습니다. 여는 태그와 닫는 태그 사이에 공백조차 없었습니다. 이 시점에서 「JS가 늦게 붙는 중」이라는 가능성이 사라집니다. 붙을 자리가 안 왔습니다.

② 브라우저가 렌더한 뒤의 DOM. .area-reply 의 높이가 0px 였고, 티스토리가 자기 위젯을 붙일 때 쓰는 data-tistory-react-app="Comment" 노드가 없었습니다. 같은 페이지에 Reaction·SupportButton·Menubar 는 정상적으로 붙어 있었습니다. 즉 티스토리 스크립트 자체는 잘 돌고 있었고, 댓글만 붙일 자리를 못 찾은 상태였습니다.

③ 정상 블로그 대조군. 기본 스킨을 쓰는 공개 블로그(notice.tistory.com/2701)의 같은 자리를 받아 비교했습니다. 거기엔 이런 것들이 있었습니다.

<div data-tistory-react-app="Namecard"></div>
<div id="entry2701Comment">
  <div class="comments"><div data-tistory-react-app="Comment"></div></div>
</div>

그리고 페이지 끝에 loadedComments[2701] = true 가 있었습니다. 제 쪽에는 이 셋이 하나도 없었습니다. 대조군이 없었으면 「원래 이렇게 나오는 건가」에서 멈췄을 겁니다.

세 층을 나란히 놓으면 이렇습니다.

재는 곳내 블로그대조군(기본 스킨)
서버 HTML의 댓글 영역 안빈 문자열 (공백 0자)Namecard + entry{N}Comment 마크업
렌더 후 .area-reply 높이0px위젯 높이만큼
data-tistory-react-app="Comment"없음있음
같은 페이지의 다른 위젯Reaction·SupportButton·Menubar 정상정상
페이지 끝 loadedComments[{N}]없음= true
서버에 있는 댓글 데이터있음 (글 3개에 각 1건)

마지막 줄이 이 표에서 제일 아팠습니다. 데이터는 있는데 표시할 자리가 없던 상태입니다. 읽지 못한 댓글이 4주 동안 서버에 있었습니다.

그리고 넷째 줄이 범인을 좁힙니다. 다른 위젯 셋이 정상이라면 티스토리 스크립트도, 스킨 로딩 순서도, 네트워크도 아닙니다. 댓글 하나만 자리를 못 찾았습니다.

원인은 치환자가 아니라 그것을 감싸는 것이었습니다

제가 스킨에 넣은 것은 댓글 치환자 한 줄이었습니다. 그 태그는 유효한 태그가 맞습니다. 문제는 그것을 감싸는 그룹 래퍼 <s_rp> 가 없었다는 것이었습니다.

티스토리 스킨 엔진에서 <s_rp> 는 단순한 조건 블록이 아닙니다. 서버가 이 태그를 처리하면서 안쪽 내용 말고 바깥 구조를 같이 만들어냅니다.

그러니까 대조군에서 봤던 셋이 전부 이 래퍼의 산물이었습니다. 그리고 결정적으로, 그룹 밖에 있는 댓글 치환자는 빈 문자열로 치환됩니다. 에러도 아니고 주석도 아니고, 그냥 사라집니다.

이게 이 버그가 4주를 간 이유입니다. 잘못 쓰면 화면에 뭔가 이상한 게 나와야 알아채는데, 아무것도 안 나오는 방식으로 실패했습니다. 빈 자리는 「아직 안 만든 자리」와 구분되지 않습니다.

근거는 티스토리가 공개 배포하는 공식 Poster 스킨입니다. tistory1.daumcdn.net/tistory/0/pg_Poster/skin.html 을 그대로 받아보면 345~349행에 이 구조가 있습니다(2026-09-09 재확인, HTTP 200). 치환자가 <s_rp> 안에 들어가 있습니다.

하마터면 반대 방향으로 갈 뻔했습니다

원인을 찾는 도중에 한 번 더 틀렸습니다. <s_rp> 를 검색하다 보면 그 안에서 쓰는 s_rp_container·s_rp_rep·s_rp_input_form 같은 태그들이 같이 나옵니다. 예전 ray 테마 계열 스킨이 이 방식으로 댓글 목록과 입력폼을 직접 그렸습니다. 저는 그 마크업을 통째로 이식하려고 했습니다.

그쪽이 오히려 레거시였습니다. 지금은 서버가 만들어준 자리에 React 위젯이 스스로 목록과 폼을 그리므로, 스킨이 할 일은 두 줄뿐입니다 — <s_rp> 로 감싸고 그 안에 댓글 치환자를 두는 것. 옛 마크업을 이식했으면 위젯과 수동 마크업이 겹쳐 더 어려운 문제가 됐을 겁니다.

「검색 결과에 나온다」와 「지금 쓰는 방식이다」는 다릅니다. 스킨 태그는 문서화가 얇아서 블로그 글로 배우게 되는데, 그 글들의 작성 시점이 잘 안 보입니다. 공식 스킨을 직접 받아 보는 쪽이 빠르고 정확했습니다.

관리자 설정은 무죄였습니다

원인을 확정하기 전에 「혹시 댓글 허용이 꺼져 있나」를 의심했습니다. 관리 화면의 댓글 설정을 두 블로그와 대조군에서 확인했더니 셋 다 같았습니다 — 댓글 허용 켜짐, 승인 필요 없음, 비회원 작성만 꺼짐.

마지막 항목은 설정된 동작이라 버그가 아닙니다. 다만 비회원에게는 작성할 때 로그인 유도가 뜨므로, 「댓글이 안 달린다」는 제보를 받으면 이것과 위젯 미렌더를 구분해야 합니다. 증상이 비슷하고 원인이 완전히 다릅니다.

고친 뒤

두 스킨 모두 댓글 영역 안쪽을 <s_rp> 로 감쌌습니다. 위젯이 서버가 만든 래퍼 안에 붙으므로, 그 래퍼까지 본문 폭 안에 들어오도록 <s_rp> 를 기존 컨테이너 안쪽에 두었습니다. 바깥에 두면 댓글 영역만 본문보다 넓게 튀어나옵니다.

고친 뒤 한쪽 블로그의 글 41편을 전수로 확인했습니다. 41편 전부에서 댓글 영역이 정상 마운트됐습니다. 그리고 이후 스킨을 다시 저장할 때마다 같은 검사를 한 번씩 돌립니다 — 이 버그는 스킨 파일을 건드리다 래퍼를 잃어버리면 조용히 재발합니다.

남은 것

배운 것을 한 줄로 적으면 이렇습니다. 증상이 사라진 것을 기능이 살아난 증거로 쓰지 말 것. 둘은 같은 시각에 일어나도 다른 사건이고, 확인 비용은 대개 5초입니다.