OG 이미지 카드가 잘못된 글꼴로 렌더링되는 문제: 스크린샷이 웹폰트 다운로드보다 빨랐다
요약
Open Graph 이미지 생성 시 글꼴 로딩 지연으로 인해 잘못된 기본 글꼴로 렌더링되는 레이스 컨디션 문제를 해결한 사례입니다. 핵심은 스크린샷을 찍기 전에 `document.fonts.ready`를 사용하여 글꼴 로딩이 완료될 때까지 기다리는 것입니다.
핵심 포인트
- 헤드리스 크로미움 환경에서 글꼴 캐싱 및 네트워크 지연이 문제의 원인이었습니다.
- 스크린샷 직전에 `await page.evaluate(() => document.fonts.ready)`를 추가하여 안정성을 확보했습니다.
- 글꼴을 base64로 인라인 처리하고 외부 요청을 제거하여 렌더링 속도를 크게 개선했습니다.
지난달에 제가 만든 소셜 미리보기 카드 몇 개가 잘못된 글꼴로 렌더링되기 시작했습니다. 저는 제목과 설명을 이용해 1200x630 템플릿으로 Open Graph 이미지를 생성하는데, 이 카드들은 특정 디스플레이 글꼴을 사용해야 합니다. 그런데 일부는 대신 기본 세리프(serif) 글꼴로 나왔습니다. 오류나 경고 메시지는 없었고, 그저 보기 안 좋은 텍스트만 있었습니다.
패턴이 단서였습니다. 배포 후 첫 번째 렌더링에서만, 또는 콜드 컨테이너(cold container)에서만 발생했습니다. 로컬 환경에서는 모든 것이 완벽했습니다. 이는 캐싱 문제처럼 느껴졌고, 실제로도 그랬습니다. 제 코드가 아닌 브라우저 글꼴 캐싱이 원인이었습니다.
제 생성기는 헤드리스 크로미움(headless Chromium)에서 HTML 템플릿을 렌더링하고 스크린샷을 찍습니다. 제 코드는 goto(url) 다음에 가능한 한 빨리 screenshot()을 실행했습니다. 개발 환경에서는 woff2 파일이 이미 크로미움의 디스크 캐시에 있었기 때문에 '즉시' 로드되었습니다. 하지만 새로운 컨테이너에서는 글꼴이 글꼴 호스트(font host)로부터 이동해야 했고, 이 과정은 200ms에서 800ms까지 걸렸습니다. 그리고 크로미움은 기다리는 동안 유용하게 기본 글꼴로 페인팅합니다. 제 스크린샷은 절대 기다리지 않았습니다. 저는 제가 통제할 수 없는 네트워크 타이머 위에서 레이스 컨디션(race condition)을 배포하고 있었던 것입니다.
핵심 해결책은 한 줄이었습니다: 스크린샷 전에 await page.evaluate(() => document.fonts.ready)를 추가하는 것이었습니다. 이 Promise는 글꼴 로딩이 안정화되면 해결됩니다. 그 후 저는 레이스 자체를 완전히 제거했습니다. 이제 글꼴은 템플릿에 base64로 인라인(inlined)되어 외부 요청을 할 필요가 없어졌습니다. 중간 콜드 렌더링 시간은 약 1.1초에서 약 300ms로 떨어졌고, 결과물은 결정론적(deterministic)이 되었습니다.
제가 얻은 두 가지 교훈입니다:
- 헤드리스 렌더링의 경우,
이제 생성기는 항상 올바른 카드를 만듭니다. 저는 이 기능을 https://x402.freeq.one/tools/og_image_generator.html API로 패키징했으며, 폰트 인라인(font-inlining) 수정 사항을 영구적으로 적용했습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기