logo hsb.horse
← Voltar para o índice do blog

Blog

Notas sobre tentativas fracassadas de recuperar arquivos WOFF do Google Fonts no navegador

Um registro de tentativa e erro ao tentar obter arquivos ttf/otf/woff do Google Fonts no lado do cliente e usá-los com @vercel/satori. Resolvemos as limitações do cabeçalho do User-Agent e os problemas de incompatibilidade do woff2.

Publicado:

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

  1. O usuário insere o nome e o estilo da fonte
  2. Obtenha CSS da API Google Fonts
  3. Extraia o URL do arquivo de fonte do CSS
  4. Baixe o arquivo da fonte
  5. 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

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.