birchholt 직접 해보고 남기는 기록

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

티스토리 스킨(블로그 화면 전체를 만드는 템플릿 파일)을 직접 만들어 쓰는 블로그 두 개에서, 글 페이지의 댓글창이 4주 동안 화면에 없었습니다. 댓글 영역 자체가 아예 그려지지 않았고 그 자리에 아무것도 없으니 빈 공간처럼 보여서 저는 그게 정상인 줄 알았습니다.

빈 벽의 선반 자리 앞에서 자기가 쓴 소책자를 읽는 사람

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

무엇을 잘못 읽었나

멈춘 바람개비를 보고 돌아서는 사람과 등이 없는 빈 기둥

당시 증상은 글 페이지만 무한 로딩이었습니다. 스피너(빙글빙글 도는 로딩 표시)가 계속 돌고 본문이 안 떴습니다.

스킨에 댓글 치환자(서버가 내용을 채워 넣도록 스킨에 미리 두는 자리 표시)를 넣었더니 로딩이 풀렸고 저는 두 가지를 한꺼번에 해결했다고 판단했습니다 — 로딩이 풀렸으니 댓글 위젯도 떴을 것이다.

맞은 건 앞뿐이고 그마저도 이유가 달랐습니다.

당시 메모에는 무한 로딩의 후보를 두 개 적어뒀습니다. (a) 댓글이 붙을 자리 없음, (b) 발행 글 0개. 로딩을 실제로 푼 것은 (b)입니다. 글을 하나 발행하니 로딩이 끝났습니다. 같은 시점에 넣은 (a)의 치환자는 화면에 아무것도 내놓지 않는 상태 그대로 4주를 갔습니다.

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

세 층으로 다시 쟀습니다

찬 서랍과 텅 빈 서랍을 자와 돋보기, 저울로 비교하는 두 손

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

아래 세 층은 2026-09-03에 잰 값입니다. 고친 뒤의 수치는 뒤에 따로 적었습니다.

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

② 브라우저가 화면을 다 그린 뒤의 DOM. 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> 는 단순한 조건 블록이 아닙니다. 서버가 이 태그를 처리하면서 안쪽 내용 외에 바깥 구조도 만들어냅니다.

이 두 줄은 공식 문서에 적힌 설명이 아니라 출력이 나온 위치를 보고 읽은 것입니다. 공식 스킨은 <s_rp> 안에 <div class="comments"> 한 겹만 두는데, 대조군이 내려준 HTML에는 그 겹 바로 앞에 Namecard 와 여는 <div id="entry{글번호}Comment"> 가, 바로 뒤에 그 닫는 태그와 loadedComments[{글번호}] 스크립트가 붙어 있었습니다(2026-09-22 재확인).

그러니까 대조군에서 봤던 셋이 전부 이 감싸는 태그가 만들어낸 것이었습니다. 그리고 결정적으로, 그룹 밖에 있는 댓글 치환자는 그대로 지워집니다. 에러나 주석 하나 남기지 않고 그냥 사라집니다.

이건 문서에 적힌 경고가 아니라 제 스킨에서 잰 결과입니다. 티스토리 공식 스킨 문서는 <s_rp> 를 「댓글으로 접근시 이 영역 내부의 치환자가 출력됩니다」라고만 설명하고, 영역 밖에 둔 치환자가 어떻게 되는지는 적지 않습니다 (공식 문서, 2026-09-22 확인).

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

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

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

낡은 도면 뭉치를 안고 덩굴 덮인 옛 작업장 쪽 갈림길에서 멈춘 사람

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

그쪽이 오히려 옛 방식이었습니다. 지금은 서버가 만들어준 자리에 React 위젯이 스스로 목록과 폼을 그립니다. 스킨이 할 일은 이게 전부입니다 — <s_rp> 로 감싸고 그 안에 댓글 치환자를 두는 것.

<s_rp>
  <div class="comments">
    [##_comment_group_##]
  </div>
</s_rp>

공식 Poster 스킨 skin.html 345~349행을 들여쓰기만 줄여 그대로 옮겼습니다(2026-09-22 확인).

옛 HTML을 옮겨 심었으면 위젯과 손으로 적은 코드가 겹쳐 더 어려운 문제가 됐을 겁니다.

티스토리가 공개한 ray 테마의 skin.html 에는 s_rp_container·s_rp_rep·s_rp_input_form 이 그대로 있고 댓글 치환자는 한 번도 나오지 않습니다 (github.com/tistory/tistory-theme-ray). 반대로 지금 배포되는 공식 Poster 스킨에는 그 세 태그가 하나도 없고 <s_rp> 안에 치환자 한 줄만 있습니다. 두 파일 모두 2026-09-22에 받아 세어 봤고 HTTP 200이었습니다.

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

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

나란히 선 오두막 세 채의 똑같은 스위치 상자를 비교하는 사람

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

2026-09-03에 세 블로그의 댓글 설정을 나란히 놓고 비교한 결과입니다.

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

고친 뒤

창마다 화분 상자 안쪽에 맞춰 넣은 받침을 등불로 하나씩 살피는 사람

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

고친 뒤 한쪽 블로그의 글 41편을 전수로 확인했습니다. 41편 전부에서 댓글 영역이 제대로 붙었습니다.

2026-09-09 측정. sitemap에서 글 주소를 전부 모아 한 편씩 받아 댓글 영역이 몇 번 나오는지 세는 방식이고, 41편 모두 HTTP 200에 같은 개수였습니다.

이후로는 스킨을 다시 저장할 때마다 같은 검사를 한 번씩 돌립니다. 이 버그는 스킨 파일을 건드리다 감싸는 태그를 잃어버리면 조용히 재발합니다.

남은 것

갯벌의 옛 발자국 시작점에 천 깃발 달린 표지 막대를 꽂는 사람

배운 것을 한 줄로 적으면 이렇습니다. 증상이 사라진 것을 기능이 살아난 증거로 쓰지 말 것. 확인 비용은 대개 5초입니다.