브라우저에서 vercel / satori를 사용하여 이미지를 생성하고 싶었습니다.
폰트 파일을 셀프 호스팅하면 문제없이 satori를 이용할 수 있지만, 가능하면 셀프 호스팅하고 싶지 않다(대응 폰트가 늘어나면 번거로움).
Google Font를 통해 글꼴 파일을 다운로드하고 satori에서 사용할 수 없는지 시도했지만 결론부터 말하면 실패했습니다.
결론
satori가 woff2에 대응하고 있으면 실현할 수 있지만, 대응하고 있지 않는 현상 프런트 엔드(클라이언트 측)만으로는 실현할 수 없다.
서버 측이 있으면 실현할 수 있다.
요구 사항
- 서버측 없음
- 사용자가 Google Fonts에서 사용하려는 글꼴의 이름과 스타일을 선택하고 입력란에 입력한다고 가정
예상되는 처리 흐름
- 사용자가 글꼴 이름과 스타일을 입력
- Google Fonts API에서 CSS 얻기
- CSS에서 글꼴 파일 URL 추출
- 폰트 파일 다운로드
- satori에서 이미지 생성
CSS Fetch
Google Font는 유저 에이전트에 맞추어, 반환하는 폰트 파일의 형식이 바뀌므로 User-Agent 헤더를 재기록하는 것으로 해결을 시도했다.
하지만 잘 생각하면 금지 헤더이므로 덮어쓸 수 없고, 눈론은 여기에서 좌절한다.
export const USER_AGENTS_BY_FONT_TYPE = { // IE11 as woff woff: "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko", // Googlebot as truetype ttf: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)",};
export type FontType = keyof typeof USER_AGENTS_BY_FONT_TYPE;
export async function fetchGoogleFontCSS( url: string, fontType: FontType = "ttf") { const response = await fetch(url, { headers: { "User-Agent": USER_AGENTS_BY_FONT_TYPE[fontType], }, });
if (!response.ok) { throw new Error( `Failed to load font: ${response.status} ${response.statusText}` ); }
return response.text();}User-Agent는 금지 헤더이므로 fetch로 덮어쓸 수 없다.
CSS에서 데이터 추출
만일 CSS가 취득할 수 있었을 경우의 구현은 이하와 같다.
const subsetRegex = /\/\* (.+?) \*\//;const fontFileRegex = /src: url\((.+?)\)/;
type ExtractResult = { subsets: Record<string, string>; hasItems: boolean;};
const extract = (regex: RegExp, line: string) => regex.exec(line)?.[1];
export function extractFontFromCSS(css: string): ExtractResult { const subsets: Record<string, string> = {};
let currentSubset = ""; for (const line of css.split("\n")) { const subset = extract(subsetRegex, line); if (subset) { currentSubset = subset; continue; }
const url = extract(fontFileRegex, line); if (url && !subsets[currentSubset]) { subsets[currentSubset] = url; } }
return { subsets, hasItems: Object.keys(subsets).length > 0, };}끝에
그래서 결국 서버 사이드 또는 프록시가 필요하다는 결론으로 끝.
브라우저로부터의 제약(금지 헤더, woff2만 전달)에 의해, 클라이언트 측만으로의 실현은 단념했다.
참고 자료
요약
브라우저에서 Google Fonts로부터 woff/ttf를 취득하려고 했지만, User-Agent 제한과 satori의 woff2 비대응에 의해 실패.
서버 측 또는 프록시를 통과해야합니다. 실패로부터 배운 지견으로서 기록을 남겨둔다.
hsb.horse