Skip to content

fix(giscus): 댓글 위젯이 head로 끌려들어가 안 보이던 문제 수정 - #76

Merged
CoBool merged 3 commits into
mainfrom
claude/giscus-frame-visibility-fix
Aug 15, 2026
Merged

fix(giscus): 댓글 위젯이 head로 끌려들어가 안 보이던 문제 수정#76
CoBool merged 3 commits into
mainfrom
claude/giscus-frame-visibility-fix

Conversation

@CoBool

@CoBool CoBool commented Aug 15, 2026

Copy link
Copy Markdown
Owner

변경 내용

  • src/components/giscus-comments.tsx를 client component로 바꾸고, useEffect에서 직접 <script> 엘리먼트를 만들어 ref가 가리키는 <section> 안에 삽입하도록 변경.
  • src/app/globals.css에 giscus 공식 문서가 권장하는 .giscus-frame { width: 100%; border: none; } 규칙 추가.
  • giscus data-theme를 OS 설정(preferred_color_scheme) 대신 사이트 자체 테마(<html class="dark">)를 읽도록 바꾸고, MutationObserver + giscus의 setConfig postMessage API로 테마 전환 시 iframe을 실시간 갱신.

변경 이유

giscus 값을 처음으로 실제 채우고 확인하는 과정에서 세 가지 문제를 순서대로 발견했다.

1. 위젯이 아예 안 보임. 일반 JSX <script src="https://giscus.app/client.js">를 썼더니, React 19가 중복 제거를 위해 이 태그를 자동으로 <head>(display:none)로 끌어올렸다. giscus의 client.jsdocument.currentScript 옆에 위젯 DOM(.giscus div + iframe)을 꽂는데, 스크립트 자체가 head로 옮겨져 있으니 위젯 전체가 숨겨진 채로 렌더됐다.

2. next/script로 바꿨더니 이번엔 좌우 여백이 없음. next/script(strategy="lazyOnload")로 교체해 head 호이스팅은 피했지만, next/scriptbeforeInteractive가 아닌 전략에서는 JSX 위치와 무관하게 스크립트를 document.body 끝에 직접 appendChild한다. giscus 위젯도 그 옆에 꽂히면서 카드 레이아웃 밖, body 바로 아래 자식이 되어 버렸고, 그래서 다른 본문 콘텐츠와 달리 좌우 패딩 없이 화면 끝까지 늘어나 보였다. → ref 컨테이너에 직접 스크립트를 마운트하는 방식으로 위치를 우리가 통제하도록 다시 작성.

3. 사이트를 라이트/다크로 전환해도 giscus는 항상 다크로 고정. 이 프로젝트의 테마 스위처는 next-themes가 아니라 <html>dark 클래스를 직접 토글하는 커스텀 구현이다(src/features/theme). data-theme="preferred_color_scheme"는 OS의 prefers-color-scheme만 보고 이 클래스는 전혀 모르기 때문에, 사이트에서 라이트를 골라도 OS가 다크면 giscus는 계속 다크로 나왔다. → 초기 렌더 시 dark 클래스를 직접 읽어 data-theme을 정하고, MutationObserver로 클래스 변화를 감지해 giscus의 setConfig postMessage API로 iframe을 새로고침 없이 실시간 전환하도록 수정.

세 문제 모두 "스크립트/설정이 자기 위치나 OS 설정을 기준으로 알아서 동작한다"는 giscus의 기본 가정이, 프레임워크가 스크립트 위치를 옮기고 우리가 테마를 직접 관리한다는 이 프로젝트의 실제 조건과 어긋나서 생겼다.

검증

  • pnpm lint 통과
  • pnpm typecheck 통과
  • pnpm test — 211개 전부 통과
  • pnpm build 통과
  • 로컬 dev 서버에서 giscus.app 실제 값으로 단계별 확인:
    • iframe이 <head> 안에서 0×0으로 숨겨짐 → next/script 적용 후 보이지만 body 직속이라 풀블리드 → ref 컨테이너 마운트 후 본문과 동일한 좌우 여백으로 카드 안에 정상 렌더
    • 사이트 테마 드롭다운으로 다크 전환 → 페이지 새로고침 없이 giscus 위젯(반응 박스, 댓글 입력창, "GitHub으로 로그인" 버튼)이 즉시 다크로 전환되는 것을 스크린샷으로 확인

🤖 Generated with Claude Code

CoBool and others added 3 commits August 15, 2026 20:10
React 19 auto-hoists plain JSX <script src> tags into <head> for
dedup, and giscus's client.js appends its comment widget next to
wherever its own script tag landed — so the whole .giscus container
ended up inside <head> (display:none), collapsing the iframe to 0x0.
Never caught before because giscus had no real config until now.

Switch to next/script (renders at its JSX position instead of being
hoisted) and add the width/border rule giscus's own docs recommend
for .giscus-frame. Verified live: reactions, comment box, and
"GitHub으로 로그인" all render after this.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
next/script's afterInteractive/lazyOnload strategies append the
<script> element to document.body regardless of its JSX position, so
giscus's widget (which it inserts next to its own script tag) landed
as a direct child of <body> — outside the post card, with no left/
right padding to match the rest of the content.

Switch to a client component that creates the script element itself
and appends it into a ref'd <section>, so the widget is guaranteed to
render inside our layout. Verified: the comment box and login button
now line up with the surrounding prose instead of running edge-to-edge.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
data-theme="preferred_color_scheme" only reads prefers-color-scheme,
but this site's theme switcher is a custom implementation (no
next-themes) that toggles a "dark" class on <html> and can be set
independently of the OS. giscus never saw that class, so it stayed
on whatever the OS reported regardless of the in-app toggle.

Read the "dark" class for the initial data-theme, and watch it with a
MutationObserver to push live updates into the iframe via giscus's
setConfig postMessage API — no remount needed. Verified live: toggling
the site's theme switches the widget instantly without a reload.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@CoBool
CoBool merged commit 91aa0d4 into main Aug 15, 2026
1 check passed
@CoBool
CoBool deleted the claude/giscus-frame-visibility-fix branch August 15, 2026 11:27
CoBool added a commit that referenced this pull request Aug 15, 2026
The deploy workflow's Build step only ever set NEXT_PUBLIC_SITE_URL,
so giscus (added in #76) and Google Analytics never actually turned on
in production even after being configured — both features only exist
locally via .env.local, which is gitignored and invisible to CI.

Add the six NEXT_PUBLIC_GISCUS_*/NEXT_PUBLIC_GA_MEASUREMENT_ID values
as repository variables and wire them into the Build step's env block.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant