GioJSdocs
On this page

Font Optimization

Self-host any font as WOFF2 with correct preload headers.

List each font file in gio.toml. At startup the server puts every file in .gio/fonts/, serves it from /_gio/fonts/, and injects a <link rel="preload"> per file plus a generated @font-face stylesheet into every page's <head> - visitors never make a request to a third-party font CDN.

Declare fonts in gio.toml

Add one [[fonts]] entry per .woff2 file - one weight and style of one family. Projects created with create-giojs ship their fonts in public/fonts/ and declare them like this:

toml
[[fonts]]
family = "Fraunces"
url = "/public/fonts/fraunces-400-normal.woff2"   # a file in public/

[[fonts]]
family = "Fraunces"
url = "/public/fonts/fraunces-400-italic.woff2"
style = "italic"            # default "normal"

[[fonts]]
family = "JetBrains Mono"
url = "/public/fonts/jetbrains-mono-400-normal.woff2"

[[fonts]]
family = "JetBrains Mono"
url = "/public/fonts/jetbrains-mono-600-normal.woff2"
weight = 600                # default 400

Then use the family in your CSS:

app/globals.css
body {
  font-family: 'Fraunces', Georgia, serif;
}

Local files and remote URLs

A url takes one of two forms:

  • A url without a scheme names a file in public/, written the way it is served: /public/fonts/a.woff2 and /fonts/a.woff2 are both public/fonts/a.woff2. It is read at every start, so the server needs no network, and served under a name with a hash of its content (fraunces-400-normal-1a2b3c4d.woff2): an edited file gets a new URL on restart, so browsers and CDNs that cached the old one pick it up. A missing file stops the server at startup with its path.
  • A remote URL such as https://cdn.example.com/inter-latin-400.woff2 - downloaded on the first start and reused after that (an existing file is never fetched again). The download happens before the server starts listening, and a failed download or an error status stops startup rather than saving an error page as the font. A fresh container or a new standalone folder downloads again on its first start, so the host needs outbound HTTPS to that URL then - or keep .gio/fonts/ on a persistent volume. A file in public/ avoids both.

GIO_FONTS_DIR points the font folder somewhere other than .gio/fonts/.

Self-hosted fonts are served from /_gio/fonts, eliminating a render-blocking round-trip to an external host. Every page gets a <link rel="preload"> per font (except entries with preload = false, for fonts only used below the fold) and the generated /_gio/fonts/fonts.css with its @font-face rules (font-display: swap). The .woff2 files are cached as immutable (a URL never gets new content); fonts.css is rewritten from gio.toml on every start under the same URL, so it is served with Cache-Control: public, max-age=0, must-revalidate and revalidated via Last-Modified.

Static export

[[fonts]] is applied by the Rust server, so gio export does not see it. A static site declares its fonts with @font-face in an imported stylesheet instead; the CSS pipeline bundles the files its url()s name with hashed names:

app/globals.css
@font-face {
  font-family: 'Fraunces';
  src: url('../public/fonts/fraunces-400-normal.woff2') format('woff2');
  font-weight: 400;
  font-display: swap;
}