Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preload custom font with Next.js

Greetings Stack Overflow community! I'm using some custom fonts in my Next.js project using the following CSS:

@font-face {
  font-family: OpenSans;
  font-display: swap;
  src: url(./OpenSans-Regular.woff2) format('woff2');
}

The thing is that Lighthouse audit it's telling me to preload these .woff2 files but they are getting hashed by Next.js. I don't know how to add the link tag with rel="preload" for the fonts.

Where can I tell Next.js to preload these fonts?

Thanks you!

like image 719
Daniel Ramos Avatar asked Jul 21 '20 22:07

Daniel Ramos


3 Answers

I had the same issue, but this article gave the correct solution

Problem is, the font files get compiled if you place them in any other folder besides public. So if you place them in the public folder and reference them manually, you can be using the link preload like below.

Include them in the Head tag and specify the type for the different font types for browser compatibility. Make sure to reference them correctly in the css as well.

<Head>
<link
        rel="preload"
        href="/fonts/yourfont/yourfont.woff2"
        as="font"
        crossOrigin=""
        type="font/woff2"
      />
</Head>
@font-face {
   font-family: "YourFont";
   font-style: normal;
   font-weight: 900;
   src: url('/fonts/yourfont.woff2') format("woff2"),
   url('/fonts/yourfont.woff') format("woff"),
   url('/fonts/yourfont.ttf') format("truetype"),
   url('/fonts/yourfont.svg#yourfont') format("svg");
}
like image 145
Hendrik Vlaanderen Avatar answered Oct 10 '22 05:10

Hendrik Vlaanderen


For external fonts, you can simply add the preload link in your head component;

<link rel="preload" href="https://fonts.googleapis.com/css?family=Play&display=swap" as="font" />

As for the internal fonts that you have in your public folder, this requires;

  • file-loader configuration in next.config.js, this is to resolve the hashed filename
  • Type definition for the fonts
  • Then import it into your head

Which you can find my sample below;


I created a Layout.tsx which wraps my other components, which its main purpose is that there would not be duplicated meta tags - But this is unrelated to the question.

Here's the code I have in [email protected] - to preload both external and internal fonts.

App.tsx

function App({ Component, pageProps }: AppProps): JSX.Element {
  const queryClient = new QueryClient();

  return (
    <QueryClientProvider client={queryClient}>
      <Hydrate state={pageProps.dehydratedState}>
        <Provider store={store}>
          <main className="main-container position-relative" data-testid="main-container">
            <HeaderComp />
            <Layout>
              <Component {...pageProps} />
            </Layout>
            <FooterComp />
            <ScrollToTop />
          </main>
        </Provider>
      </Hydrate>
    </QueryClientProvider>
  );
}

Layout.tsx

import fontGilroyBold from "@assets/fonts/gilroy/Gilroy-Bold.woff";

const Layout: React.FunctionComponent = ({ children }) => {
  return (
    <div className="content font-play position-relative">
      <Head> {* next/head *}
        {/* ...metaTags */}
        <link rel="preload" href={fontGilroyBold} as="font" />
        <link rel="preload" href="https://fonts.googleapis.com/css?family=Play&display=swap" as="font" />
      </Head>
      {children}
    </div>
  );
};

next-env.d.ts

...
declare module "*.woff";
declare module "*.woff2";
...

next.config.js


const nextConfig = {
  webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
    /**
     * Override some of the existing loaders
     */
    // ...

    /**
     * Font imports in the code repository will be resolved as relative path
     */
    config.module.rules.push({
      test: /gilroy\/.+\.(woff|woff2)$/,
      use: {
        loader: "file-loader",
        options: {
          /** Stolen configuration from pre-existing "config.module.rules[2]" */
          outputPath: "static/fonts/gilroy/",
          publicPath: "/_next/static/fonts/gilroy/",
          limit: 1,
        },
      },
    });

    return config;
  },
};
like image 7
choz Avatar answered Oct 10 '22 05:10

choz


You can preload them in your _document.js inside the <Head> component by adding the following:

<link
  rel="preload"
  href="/fonts/inter-var-latin.woff2"
  as="font"
  type="font/woff2"
/>
like image 8
nullspace Avatar answered Oct 10 '22 07:10

nullspace