使用 Next.js 预加载自定义字体

Dan*_*mos 10 reactjs server-side-rendering next.js

问候 Stack Overflow 社区!我使用以下 CSS 在我的 Next.js 项目中使用了一些自定义字体:

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

问题是 Lighthouse 审计它告诉我预加载这些.woff2文件,但它们正在被 Next.js 散列。我不知道如何为字体添加link标签rel="preload"

我在哪里可以告诉 Next.js 预加载这些字体?

谢谢!

Hen*_*ren 18

在较新版本的 Next.js 中,这个答案不再相关。但如果您仍在使用旧的 Next.js 版本(应用程序路由器之前),这可能很有用。

问题出在 Next.js 中,如果将字体文件放在 public 之外的任何其他文件夹中,字体文件就会被编译。因此,如果您将它们放在公共文件夹中并手动引用它们,则可以使用如下所示的链接预加载。

将它们包含在 Head 标记中,并指定不同字体类型的类型以实现浏览器兼容性。确保在 CSS 中正确引用它们。

<Head>
<link
        rel="preload"
        href="/fonts/yourfont/yourfont.woff2"
        as="font"
        crossOrigin=""
        type="font/woff2"
      />
</Head>
Run Code Online (Sandbox Code Playgroud)
@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");
}
Run Code Online (Sandbox Code Playgroud)


vad*_*lim 8

对于外部字体,您只需在 head 组件中添加预加载链接即可;

<link rel="preload" href="https://fonts.googleapis.com/css?family=Play&display=swap" as="font" />
Run Code Online (Sandbox Code Playgroud)

至于文件夹中的内部字体public,这需要;

  • file-loader配置中next.config.js,这是为了解析散列文件名
  • 字体的类型定义
  • 然后将其导入你的大脑中

您可以在下面找到我的示例;


我创建了一个Layout.tsx包装我的其他组件的组件,其主要目的是不会有重复的元标记- 但这与问题无关。

这是我的代码Next@10.0.5- 预加载外部和内部字体。

应用程序.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>
  );
}
Run Code Online (Sandbox Code Playgroud)

布局.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>
  );
};
Run Code Online (Sandbox Code Playgroud)

下一个环境.d.ts

...
declare module "*.woff";
declare module "*.woff2";
...
Run Code Online (Sandbox Code Playgroud)

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;
  },
};
Run Code Online (Sandbox Code Playgroud)


nul*_*ook 6

您可以通过添加以下内容_document.js<Head>组件内部预加载它们:

<link
  rel="preload"
  href="/fonts/inter-var-latin.woff2"
  as="font"
  type="font/woff2"
/>
Run Code Online (Sandbox Code Playgroud)

  • 问题是,编译应用程序时输出文件名会被散列:/ (7认同)