27

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?

Frank
  • 451
  • 1
  • 5
  • 11

5 Answers5

8

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

yarn add -D preload-webpack-plugin@3.0.0-beta.3

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

    }),
Pavel
  • 81
  • 1
  • 2
1

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.

Solders
  • 391
  • 1
  • 4
  • 11
1

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)/]
    }),
Alireza
  • 2,319
  • 2
  • 23
  • 35
0

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)

Gregory
  • 73
  • 1
  • 6
-5

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.

E_net4
  • 27,810
  • 13
  • 101
  • 139
GProst
  • 9,229
  • 3
  • 25
  • 47
  • 2
    Thanks for the response but my problem is that the font filenames are hashed by webpack and so I don't know what they will be after they are copied across to the `dist` folder. Perhaps there is a way of using a placeholder in the HTML file? – Frank Mar 29 '19 at 14:17
  • 2
    Are your font files going to change often? Why do you need to include them to your webpack compilation process? I think you can create another `assets` folder to server static files which don't need to be compiled by webpack in parallel with a `dist` folder and serve static files from this folder as well – GProst Mar 29 '19 at 15:06
  • That's a fair point. The fonts won't change and even if they do, copying them across after the webpack build isn't too much effort. I presume that linking to the font files in the HTML (for preload) and also linking using @font-face in CSS (where they'll actually be used) is fine - i.e. once they are preloaded by the browser, then it won't bother doing so again? – Frank Mar 29 '19 at 15:24
  • 1
    I don't think there is any other way of preloading fonts other than using `link`. So even if you used some Webpack preload solution it would just insert the `link` with preload attribute that would load your asset. So yes I believe a browser shouldn't make another request if it already preloaded the asset however I think you'd want to put some `cache-control` headers so that browser cached the asset. – GProst Mar 29 '19 at 15:42
  • Cheers. Your recommended approach is now in and working well. – Frank Apr 01 '19 at 06:10
  • Glad to hear that! – GProst Apr 01 '19 at 13:21
  • not what the user was looking for but that helped me out +1 – Brandon Minton Feb 22 '20 at 08:58
  • This can be the best solution when you want only specific fonts to be preloaded. – cbrwizard Oct 12 '20 at 12:56