Skip to content

[DONE] 커뮤니티의 펌웨어 안내 띠가 첫 그림부터 쪽에 있어서, 하이드레이션 뒤에 쪽 전체를 아래로 밀지 않는다 - #289

Merged
patternflow-bot merged 5 commits into
devfrom
claude/lsh-pf-round118-kqg2u7
Oct 26, 2026
Merged

patternflow-bot merged 5 commits into
devfrom
claude/lsh-pf-round118-kqg2u7

Conversation

@patternflow-bot

@patternflow-bot patternflow-bot commented Oct 26, 2026 •

Copy link
Copy Markdown

lsh / https://claude.ai/code/session_01M3FRpN2cp7bV3HfRKRqsNS

커뮤니티의 펌웨어 띠는 닫았는지를 브라우저만 알아서 하이드레이션 뒤에야 나왔어요. 이제 닫으면 쿠키에도 적고 레이아웃이 서버에서 읽어서, 닫지 않은 사람에겐 띠가 서버 HTML 부터 있어요. 머지하면 커뮤니티 쪽을 열 때마다 폰에서 본문이 119px, 데스크톱에서 55px 뒤늦게 밀리던 일(390px CLS 0.141)이 없어져요.

좋아지는 것: 커뮤니티 쪽이 열리자마자 펌웨어 띠가 제자리에 있다 — 본문이 뒤늦게 밀리지 않는다

할 일

한 일

새 lib/community/firmwareNotice.ts 에 띠가 말하는 판(manifest.version), 쿠키 이름 pf-firmware-notice, 값이 이번 판을 닫는지 보는 firmwareNoticeDismissed 를 두었어요. FirmwareNotice.tsx 는 클라이언트 컴포넌트라서, 서버 컴포넌트인 레이아웃이 거기서 이름을 가져오면 글 대신 참조를 받아요. 그래서 따로 뺐어요.

components/community/FirmwareNotice.tsx 는 serverDismissed 를 받아 useSyncExternalStore 의 서버 값으로 써요. 전엔 () => true 였어요. 브라우저 값은 쿠키와 localStorage 가운데 하나라도 이번 판이면 「닫음」이에요. ✕ 를 누르면 둘 다에 적어요. 쿠키는 Path=/community; Max-Age=31536000; SameSite=Lax 이고 https 면 Secure 를 붙여요. localStorage 에만 닫음이 있는 사람(이 PR 전에 닫은 사람)은 처음 여는 쪽에서 쿠키를 적어요.

app/community/layout.tsx 는 cookies() 로 그 쿠키를 읽어 넘겨요. 레이아웃은 이미 headers() 를 불러 요청마다 그려지니 캐시는 그대로예요.

새 components/community/FirmwareNotice.test.tsx 는 레이아웃을 진짜로 renderToString 해요. 흉내 내는 것은 next/headers, 세션, DB, 머리줄의 다른 컴포넌트 다섯이에요. 쿠키가 없으면 띠가 있는지, 이번 판 쿠키면 없는지, 지난 판(v3.10.4) 쿠키면 다시 있는지 봐요. ✕ 가 쿠키와 localStorage 에 적는지, localStorage 에만 닫음이 있으면 서버 HTML 의 띠를 하이드레이션이 걷고 쿠키를 적는지도 봐요.

증거

스크립트를 끈 첫 그림이에요. 하이드레이션 전에 보이는 쪽이 이거예요. 닫은 적 없는 사람의 /community/patterns 예요.

폰 390 · 첫 그림 · dev
폰 390 · 첫 그림 · 이 PR
데스크톱 1440 · 첫 그림 · dev
데스크톱 1440 · 첫 그림 · 이 PR

Pi 와 같은 NEXT_PUBLIC_COMMUNITY_URL, NEXT_PUBLIC_BUILD_ENABLED 로 dev(0ef615c)와 이 PR 을 따로 빌드했어요. 스크래치 DB 마다 다섯 사람이 HTTP 로 가입해 공개 패턴 스물다섯을 올렸어요. playwright-core 1.56.1 로 네 쪽(/community, /community/patterns, /community/decks, /community/p/<id>)을 경우마다 세 번씩 새 컨텍스트로 열어 4초 봤어요. 머리줄 y 는 main header 의 위치를 rAF 로 적은 것이에요.

닫은 적 없는 사람 · 네 쪽 × 세 번        dev                                이 PR
390   로그아웃   서버 HTML 의 띠         없음                               있음
                 CLS                     0.141 (12번 모두)                  0.000 (12번 모두)
                 머리줄 y                0 → 119 (303~359ms)                119 그대로
390   로그인     CLS                     0.141~0.142                        0.000
1440  로그아웃   CLS                     0.038 (12번 모두)                  0.000 (12번 모두)
                 머리줄 y                0 → 55 (266~381ms)                 55 그대로
1440  로그인     CLS                     0.038                              0.000

닫은 사람 · 네 쪽 × 세 번                dev       이 PR
이 PR 뒤에 닫음(쿠키와 localStorage)     0.000     0.000 · 서버 HTML 에 띠 없음
이 PR 전에 닫음(localStorage 만), 첫 쪽  0.000     390 0.141 · 1440 0.038 · 띠가 서버 HTML 에 있다가 빠지고 쿠키를 적음

그 「이 PR 전에 닫음」 사람이 한 컨텍스트로 이어서 열면(390):

/community            서버 HTML 띠 있음 · CLS 0.141 · 띠 빠짐 · 쿠키 pf-firmware-notice=v3.11.0
/community/patterns   서버 HTML 띠 없음 · CLS 0.000
/community/decks      서버 HTML 띠 없음 · CLS 0.000
쿠키                  Path /community · SameSite Lax · 365일

닫은 적 없는 사람이 ✕ 를 누르면(390):

/community/patterns   서버 HTML 띠 있음 · CLS 0.000
✕ 뒤                  띠 없음 · 쿠키 pf-firmware-notice=v3.11.0 · localStorage v3.11.0
/community/decks      서버 HTML 띠 없음 · CLS 0.000
/community            서버 HTML 띠 없음 · CLS 0.000
/terms 요청의 Cookie   pf-firmware-notice 없음

서버 HTML 만 curl 로 받으면:

curl /community                                        → "Pick an edition" 1번
curl -H "Cookie: pf-firmware-notice=v3.11.0" /community → 0번
curl -H "Cookie: pf-firmware-notice=v3.10.4" /community → 1번

새 시험을 dev 의 FirmwareNotice.tsx 와 layout.tsx 로 돌렸을 때:

 × the community layout's HTML > has the notice when there is no cookie
 ✓ the community layout's HTML > leaves it out when the cookie dismisses this release
 × the community layout's HTML > has it again for a cookie an earlier release left
 × dismissing > writes the cookie the layout reads, and localStorage
 × dismissing > from before the cookie still counts, and the cookie is written for next time
      Tests  4 failed | 1 passed (5)

고친 뒤:

 ✓ src/components/community/FirmwareNotice.test.tsx (5 tests)

다섯 검사(web/ 에서, 5188651):

npm ci                              → exit 0
npm run lint -- --max-warnings=0    → exit 0
npm run typecheck                   → exit 0
npm run build                       → ✓ Compiled successfully in 15.0s · exit 0
npm run check:ci                    → Test Files 117 passed (117) · Tests 1423 passed (1423)
                                      drift: passed 14, skipped 2 (links-absolute, roadmap) · exit 0
npm run check:voice                 → check:voice: nothing found

e49c1f3 은 주석의 줄표 하나와 레이아웃의 import 차례만 바꿨어요. 거기서 lint, typecheck, 새 시험과 linkPrefetch.test.ts 를 다시 돌려 통과했어요.

실행법

# web/ 에서
npx vitest run src/components/community/FirmwareNotice.test.tsx
NEXT_PUBLIC_COMMUNITY_URL=http://localhost:3100 NEXT_PUBLIC_BUILD_ENABLED=1 npm run build
COMMUNITY_ENABLED=1 COMMUNITY_DB_PATH=<스크래치>/community.db BETTER_AUTH_SECRET=<아무 글> BETTER_AUTH_URL=http://localhost:3100 COMMUNITY_ALLOWED_ORIGINS=http://localhost:3100 npx next start -p 3100

새 창(쿠키 없음)에서 폰 폭으로 /community/decks 를 열면 띠가 처음부터 머리줄 위에 있고 본문이 움직이지 않아요. ✕ 를 누르고 새로 고치면 띠 없이 열려요.

가정

  • 이 PR 전에 닫은 사람은 이 PR 뒤 처음 여는 쪽 하나에서 띠가 서버 HTML 에 있다가 하이드레이션에 빠지며 본문이 한 번 올라가요(390 CLS 0.141). 그때 쿠키를 적어서 둘째 쪽부터는 없어요. 서버는 localStorage 를 못 읽으니 쿠키로는 이 한 번을 막지 못해요. 띠 앞에 localStorage 를 보는 inline 스크립트를 두면 막지만, 쪽마다 스크립트가 하나 느는 값에 비해 한 번뿐이라 두지 않았어요. 닫음은 판마다라 다음 릴리스에선 모두 다시 물어요.
  • 쿠키 경로는 /community 예요. 띠는 커뮤니티 레이아웃에만 있어서 다른 쪽 요청엔 실리지 않아요(/terms 요청으로 확인했어요).
  • 쿠키엔 판 이름(v3.11.0)만 들어요. 서버는 읽기만 하고 남기지 않아요. /terms 9절 「What we store」 는 서버가 남기는 것을 적는 절이라 줄을 더하지 않았어요.
  • dev 의 useDismissed 문서 주석은 서버 값이 「닫지 않음」 이라 했는데 코드는 () => true 였어요. 주석을 지금 코드대로 고쳤어요.
  • 후보 줄의 FirmwareNotice.tsx:44 · :31:45 · :52:58 과 layout.tsx:80 은 그대로였어요. <FirmwareNotice /> 는 :84 에 있었어요.
  • 390 의 CLS 는 [DONE] 로그인한 사람의 머리줄에 쪽을 열 때마다 「Sign in」 이 잠깐 뜨지 않는다 #288 의 경험대로 Playwright isMobile 없이 쟀어요. 후보 줄의 0.141 과 같은 값이 나왔어요. 후보 줄의 「로그인하면 0.1450.183」 은 [DONE] 로그인한 사람의 머리줄에 쪽을 열 때마다 「Sign in」 이 잠깐 뜨지 않는다 #288 뒤로 0.1410.142 예요. 머리줄이 처음부터 한 줄이 되어서예요.

Changelog

Web

  • The community's firmware notice is in the server's HTML for anyone who has not dismissed it. It arrived at hydration and pushed every community page down, 119px on a phone (CLS 0.141 at 390px) and 55px at 1440px. Dismissing it now writes a cookie as well as localStorage, and the layout reads the cookie.

경험

언제: Vitest 에서 useSyncExternalStore 의 서버 값과 하이드레이션 뒤 바뀜을 시험할 때
교훈: testing-library 의 render 는 새로 그려서 서버 값을 건너뛰니, renderToString 한 HTML 을 container 에 넣고 render(…, { container, hydrate: true }) 를 act 안에서 돌려 하이드레이션 길을 봐요
근거: #289 에서 localStorage 에만 닫음이 있는 사람의 띠가 서버 HTML 에 있다가 하이드레이션에 빠지고 쿠키를 적는지를 이렇게 시험했어요

바퀴

바퀴 118 · 후보 13 「펌웨어 안내 띠가 첫 그림부터 쪽에 있어서, 하이드레이션 뒤에 쪽 전체를 아래로 밀지 않는다」

다음 바퀴

  • 14위 「아이폰에서 커뮤니티 글 칸을 눌러도 쪽이 확대되지 않는다」: 폰에서 벽 검색, 댓글, 로그인 칸의 글자가 14px, 공유 링크가 12px 로 16px 아래예요.
  • 15위 「폰에서 커뮤니티 머리줄과 벽의 정렬 칸을 엄지로 누를 수 있다」: 이번에 서버 HTML 부터 서는 펌웨어 띠의 ✕ 도 18.9×21 로 그 줄에 들어 있어요.
  • 16위 「서버가 HTML 오류 쪽을 돌려줘도 커뮤니티 글 칸이 「Network error.」 대신 서버가 몇 번으로 답했는지 말한다」: response.json() 으로 읽는 28곳이 502 HTML 에 던져 끊긴 때와 같은 글을 보여요.

https://claude.ai/code/session_01M3FRpN2cp7bV3HfRKRqsNS


Generated by Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M3FRpN2cp7bV3HfRKRqsNS
@patternflow-bot patternflow-bot changed the title [WIP] pf 118바퀴 — 고를 일을 찾는 중 [WIP] 커뮤니티의 펌웨어 안내 띠가 첫 그림부터 쪽에 있어서, 하이드레이션 뒤에 쪽 전체를 아래로 밀지 않는다 Oct 26, 2026
The banner came in at hydration and pushed the page down 119px on a phone.
A dismissal now goes into a cookie too, and the layout reads it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M3FRpN2cp7bV3HfRKRqsNS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M3FRpN2cp7bV3HfRKRqsNS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M3FRpN2cp7bV3HfRKRqsNS
@patternflow-bot patternflow-bot changed the title [WIP] 커뮤니티의 펌웨어 안내 띠가 첫 그림부터 쪽에 있어서, 하이드레이션 뒤에 쪽 전체를 아래로 밀지 않는다 [DONE] 커뮤니티의 펌웨어 안내 띠가 첫 그림부터 쪽에 있어서, 하이드레이션 뒤에 쪽 전체를 아래로 밀지 않는다 Oct 26, 2026
@patternflow-bot
patternflow-bot marked this pull request as ready for review October 26, 2026 18:23
@patternflow-bot
patternflow-bot merged commit 9761f94 into dev Oct 26, 2026
2 checks passed
@patternflow-bot
patternflow-bot deleted the claude/lsh-pf-round118-kqg2u7 branch October 26, 2026 18:23
engmung pushed a commit to engmung/Patternflow that referenced this pull request Oct 27, 2026
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.

2 participants