La decodificación de 200KB que nadie necesitaba repetir
Mi generador de tarjetas OG incluye una fuente de reserva para que quienes lo usan no tengan que proveer la suya. Está guardada como un string en base64 incrustado en el paquete, porque el parser de fuentes de satori no puede leer fuentes variables, y esto evita el problema por completo al usar un peso estático. Cada vez que la librería generaba una tarjeta, decodificaba ese string en base64 de vuelta a bytes crudos. Cada vez, sin excepción. Incluso al generar cincuenta tarjetas en el mismo build, para cincuenta posts distintos, usando la misma fuente.
El fix es un solo if
let cachedFonts: SatoriFont[] | null = null;
export async function defaultFonts(): Promise<SatoriFont[]> {
if (!cachedFonts) {
cachedFonts = [
{ name: 'Space Mono', data: Buffer.from(regularBase64, 'base64'), weight: 400, style: 'normal' },
{ name: 'Space Mono', data: Buffer.from(boldBase64, 'base64'), weight: 700, style: 'normal' },
];
}
return cachedFonts;
}
Ese es todo el cambio. Decodificar una vez, guardar el array en caché, y devolver la misma referencia todas las veces después. El tipo de fix que apenas se siente digno de una línea en el changelog.
La prueba que realmente importa acá
La versión fácil de esta prueba llama a defaultFonts() y verifica que las fuentes se vean bien: nombre, peso, que los datos sean un Buffer real con contenido real. Es una prueba válida, pero pasaría igual sin importar si la memoización funcionara o no, porque solo llama la función una vez.
La prueba que realmente demuestra algo la llama dos veces y verifica identidad, no igualdad:
test('defaultFonts memoizes - repeat calls return the identical buffer instances', async () => {
const first = await defaultFonts();
const second = await defaultFonts();
assert.equal(first, second, 'should return the same cached array, not a fresh one');
assert.equal(first[0].data, second[0].data, 'should return the same buffer instance');
});
assert.equal sobre dos Buffers verifica identidad de referencia acá, no igualdad de contenido byte por byte como haría assert.deepEqual. Dos buffers recién decodificados con los mismos bytes fallarían esta prueba, y ese es justamente el punto. Todo el bug era “decodifica los mismos bytes dos veces,” así que una verificación de igualdad de contenido pasaría sin problema incluso en la versión rota. La única prueba capaz de distinguir “memoizado” de “no memoizado, pero consistente” es una que verifique que ambas llamadas devolvieron literalmente el mismo objeto.
Por qué valía la pena hacer este fix
Es un fix pequeño para un problema pequeño. Que un solo build decodifique un par de cientos de KB de base64 unas cuantas docenas de veces de más no le va a arruinar el día a nadie. Pero se acumula de forma invisible: un sitio con cien posts que genera una tarjeta por post paga este costo cien veces por cero beneficio, y nada en el síntoma (un build un poco más lento) apunta hacia la decodificación de la fuente como causa. Barato de arreglar, fácil de pasar por alto, exactamente el perfil de bug que vale la pena sacar del backlog incluso cuando todavía nadie se está quejando.
Lecturas relacionadas
El error de escape que solo aparece con un segundo parámetro de consulta
Una función de reescritura que funcionaba en cada prueba y cada URL real que había visto, y aun así se habría roto en el momento en que alguien agregara un segundo parámetro de consulta.
Probar la parte del código que documenta su propia trampa
Una advertencia en el README sobre un modo de fallo sutil es una confesión de que el código todavía no tiene pruebas para eso.
Demostrar que un fallback realmente funciona como respaldo
Una prueba que pasa sin importar si la opción de anulación funciona no es una prueba, es una moneda al aire que por casualidad siempre cae del mismo lado.