Experience of building a complete? font optimization package for Astro websites
Tags: webdev, javascript, programming, tutorial
Published: 2024-01-11 13:24:19

Rishi is always in awe of how [Vercel](https://vercel.com) promotes open-source and use it as the medium to grow, staying relevant to developers. Not long ago, `next/font` was released and it set a great bar of how fonts DX (and ultimately UX) shall be.

As you'd know, Rishi loves [Astro](https://astro.build), so he thought of bringing this automatic font optimization to the Astro ecosystem. He set out for building `astro-font` inspired by `next/font` which'd:

- let one specify a config and generate CSS based on off of it
- generate fallback font CSS preventing layout shifts
- allow to optionally preload fonts for best font loading practices

> Rishi is an [Astro Community Award Winner in 2022](https://astro.build/blog/community-awards-22/). Also, he's building [LaunchFa.st - Astro Boilerplate](https://launchfa.st).

On 15th December, 2023, Rishi released `astro-font` the community first npm package that aimed at enabling font optimization in all runtimes with Astro. Today, the adpotion has scaled to 4.4K NPM Downloads, LaunchFa.st maintaining a [changelog](https://www.launchfa.st/blog/astro-font-changelog) for `astro-font` and people loving the ease of setting up Astro Font in their projects 👇🏻

{% twitter 1745337344495153228 %}

Well, it's not all silver bullets. Here are some of the roadblocks Rishi faced in developing the ideal library for fonts (and still working on it):

**1. Supporting all Astro adapters**

As `astro-font` is an Astro component (allowing greater granular control) and not an Astro [integration](https://docs.astro.build/en/reference/integrations-reference/), it became increasingly difficult to detect the runtime (Node, Deno, etc.) and adjust the operations such as fetching & reading font buffer, localizing fonts to the project repo, cache & save the generated CSS in the right output directory.

This is still the reason why `astro-font` requires some work to support atomic + SSR-first Astro projects. Packages like [carton](https://github.com/lilnasy/gratelets/tree/main/packages/carton) aim at bridging this technical gap by allowing to render components in isolation, de-coupling it from the project specific requirements.

**2. Detecting if read & writes are allowed**

All of the sites today are built on two systems: user's local and on the cloud. Both runtimes use different OS (say developing on windows and deploying on ubuntu) AND read and write permissions (based on the cloud provider and configurations).

To detect this `astro-font` tries and handles the failure to do so. For example to check if file system module is accessible and writes are allowed:

```typescript
// Check if file system can be accessed
async function getFS(): Promise<typeof import('node:fs') | undefined> {
  let fs
  try {
    fs = await import('node:fs')
    return fs
  } catch (e) {}
}

// Check if writing is permitted by the file system
async function ifFSOSWrites(dir: string): Promise<string | undefined> {
  try {
    const fs = await getFS()
    if (fs) {
      const testDir = join(dir, '.astro_font')
      if (!fs.existsSync(testDir)) fs.mkdirSync(testDir)
      fs.rmSync(testDir, { recursive: true, force: true })
      return dir
    }
  } catch (e) {}
}
```

Well, that was it. Hope you gained some insight into what's going on with `astro-font` and Rishi's excitement around it.

Drop your suggestions & feedback on Astro Font, or just some tips for someone learning to build a npm package and help developers!