툴과 개발 환경7 분 읽기

콘솔은 조용했고, 화면은 비어 있었습니다

HTML에는 요소가 다 있었고 에러는 한 줄도 없었습니다. 그런데 useEffect가 한 번도 실행되지 않았습니다. 증거는 브라우저가 아니라 dev 서버 로그에만 있었습니다.

#nextjs#debugging#gotchas#reality-check#tools
브라우저: SSR HTML에 canvas와 링크가 모두 있고 콘솔 에러 0건, 그런데 useEffect가 실행되지 않아 화면이 빈다. dev 서버 로그: Blocked cross-origin request to Next.js dev resource /_next/webpack-hmr.
증상이 브라우저에 있다고 원인도 브라우저에 있는 건 아닙니다.

소스는 A 머신에, 저는 B 머신에 있습니다. tailnet으로 이어져 있어서 A에서 npm run dev 를 띄우고 B 브라우저로 http://<A의 IP>:3000 을 엽니다. 몇 달째 이렇게 일해 왔습니다.

새 페이지를 만들었습니다. 서버 컴포넌트가 데이터를 넘기고, 클라이언트 컴포넌트가 캔버스에 애니메이션을 그립니다. 열어봤더니 완전히 빈 화면이었습니다.

조용한 증상들

하나씩 확인했습니다. 전부 정상이었습니다.

SSR HTML       <canvas width="1080" height="1920" …> 있음
               스토어 링크 2개도 있음
콘솔           에러 0건. React DevTools 안내 로그만 정상 출력
네트워크        페이지 200
서버 로그       GET /t/… 200 in 347ms

요소는 DOM에 있습니다. 접근성 트리로 읽어도 나옵니다. 에러는 없습니다. 그런데 화면은 비어 있습니다.

여기서 당신이라면 어디를 의심하겠습니까?

제가 의심한 것들

순서대로 이렇게 갔습니다.

캔버스가 배경색과 같아서 안 보이는 건가? 배경이 #0B0B14 이고 캔버스 기본색도 같았습니다. 그럴듯했지만, 그러면 스토어 배지는 왜 안 보이나. (배지는 검은색이라 진짜로 어두운 배경에 묻혀 있었습니다. 두 개의 다른 원인이 같은 증상을 만들고 있었습니다.)

비동기 자산 로딩이 안 끝나는 건가? 지도 이미지를 기다리는 코드가 있었습니다. 확인해보니 503을 0.5초 만에 돌려주고 있었습니다. 아니었습니다.

requestAnimationFrame 이 백그라운드 탭에서 스로틀되나? 이건 실제로 참이었지만, 그것만으로는 첫 프레임조차 안 그려지는 걸 설명 못 합니다.

계속 브라우저만 봤습니다. 증상이 브라우저에 있었으니까요.

증거가 있던 곳

포기하고 dev 서버 로그를 봤습니다. 거기 이렇게 적혀 있었습니다.

⚠ Blocked cross-origin request to Next.js dev resource
  /_next/webpack-hmr from "100.x.y.z".
Cross-origin access to Next.js dev resources is blocked by default for safety.
 
To allow this host in development, add it to "allowedDevOrigins"…

Next 16 의 dev 서버는 다른 호스트에서 오는 /_next/* 요청을 기본으로 막습니다. 클라이언트 번들이 안 내려옵니다. 그래서 하이드레이션이 통째로 건너뛰어집니다.

서버 컴포넌트는 서버에서 렌더되니 HTML은 멀쩡합니다. 클라이언트 컴포넌트도 SSR 결과는 나옵니다. 다만 마운트가 안 되니 useEffect 가 영원히 안 돕니다. 캔버스에 그리는 코드가 전부 거기 있었습니다.

고치는 건 세 줄입니다.

const nextConfig: NextConfig = {
  reactStrictMode: true,
  allowedDevOrigins: ["100.x.y.z", "192.168.x.y"],
};

왜 이렇게 오래 걸렸나

이 실패의 성질이 고약합니다.

정상 신호가 너무 많습니다. HTML도 있고, 200도 뜨고, React 도 로드됩니다. "React 가 로드됐다"는 사실이 "React 가 마운트했다"로 자동 번역되는데, 그게 틀렸습니다.

에러가 우리 쪽에 없습니다. 차단은 dev 서버가 하고, 그 결정을 브라우저에 알려주지 않습니다. 브라우저 입장에서는 그냥 스크립트 몇 개를 못 받은 것이고, 그건 콘솔 에러가 아닙니다.

증상과 원인이 다른 프로세스에 있습니다. 저는 증상이 보이는 쪽만 계속 봤습니다. 답이 서버 로그에만 있던 건 전에도 있었습니다 — 서치콘솔이 404 메일을 퍼부었다. 로그를 보니 범인은 내 코드가 아니었다.

자가진단 3가지

  1. "화면이 비었다"를 만나면 브라우저 콘솔보다 dev 서버 로그를 먼저 보세요. 특히 원격 호스트로 접속하는 개발 환경이라면.
  2. 하이드레이션이 실제로 됐는지 확인할 방법이 있습니까? console.log 를 이펙트 첫 줄에 한 줄 넣으면 5초면 갈립니다. SSR HTML 의 존재는 마운트의 증거가 아닙니다.
  3. localhost 가 아닌 주소로 개발 서버를 열고 있습니까? 그렇다면 보안 컨텍스트도 함께 잃습니다 — 저는 같은 환경에서 WebCodecs 가 통째로 사라진 것도 겪었습니다. 두 문제 다 localhost 로 터널링하면 사라집니다.

솔직한 부분

이건 제 코드 버그가 아니었습니다. 그래서 더 오래 걸렸습니다 — 저는 계속 제가 뭘 잘못 썼는지 찾고 있었으니까요.

결국 갈라준 건 이펙트 첫 줄에 넣은 console.log 한 줄이었습니다. 로그가 안 찍히는 걸 보고서야 "코드가 틀린 게 아니라 아예 안 돈다"로 방향이 바뀌었습니다. 진작 했으면 30분은 아꼈을 겁니다.

당신의 "안 되는데 에러가 없다"는, 정말 에러가 없는 겁니까 아니면 에러를 다른 프로세스가 삼킨 겁니까?

관련 글