使用NextJS进行自托管字体

10

我正在尝试使用我的NextJS应用程序进行自托管Web字体,并且遇到了麻烦。 这是浏览器尝试访问这些字体的URL:

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

实际路径是:
_project_dir/static/fonts/Avenir.woff2

我尝试将链接包含在_app.js中,它确实下载了字体,但文本仍未被样式化。

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

这是我的_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>
    );
  }
}

我的 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');
}

我的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;
  },

4个回答

8
你不需要任何额外的依赖就可以使用字体。只需将字体文件移动到 public/fonts 文件夹中,而不是 static/fonts
然后进行预加载:
<link rel="preload" href="/fonts/Avenir.woff2" as="font" type="font/woff2" crossOrigin="anonymous" />

请记得保留起始斜杠“/”,否则它将无法正常工作。根据官方文档

public文件夹中的文件可以从基础URL(/)开始被您的代码引用。

此外,在JSX中,使用crossOrigin而非crossorigin,且它需要一个string而非boolean

在CSS中(添加每个src-url的起始斜杠):

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

然后删除字体文件的自定义webpack配置。这种方法的缺点是,字体文件不会像url-loader那样被内联。但我认为将所有字体文件内联非常低效。(您已经设置了100000的限制。几乎每个woff/woff2字体都将被内联。)


经过四个小时的努力,我设法让我的本地字体在Github Pages上的Nextjs静态导出站点中工作,我找到了这个答案,解决了所有问题。谢谢。 - ian-campbell

2
在较新版本的Next.js中,我认为您可以importWOFF2文件并在CSS中使用它,类似于Gatsby的此示例。但是,如果您不导入字体文件,而是将它们放置在/static/fonts目录中,就像您所解释的那样,您可以通过在静态目录中硬编码字体路径(由Alex建议)来避免使用WebPack加载程序或像next-fonts这样的插件。
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;

然后将该组件导入到NextJS中的_document覆盖中。这将使用添加到NextJS静态目录中的字体。确保使用woff2提供的woff2_compress方法对来自Google Fonts的任何TTF字体下载进行压缩,以获得更快的页面速度。如果您在DevTools中的网络瀑布中没有看到您的本地字体下载,请确保通过删除任何本地版本的这些字体或local字体面声明来进行测试。


不,除非他们已经手动配置了webpack以使用文件加载器/资源模块来处理字体文件,否则无法在v10.2.3中导入WOFF/WOFF2文件。 - brc-dd

0
在我的情况下,我按照brc-dd的描述设置了我的代码,但它仍然无法正常工作:字体已在网络标签页中下载,但文本仍未设置样式。
最后,将我的字体从.ttf转换为.woff2解决了我的问题。
在Next 11中,我的工作代码如下所示:
// document.js
<Head>
  <link
    rel="preload"
    href="/fonts/Lato/Lato-Light.woff2" // fix: convert .ttf to .woff2
    as="font"
    type="font/woff2"
    crossOrigin="anonymous"
  />
</Head>

// globals.css
@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 300;
  font-display: optional;
  src: url("/fonts/Lato/Lato-Light.woff2") format("woff2");
}

我的字体存储在 项目根目录/public/fonts/[字体名称]/[字体文件].woff2


-1

url('/static/fonts/Avenir.eot')

必须像这样包含路径。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接