nuxt / fonts

Plug-and-play web font optimization and configuration for Nuxt apps.
https://fonts.nuxt.com
MIT License
380 stars 4 forks source link

Support for automatic `link rel="preload"` elements for fonts #24

Closed codeflorist closed 1 month ago

codeflorist commented 3 months ago

SEO- and performance-wise it makes sense to add a <link rel="preload" head-tag for the fonts used by the site.

Since font-file-names and -locations can change (e.g. because of version/hashes), it would be great, if nuxt/fonts does that automatically. Ideally it could be enabled by family, like e.g.:

{ name: 'My Font Family', provider: 'google', preload: true },
danielroe commented 3 months ago

Adding preload by default can result in over-download fonts in a blocking way as a font may not be used on the page.

This shouldn't be needed if the font face rule + font-family are inlined in the HTML.

Do you have an example where preloading the fonts with Nuxt Fonts makes a positive difference in performance? Would you suggest that setting preload: true would result in just preloading woff2 files, for example? For all weights?

codeflorist commented 3 months ago

I guess the optimal solution would be an automatic one, that dynamically creates the preload-tags for fonts, that are actually used on the current page. They must of course be in the initial HTML - so pre-generated on server.

Otherwise i would definitely make it optional - at least by family, even better by weight/style-variant.

But i guess it's safe to say, that in 95% of all projects you have 1 or 2 fonts pretty much used on every page (a normal body font and sometimes an additional display font for headers. )

Regarding the font-format, i'd only use woff2 (or make it configurable), as that's the de-facto standard now (can i use reports 97,33% support worldwide). And according to this article...

specifying preloading for multiple types of the same resource is discouraged. Instead, the best practice is to specify preloading only for the type the majority of your users are likely to actually use.

As for the actual performance advantage, i don't have any numbers. But it is recommended by google - see here). It reduces flash of unstyled text (FOUT) - a relevant metric for Google's Page Speed score (specifically FCP and LCP). Thus it should be also relevant for SEO. Here is what Page Speed has to say about it:

Consider using <link rel=preload> to prioritise fetching resources that are currently requested later in page load. Learn how to preload key requests

This shouldn't be needed if the font face rule + font-family are inlined in the HTML.

I haven't heard that before, but i guess it could be the case. But maybe preload has additional advantages, like being parsed first or getting handled with priority by the browser. But as Google recommends it, i'm sure it has at least advantages for their speed (and thus SEO) metric.

danielroe commented 2 months ago

I've released v0.2.0 with support for font preloading (you'll need to enable with fonts.experimental.addPreloadLinks). I'd appreciate any feedback or performance measurements you or others are able to do. 🙏

codeflorist commented 2 months ago

Hey Daniel,

Many thanks for the fast implementation!

Unfortunately i cannot get this to work. I have this in my nuxt config:

    fonts: {
        experimental: {
            addPreloadLinks: true
        }
    },

But no preload-link is showing up either in dev, build or generate.

danielroe commented 2 months ago

@codeflorist Could you provide a reproduction? 🙏

codeflorist commented 2 months ago

@danielroe Sure, no problem: https://stackblitz.com/edit/nuxt-starter-janegu?file=nuxt.config.ts

mklueh commented 2 months ago

I'm facing a similar issue using UnoCSS and this plugin (I guess).

unocss.config.ts

  presetWebFonts({

      //provider: 'google',

      fonts: {

        sans: "Roboto",

        serif: "Rubik",

        mono: ["Fira Code", "Fira Mono:400,700"]
      }
    })

nuxt.config.ts

  fonts: {
    experimental: {
      addPreloadLinks: true
    }
  }

And when I visit the site, I see fonts getting downloaded from static

image

Maybe I got addPreloadLinks wrong. Is something else needed to store fonts locally during build instead?

danielroe commented 2 months ago

With this module you do not need the unocss web font preset.

mklueh commented 2 months ago

Good to know, and I also was not on the latest version

agracia-foticos commented 1 month ago

please fix addPreloadLinks, the preload link tag not appears!

danielroe commented 1 month ago

@agracia-foticos Please open an issue with a reproduction 🙏

agracia-foticos commented 1 month ago

@danielroe https://stackblitz.com/edit/nuxt-starter-et4gzh here you are

There isn't any link rel="preload" with Signika hashed name Font

danielroe commented 1 month ago

@agracia-foticos Preload links are not inserted in dev mode. (improved docs just now here)

agracia-foticos commented 1 month ago

@agracia-foticos Preload links are not inserted in dev mode. (improved docs just now here)

Compiling in PROdution mode i dont see <link rel="preload" with each font

danielroe commented 1 month ago

@agracia-foticos Cloning your reproduction and running build, this was the output:

...
<style>
@font-face{font-family:Signika;src:local("Signika Variable"),url(/_fonts/vEFO2_JTCgwQ5ejvMV0Ox_Kg1UwJ0tKfX6bOjM7-f7e0Mls-xQWzOkeLSd.woff2) format(woff2);font-display:swap;unicode-range:U+0102-0103,U+0110-0111,U+0128-0129,U+0168-0169,U+01A0-01A1,U+01AF-01B0,U+0300-0301,U+0303-0304,U+0308-0309,U+0323,U+0329,U+1EA0-1EF9,U+20AB;font-weight:300 700;font-style:normal}
/** removed more font faces here */
#element{font-family:Signika, "Signika Fallback: Arial"}</style>
<link rel="stylesheet" href="/_nuxt/entry.DFgiMwVT.css">
<link rel="modulepreload" as="script" crossorigin href="/_nuxt/CYhS_UQ5.js">
<link rel="preload" as="font" crossorigin href="/_fonts/vEFO2_JTCgwQ5ejvMV0Ox_Kg1UwJ0tKfX6bOjM7-f7e0Mls-xQWzOkeLSd.woff2">
<link rel="prefetch" as="script" crossorigin href="/_nuxt/rEEB8dd5.js">
<link rel="prefetch" as="script" crossorigin href="/_nuxt/7Il5epJC.js">
...

If you want to continue to discuss, please open a new issue. 🙏 This issue is to track automatic support for preload links, which is a future enhancement.

codeflorist commented 3 weeks ago

@danielroe

It seems the preload-tag is not generated for fonts, that are defined in tailwind.config.ts.

I define my font in tailwind-config like this:

    theme: {
        fontFamily: {
            body: ['"Felipa"', ...defaultTheme.fontFamily.sans],
        },
    },

And then set this css inside assets/css/tailwind.css:

  html {
    @apply font-body;
  }

Basically, nuxt/fonts is correctly picking up and downloading this font with everything seemingly working correctly, but it does not create the preload-tag.

Here is a stackblitz: https://stackblitz.com/edit/nuxt-starter-xrzkqs?file=app.vue

If you add this to app.vue, the preload-tag gets added correctly:

<style scoped>
div {
  font-family: Felipa, serif;
}
</style>