diff --git a/src/content/docs/en/reference/experimental-flags/fonts.mdx b/src/content/docs/en/reference/experimental-flags/fonts.mdx index 7db23256e0a85..60995743fe019 100644 --- a/src/content/docs/en/reference/experimental-flags/fonts.mdx +++ b/src/content/docs/en/reference/experimental-flags/fonts.mdx @@ -152,7 +152,7 @@ body { ## Available remote font providers -Astro re-exports most [unifont](https://github.com/unjs/unifont/) providers. You can also [make a custom Astro font provider](#build-your-own-font-provider) for any unifont provider. +Astro exports a few built-in providers, based on [unifont](https://github.com/unjs/unifont/) providers. You can also [make a custom Astro font provider](#build-your-own-font-provider). The following providers have built-in support: @@ -206,7 +206,7 @@ provider: fontProviders.fontsource() provider: fontProviders.google() ``` -Additionally, the `google()` font provider accepts all options available for the [unifont Google `ProviderOption`](https://github.com/unjs/unifont/blob/main/src/providers/google.ts#L10-L26): +Additionally, the `google()` font provider accepts all options available for the [unifont Google provider](https://github.com/unjs/unifont/#options-1): ```js provider: fontProviders.google({ @@ -512,9 +512,9 @@ optimizedFallbacks: false ### Remote font properties -Further configuration options are available for remote fonts. Set these to customize the data loaded from your [font provider](#available-remote-font-providers), for example to only download certain font weights or styles. For more control, more [granular configuration](#granular-remote-font-configuration) is available. +Further configuration options are available for remote fonts. Set these to customize the data loaded from your [font provider](#available-remote-font-providers), for example, to only download certain font weights or styles. For more control, more [granular configuration](#granular-remote-font-configuration) is available. -Under the hood, these options are handled by [unifont](https://github.com/unjs/unifont/). Some properties may not be supported by some providers and may be handled differently by each provider. +Each provider is responsible for handling these options, so availability and support for the following properties may vary. #### weights @@ -846,88 +846,162 @@ export default defineConfig({ ## Build your own font provider -If you do not wish to use one of the [built-in providers](#available-remote-font-providers) (eg. you want to use a 3rd-party unifont provider or build something for a private registry), you can build your own. +If you do not wish to use one of the [built-in providers](#available-remote-font-providers) (e.g. you want to use a [3rd-party unifont provider](#supporting-a-3rd-party-unifont-provider) or [build something for a private registry](#supporting-a-private-registry)), you can build your own. -An Astro font provider is made up of two parts: the config object and the actual implementation. +The preferred method for implementing a custom font provider is to export a function that returns [the `FontProvider` object](#the-font-provider-object) and takes the [configuration](#config) as a parameter. - +### The font provider object -1. Create a function that returns a `FontProvider` config object containing: +The experimental Fonts API allows you to access fonts in a unified way. Each family requires the use of an Astro Font Provider to retrieve font faces. - - `entrypoint`: A URL, a path relative to the root, or a package import. - - `config`: An optional serializable object passed to the unifont provider. +A `FontProvider` is an object containing required [`name`](#name-1) and [`resolveFont()`](#resolvefont) properties. It also has optional [`config`](#config), [`init()`](#init) and [`listFonts()`](#listfonts) properties available. - +#### `name` - +

- ```ts title="provider/config.ts" - import type { FontProvider } from 'astro'; +**Type:** `string` +

- export function myProvider(): FontProvider { - return { - entrypoint: new URL('./implementation.js', import.meta.url) - }; - }; - ``` +A unique name for the provider, used in logs and for identification. -
+#### `resolveFont()` - +

- ```ts title="provider/config.ts" - import type { FontProvider } from 'astro'; +**Type:** `(options: ResolveFontOptions) => Awaitable<{ fonts: FontFaceData[] } | undefined>`
+

- interface Config { - // ... - }; +Used to retrieve and return font face data based on the given options. - export function myProvider(config: Config): FontProvider { - return { - entrypoint: new URL('./implementation.js', import.meta.url), - config - }; - }; - ``` +#### `config` -
+

- +**Type:** `Record`
+**Default:** `undefined` +

-2. Create a second file to export your unifont `provider` implementation: +A serializable object, used for identification. - ```ts title="implementation.ts" - import { defineFontProvider } from "unifont"; +#### `init()` - export const provider = defineFontProvider("my-provider", async (options, ctx) => { - // fetch/define your custom fonts - // ... - }); - ``` +

- :::tip +**Type:** `(context: FontProviderInitContext) => Awaitable`
+**Default:** `undefined` +

- You can check out [the source code for unifont's providers](https://github.com/unjs/unifont/blob/main/src/providers/) to learn more about how to create a unifont provider. +Optional callback, used to perform any initialization logic. Its context contains a `storage` object, useful for caching. - ::: +#### `listFonts()` -3. Add your custom provider to your font configuration. +

- ```js title="astro.config.mjs" ins="myProvider()" - import { defineConfig } from "astro/config"; - import { myProvider } from "./provider/config"; +**Type:** `() => Awaitable`
+**Default:** `undefined` +

- export default defineConfig({ - experimental: { +Optional callback, used to return the list of available font names. + +### Supporting a private registry + +The following example defines a font provider for a private registry: + +```ts title="font-provider.ts" +import type { FontProvider } from "astro"; +import { retrieveFonts, type Fonts } from "./utils.js", + +interface Config { + token: string; +} + +export function registryFontProvider(config: Config): FontProvider { + let data: Fonts = {} + + return { + name: "registry", + config, + init: async () => { + data = await retrieveFonts(token); + }, + listFonts: () => { + return Object.keys(data); + }, + resolveFont: ({ familyName, ...options }) => { + const fonts = data[familyName]; + if (fonts) { + return { fonts }; + } + return undefined; + }, + }; +} +``` + +You can then register this font provider in the Astro config: + +```ts title="astro.config.ts" +import { defineConfig } from "astro/config"; +import { registryFontProvider } from "./font-provider"; + +export default defineConfig({ + experimental: { fonts: [{ - provider: myProvider(), - // ... + provider: registryFontProvider({ + token: "..." + }), + name: "Custom", + cssVariable: "--font-custom" }] - } - }); - ``` + } +}); +``` -
+### Supporting a 3rd-party unifont provider + +You can define an Astro font provider using a unifont provider under the hood: + +```ts title="font-provider.ts" {3,5,6} +import type { FontProvider } from "astro"; +import type { InitializedProvider } from 'unifont'; +import { acmeProvider, type AcmeOptions } from '@acme/unifont-provider' + +function acmeFontProvider(config?: AcmeOptions): FontProvider { + const provider = acmeProvider(config); + let initializedProvider: InitializedProvider | undefined; + return { + name: provider._name, + config, + async init(context) { + initializedProvider = await provider(context); + }, + async resolveFont({ familyName, ...rest }) { + return await initializedProvider?.resolveFont(familyName, rest); + }, + async listFonts() { + return await initializedProvider?.listFonts?.(); + }, + }; +} +``` + +You can then register this font provider in the Astro config: + +```ts title="astro.config.ts" +import { defineConfig } from "astro/config"; +import { acmeFontProvider } from "./font-provider"; + +export default defineConfig({ + experimental: { + fonts: [{ + provider: acmeFontProvider({/* ... */}), + name: "Custom", + cssVariable: "--font-custom" + }] + } +}); +``` ## Caching