Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Self-hosted fonts using NextJS

Tags:

I'm trying to self-host webfonts using my NextJS app and having trouble. This is the URL browser tries to access these fonts:

localhost:3000/_next/static/css/fonts/Avenir.woff2

The actual path is:

_project_dir/static/fonts/Avenir.woff2

I tried including the link in the the _app.js, it does download the fonts, but the text remains unstyled.

<link rel="preload" as="font" href="/static/fonts/Avenir.woff2" type="font/woff2" crossorigin />

Here's my _app.js:


  render() {
    const { Component, pageProps } = this.props;
    return (
      <Container>
        <link href="https://fonts.googleapis.com/css?family=Poppins:500,500i,600&display=swap" rel="stylesheet" />
        <link rel="preload" as="font" href="/static/fonts/Avenir.woff2" type="font/woff2" crossorigin />
        <link rel="preload" as="font" href="/static/fonts/AvenirHeavy.woff2" type="font/woff2" crossorigin />
        <Head>
          <title>Project</title>
        </Head>
        <Provider store={store}>
          <PersistGate loading={null} persistor={persistor}>
            <Component pageContext={this.pageContext} {...pageProps} />
          </PersistGate>
        </Provider>
      </Container>
    );
  }
}

My main.css

@font-face {
  font-family: 'Avenir';
  font-weight: 400;
  font-style: normal;
  font-display: swap;
  src: url('fonts/Avenir.eot');
  src: url('fonts/Avenir.eot?#iefix') format('embedded-opentype'), url('fonts/Avenir.woff2') format('woff2'),
    url('fonts/Avenir.woff') format('woff'), url('fonts/Avenir.ttf') format('truetype');
}

@font-face {
  font-family: 'Avenir';
  font-weight: 500;
  src: url('fonts/Avenir.eot');
  src: url('fonts/Avenir.eot?#iefix') format('embedded-opentype'), url('fonts/Avenir.woff2') format('woff2'),
    url('fonts/Avenir.woff') format('woff'), url('fonts/Avenir.ttf') format('truetype');
}

@font-face {
  font-family: 'Avenir';
  font-weight: 900;
  src: url('fonts/AvenirHeavy.eot');
  src: url('fonts/AvenirHeavy.eot?#iefix') format('embedded-opentype'), url('fonts/AvenirHeavy.woff2') format('woff2'),
    url('fonts/AvenirHeavy.woff') format('woff'), url('fonts/AvenirHeavy.ttf') format('truetype');
}

And my next.config.js:

  webpack(config, options) {
    config.module.rules.push({
      test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
      use: {
        loader: 'url-loader',
        options: {
          limit: 100000,
        },
      },
    });
    return config;
  },

like image 850
Alex Avatar asked Aug 21 '19 11:08

Alex


People also ask

How do I use Nextjs fonts?

To add a web font to your Next. js application, add the font to a Custom Document . Note that we don't recommend adding fonts with next/head , as this only applies the font to the particular page and won't work with a streaming architecture.


2 Answers

You don't need to any additional dependency to use fonts. Simply move your fonts to public/fonts instead of static/fonts.

Then to preload:

<link rel="preload" href="/fonts/Avenir.woff2" as="font" type="font/woff2" crossOrigin="anonymous" />

Remember to keep the beginning slash, otherwise it won't work. According to the official docs:

Files inside public can then be referenced by your code starting from the base URL (/).

Also, in JSX, it's crossOrigin not crossorigin, and it expects a string, not a Boolean.

And in CSS/SCSS (add beginning slash to each src-url):

@font-face {
  /* ... */
  src: url('/fonts/Avenir.woff2') format('woff2');
  /* ... */
}

Then remove the custom webpack configuration for font files. A downfall for this method is that the fonts will not be inlined as done by url-loader. But I believe it is quite inefficient to inline all fonts anyway. (You've set a limit of 100000. Almost every woff/woff2 font will be inlined.)

like image 94
brc-dd Avatar answered Sep 29 '22 08:09

brc-dd


In newer versions of next I believe you can import the WOFF2 file and use that in your CSS similar to this example for Gatsby. However, if you're not importing font files and instead placing them in the /static/fonts directory as you explain you can avoid using the WebPack loader or a plugin like next-fonts by hard-coding the font paths in your static directory as suggested by Alex:

import React, { Fragment } from "react";

const WebFonts = () => (
  <Fragment>
    <style global jsx>{`
      @font-face {
        font-family: "Source Sans Pro";
        font-style: normal;
        font-stretch: normal;
        font-weight: 400;
        font-display: fallback;
        src: local("SourceSansPro Regular"), local("SourceSansPro-Regular"),
          url(/static/fonts/SourceSansPro-Regular.woff2) format("woff2");
        unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
          U+A720-A7FF;
      }
      @font-face {
        font-family: "Source Sans Pro";
        font-style: normal;
        font-weight: 600;
        font-display: fallback;
        src: local("SourceSansPro SemiBold"), local("SourceSansPro-SemiBold"),
          url(/static/fonts/SourceSansPro-SemiBold.woff2) format("woff2");
        unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
          U+A720-A7FF;
      }
      @font-face {
        font-family: "Source Sans Pro";
        font-style: normal;
        font-weight: 700;
        font-display: fallback;
        src: local("SourceSansPro SemiBold"), local("SourceSansPro-SemiBold"),
          url(/static/fonts/SourceSansPro-Bold.woff2) format("woff2");
        unicode-range: U+0100-024f, U+1-1eff, U+20a0-20ab, U+20ad-20cf, U+2c60-2c7f,
          U+A720-A7FF;
      }
    `}</style>
  </Fragment>
);

export default WebFonts;

And then importing that Component into your _document override in NextJS. This will use fonts added to the NextJS static directory. Be sure to compress any TTF font downloads from Google Fonts using the woff2_compress method provided by woff2 before serving them for better page speed. And if you're not seeing your local font downloads appearing in the Network waterfall in DevTools make sure you test by removing any local versions of those fonts or local font face declarations.

like image 32
vhs Avatar answered Sep 29 '22 09:09

vhs