Frank
Frank

Reputation: 451

How to preload a CSS @font-face font that is bundled by webpack4+babel?

I have a webpack4+babel bundler setup for a react web app. In a LESS file, I reference a local font. This font gets copied over to the dist folder on build and its filename is hashed. I want to be able to preload this font.

Here is my LESS file:

@font-face {
    font-family: 'Test';
    src: url('../fonts/test.ttf') format('truetype');
    font-weight: 400;
}

I have tried the following approaches but so far with no success:

  1. Add custom import to my app's main JS file.
import(/* webpackPreload: true */ "../fonts/test.ttf");

Here is my .babelrc file:

{
    "presets": [
        "@babel/preset-env",
        "@babel/preset-react"
    ],
    "plugins": [
        "@babel/plugin-syntax-dynamic-import"
    ]
}

Running webpack does not produce preload directions anywhere as far as I can see in the outputted html - I have searched through the dist folder contents and found nothing.

  1. preload-webpack-plugin

I add this to my webpack.config.js file:

plugins: [
  new HtmlWebpackPlugin(),
  new PreloadWebpackPlugin({
    rel: 'preload',
    as(entry) {
      if (/\.css$/.test(entry)) return 'style';
      if (/\.woff$/.test(entry)) return 'font';
      if (/\.png$/.test(entry)) return 'image';
      return 'script';
    }
  })
]

This creates preloads for the JS script file bundles but not for the CSS and fonts.

Any ideas on how to get this to work?

Upvotes: 27

Views: 22886

Answers (5)

Gregory
Gregory

Reputation: 111

I think was able to fix this by moving the font file to my public folder, and then moving my @font-face definition to <style> tags within my index.html file, where I could use %PUBLIC_URL% to specify the location to Webpack:

<head>
  
  <!-- Some stuff... -->

  <link rel="preload" href="%PUBLIC_URL%/my-font-file.ttf" as="font" />

  <style>
    @font-face {
      font-family: my-font-name;
      src: url('%PUBLIC_URL%/my-font-file.ttf');
    }
  </style>
</head>

(with my-font-file.ttf in the public folder of my project)

Upvotes: 0

GProst
GProst

Reputation: 10237

I believe to preload the font file you can just manually specify the <link /> in your index.html file:

<link rel="preload" href="../fonts/test.ttf" as="font" type="font/ttf">

See this for some details.

Upvotes: -5

Pavel
Pavel

Reputation: 81

was able to make it work on webpack4 by installing version 3beta and using while list option:

yarn add -D [email protected]

new PreloadWebpackPlugin({
        rel: 'preload',
        as: 'font',
        include: 'allAssets',
        fileWhitelist: [/\.(woff2?|eot|ttf|otf)(\?.*)?$/i],

    }),

Upvotes: 8

Alireza
Alireza

Reputation: 2449

I found a workaround for this. It isn't pleasant but I think is't better than nothing. here I only wanted to preload woff and woff2 files.

new PreloadWebpackPlugin({
      rel: 'preload',
      include: 'allAssets',
      fileBlacklist: [/\.(js|ttf|png|eot|jpe?g|css|svg)/]
    }),

Upvotes: 1

Solders
Solders

Reputation: 401

Posting this since I think it might help someone in a similar position - I realize it doesn't solve the described issue.

Had the same problem - didn't need to hash my font-files but had another part of the url that was not static. A bit hackish, but solved my problem. Maybe it can help someone. In theory you can create your own hash-id and set that as the htmlWebpack-plugin variable.

In my index.html

<html>
  <head>
    <link rel="preload" href="<%= htmlWebpackPlugin.options.woffSrc %>" as="font" type="font/woff" crossorigin>
    <link rel="preload" href="<%= htmlWebpackPlugin.options.woff2Src %>" as="font" type="font/woff2" crossorigin>

    //rest of html

webpack.prod.conf.js - updated HtmlWebpackPlugin

plugins: [
  new HtmlWebpackPlugin({
    ...config,
    woffSrc: `https://url.to.my.page.com/${ASSETS_FOLDER}/static/assets/fonts/GilroyRegular.woff`,
    woff2Src: `https://url.to.my.page.com/${ASSETS_FOLDER}/static/assets/fonts/GilroyExtraBold.woff2`
  })
]

I reasoned that the font-files didn't need to have the hash - since that is mainly used to control cache and I won't change the font files, so I turned that of in my webpack file-loader. Please correct me if I'm wrong here.

Having the loader:

{
  test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
  loader: 'url-loader',
  options: {
    limit: 2000,
    name: utils.assetsPath('assets/fonts/[name].[ext]')
  }
}

Was unable to get the preload-webpack-plugin to work due to build errors and got tired troubleshooting after 2 days.

Upvotes: 1

Related Questions