wandres.dev
FUENTES (FONTS API) · fuentes optimizadas

Proveedores: Google, Fontsource y local

El catálogo de proveedores integrados de Astro (Google, Fontsource, local, NPM y otros), cómo acotar la descarga con subsets, weights y styles, el proveedor local con variants y src, y la construcción de un proveedor propio con el objeto FontProvider apoyado en unifont y su primitiva defineFontProvider.

⏱ 17 min

La clave provider de cada familia decide de dónde sale la fuente, y Astro trae de fábrica un catálogo de proveedores para los orígenes más comunes, además de la puerta abierta a construir el tuyo. Todos comparten el mismo motor por debajo, unifont, que unifica catálogos tan distintos como Google, Fontsource o un registro privado bajo una interfaz común. Esta lección recorre los proveedores integrados, las palancas para descargar solo lo que usas, y cómo escribir un proveedor propio cuando ninguno de los de serie encaja.

🎯 Al terminar esta lección sabrás
  • Elegir entre los proveedores integrados: Google, Fontsource, local y NPM.
  • Acotar la descarga con subsets, weights y styles.
  • Configurar el proveedor local con variants y src.
  • Construir un proveedor propio con el objeto FontProvider sobre unifont.

El catálogo de proveedores integrados

Astro exporta sus proveedores desde astro/config bajo el objeto fontProviders. Cada uno resuelve una familia contra un origen distinto: google y bunny sirven el catálogo de Google Fonts, fontsource y npm toman fuentes publicadas como paquetes, fontshare y adobe acceden a sus respectivas bibliotecas, y local lee archivos de tu disco. Elegir uno es cambiar una línea.

---
// astro.config.mjs
import { defineConfig, fontProviders } from 'astro/config';

export default defineConfig({
  fonts: [
    { provider: fontProviders.google(), name: 'Inter', cssVariable: '--font-inter' },
    { provider: fontProviders.fontsource(), name: 'Roboto', cssVariable: '--font-roboto' },
  ],
});

google y fontsource acceden en gran medida a las mismas familias, pero por caminos distintos: el primero consulta la API de Google Fonts, el segundo resuelve paquetes de código abierto publicados en el registro de Fontsource. La familia resultante es equivalente; cambia la infraestructura que la entrega y, con ella, matices de disponibilidad y de versiones.

ℹ️
Fontsource y Google: el mismo tipo, distinto surtidor

Fontsource empaqueta las fuentes de Google (y muchas más de licencia abierta) como paquetes versionados, lo que da reproducibilidad: fijas una versión y siempre obtienes exactamente los mismos archivos. google consulta el servicio en vivo. Para la mayoría de proyectos ambos sirven; si te importa la reproducibilidad estricta o quieres resolver sin salir a la API de Google, fontsource o npm son la elección natural.

subsets, weights y styles: descargar solo lo necesario

Una fuente completa puede pesar cientos de kilobytes por variante, la mayoría de ellos glifos que tu sitio jamás mostrará. Tres claves recortan esa grasa. weights limita los grosores; styles limita entre normal y cursiva; y subsets limita los rangos de caracteres a los alfabetos que de verdad usas, como latin o latin-ext, descartando el cirílico, el griego o el vietnamita si no aparecen.

---
// astro.config.mjs
export default defineConfig({
  fonts: [
    {
      provider: fontProviders.fontsource(),
      name: 'Inter',
      cssVariable: '--font-inter',
      weights: [400, 600, 700],
      styles: ['normal'],
      subsets: ['latin', 'latin-ext'],
    },
  ],
});

Cada valor que quitas es un archivo que no se descarga. Pedir tres pesos en un solo estilo y dos subconjuntos, en lugar de la familia entera con todos sus grosores y alfabetos, puede reducir el peso tipográfico a una fracción. La disciplina aquí es la misma que con cualquier activo: no cargues lo que no vas a mostrar.

💡
Fuentes variables: un rango en lugar de una lista

Si la familia es una fuente variable, no enumeres pesos sueltos: pásale a weights un rango como cadena, por ejemplo ['100 900']. Un único archivo variable cubre entonces todo el espectro de grosores de forma continua, lo que suele pesar menos que varias instancias estáticas y te da grosores intermedios gratis. Es la opción más eficiente cuando la fuente la soporta.

Cuando necesitas combinaciones muy concretas, puedes declarar la misma familia varias veces, con idéntico name, provider y cssVariable, cambiando solo los weights o styles. Astro fusiona los resultados y descarga solo la intersección real de lo que pediste, de modo que puedes bajar el peso 500 en normal y cursiva pero el 700 solo en normal, sin traer nada de más.

El proveedor local y los proveedores propios

El proveedor local no busca en la red: declara archivos que ya tienes como variants, y cada variante es un @font-face con su src, su weight y su style. Si omites peso o estilo, Astro intenta inferirlos del primer archivo.

---
// astro.config.mjs
export default defineConfig({
  fonts: [
    {
      provider: fontProviders.local(),
      name: 'Geist',
      cssVariable: '--font-geist',
      options: {
        variants: [
          { weight: '100 900', style: 'normal', src: ['./src/assets/fonts/GeistVariable.woff2'] },
        ],
      },
    },
  ],
});

Cuando ninguno de los proveedores de serie encaja, por ejemplo si tu empresa sirve las fuentes desde un registro privado, construyes el tuyo. Un proveedor es una función que devuelve un objeto FontProvider con un name y un resolveFont, más los opcionales init y listFonts. resolveFont recibe el nombre de la familia y devuelve sus datos de fuente.

// font-provider.ts
import type { FontProvider } from 'astro';

export function registryFontProvider(): FontProvider {
  let data: Record<string, any> = {};
  return {
    name: 'registry',
    init: async () => { data = await cargarFuentesDelRegistro(); },
    listFonts: () => Object.keys(data),
    resolveFont: ({ familyName }) => {
      const fonts = data[familyName];
      return fonts ? { fonts } : undefined;
    },
  };
}

Por debajo, todo el sistema de fuentes se apoya en unifont, que expone la primitiva defineFontProvider para escribir proveedores universales. Astro sabe envolver cualquier proveedor de unifont en su propio objeto FontProvider, así que el ecosistema de resolutores de fuentes de la comunidad está a tu alcance sin reinventar nada.

flowchart LR
FAM[familia con su provider] --> UNI[capa unifont]
UNI --> BUILTIN[proveedor integrado google fontsource local]
UNI --> CUSTOM[proveedor propio FontProvider]
BUILTIN --> RF[resolveFont devuelve las font faces]
CUSTOM --> RF
RF --> FILES[Astro descarga y optimiza los archivos]
style FAM fill:#89b4fa,color:#11111b
style FILES fill:#a6e3a1,color:#11111b
🔠

google / bunny

El catalogo de Google Fonts, resuelto en vivo. La opcion mas directa para tipos populares.

📦

fontsource / npm

Fuentes abiertas como paquetes versionados. Reproducibles y resueltas sin la API de Google.

💾

local

Tus archivos como variants con src. Control total, sin dependencias externas.

🛠️

FontProvider propio

Un name y un resolveFont sobre unifont para orígenes a medida, como un registro privado.

El proveedor es una frontera de abstracción, no un origen

Lo que de verdad estás manejando cuando eliges un provider no es un servidor de fuentes, sino una frontera de abstracción cuidadosamente trazada. Fíjate en lo que permanece invariable al cambiar de proveedor: el name, el cssVariable, la forma de aplicar la fuente en CSS, todo tu diseño. Y fíjate en lo que cambia: solo la maquinaria que va a buscar los archivos. Esa asimetría es el corazón de un buen diseño de sistemas. Al interponer una interfaz común, resolveFont, entre tu declaración y el origen concreto, Astro convierte el origen de una fuente en un detalle intercambiable, tan reemplazable como el motor de una base de datos detrás de un ORM. Puedes empezar con Google por comodidad, migrar a Fontsource por reproducibilidad, y acabar sirviendo desde un registro privado por gobernanza corporativa, y en ninguno de esos saltos tu CSS se entera. Unifont lleva esta idea un paso más allá: al estandarizar la interfaz de los proveedores para todo un ecosistema, hace que un resolutor escrito para otro framework sea reutilizable en Astro sin fricción, porque ambos hablan el mismo protocolo. La lección que trasciende las fuentes es esta: cuando nombras algo por su intención, esta familia, y no por su ubicación, esta URL, ganas la libertad de cambiar la ubicación sin renombrar la intención. Las mejores abstracciones no ocultan la complejidad por pereza, sino que la aíslan tras una junta por la que puedes cambiar el mundo de un lado sin perturbar el otro.

⚔️ Cambia el surtidor sin cambiar el diseño
  1. Declara una familia con fontProviders.google() y aplícala en tu CSS; observa el resultado.
  2. Cambia solo el provider a fontProviders.fontsource() manteniendo name y cssVariable, y verifica que el diseño no se inmuta.
  3. Acota la descarga con weights, styles y subsets, y compara el peso total de las fuentes antes y después.
  4. Esboza un FontProvider propio con name y resolveFont que devuelva una familia ficticia, regístralo en la config y comprueba que Astro lo trata igual que a uno integrado.