Queria gerar uma imagem usando vercel/satori no navegador.
Se você auto-hospedar os arquivos de fontes, poderá usar o satori sem problemas, mas se possível, você não deseja auto-hospedar (será problemático se o número de fontes suportadas aumentar).
Tentei baixar um arquivo de fonte via Google Font e ver se ele poderia ser usado com o satori, mas no final falhou.
Conclusão
Isso pode ser alcançado se o satori suportar woff2, mas não pode ser alcançado apenas com o front-end (lado do cliente), que atualmente não o suporta.
Isso pode ser alcançado se houver um lado do servidor.
Requisitos
- Sem lado do servidor
- Presume-se que o usuário selecione o nome e o estilo da fonte que deseja usar em [Google Fonts] (https://fonts.google.com/) e os insira no campo de entrada.
Fluxo de processamento assumido
- O usuário insere o nome e o estilo da fonte
- Obtenha CSS da API Google Fonts
- Extraia o URL do arquivo de fonte do CSS
- Baixe o arquivo da fonte
- Geração de imagens com satori
Busca CSS
O Google Font altera o formato do arquivo de fonte retornado dependendo do agente do usuário, então tentei resolver isso reescrevendo o cabeçalho User-Agent.
Porém, se você pensar bem, por se tratar de um cabeçalho proibido, ele não pode ser substituído e o plano fica paralisado aqui.
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();}O User-Agent não pode ser substituído pela busca porque é um [cabeçalho proibido] (https://developer.mozilla.org/ja/docs/Glossary/Forbidden_header_name).
Extraia dados de CSS
Se você conseguir obter CSS, a implementação é a seguinte.
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, };}No final
Então, acabei concluindo que precisava de um servidor ou proxy.
Devido a restrições do navegador (cabeçalhos proibidos, somente entrega do woff2), desistimos de implementá-lo apenas no lado do cliente.
Materiais de referência
- Carregar Google Fonts dinamicamente com JavaScript
- next.js/packages/font/src/google at canary · vercel/next.js
resumo
Tentei obter woff/ttf do Google Fonts no navegador, mas falhou devido a restrições do User-Agent e à incompatibilidade do satori com o woff2.
Precisa passar pelo lado do servidor ou proxy. Mantenha um registro do que você aprendeu com seus fracassos.
hsb.horse