Using local web fonts with webpack

21,435

Solution 1

Got a working solution thanks to @omerts in this thread. Solution involved using publicPath. I had been trying to use it as an option in module.exports with the fonts file-loader, not the output.

Updated webpack.config.js:

const webpack = require('webpack');
const PROD = JSON.parse(process.env.PROD_ENV || '0');
const path = require('path');

const PATHS = {
  build: path.join(__dirname, './src/public')
};

module.exports = {

  entry: './src/app/App.jsx',

  output: {
    path: PATHS.build,
    filename: PROD ? 'bundle.min.js' : 'bundle.js',
    publicPath: PATHS.build
  },

  module: {
    loaders: [
      {
        test: /\.jsx?$/,
        loader: 'babel-loader',
        exclude: '/node_modules/',
        query: {
          presets: ['es2015', 'react', 'stage-1']
        }
      },
      {
        test: /\.s?css$/,
        loaders: ['style', 'css', 'sass']
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2)$/,
        loader: 'file-loader?name=/fonts/[name].[ext]'
      },
      {
        test: /\.(jpg|png)$/,
        loader: 'file-loader?name=/fonts/[name].[ext]'
      }
    ]
  },

  plugins: PROD ? [
    new webpack.optimize.UglifyJsPlugin({
      beautify: false,
      comments: false,
      compress: { 
        warnings: false,
        drop_console: true
      },
      mangle: {
        except: ['$'],
        screw_ie8: true,
        keep_fnames: false
      }
    })
  ] : []
};

Solution 2

I got it working thanks to this article: https://www.robinwieruch.de/webpack-font

Solution 3

Is it possible to just always reference the original fonts? They don't appear to get changed by file-loader anyways.

File structure

APP
├───build
│   │   build.js
│   │   build.min.js
│   │
│   └───fonts
│           allthefonts.woff
│
├───css
│       main.css
│
├───fonts
│       allthefonts.woff
│
└───js
        main.js

main.css

@font-face {
  font-family: All-The-Fonts;
  src: url('../fonts/allthefonts.woff') format('woff'); 
}

webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
  ...
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: "[name].js",
    globalObject: 'this'
  },
  module: {
    rules: [
      {
        test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
        use: [{
          loader: 'file-loader',
          options: {
            name: '[name].[ext]',
            outputPath: './fonts/' //dont actually use these fonts but still need to process them
          }
        }]
      }
    ]
  },
  ...
};

Solution 4

a better approach would be to use 'url-loader' and add the following line in loaders.

{
  test: /\.(jpe?g|png|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/, 
  loader: 'url-loader?limit=100000'
}
Share:
21,435
johnjohn
Author by

johnjohn

Updated on August 07, 2022

Comments

  • johnjohn
    johnjohn almost 2 years

    I'm trying to use some local web fonts in my React project. I'm including them in my main.scss file, and loading them via webpack. The bundle builds correctly, including main.scss styles. I see webpack load the font files, and copy them to public/fonts/, but my bundle file can't find the fonts.

    As I understand it, your @font-face src should be in relation to where bundle will be. I'm setting this to the same path that I load the fonts with in webpack, './fonts/'. The exact error I'm seeing is:

    file:///Users/myusername/Documents/folder1/folder2/folder3/APP/fonts/FoundersGroteskWeb-Regular.woff net::ERR_FILE_NOT_FOUND
    

    I've been trying a lot of different path configurations, and using the publicPath option in webpack, but I'm going in circles at this point over what seems like a really simple reference error.

    File Structure:

    APP
    ├──webpack.config.js
    ├──src
         ├──app
            ├──App.jsx
            ├──styles
               ├──main.scss
               ├──fonts
                  ├──allthefonts.woff
         ├──public
            ├──bundle.js
            ├──fonts
               ├──allthefonts.woff
    

    App.jsx:

    require('./styles/main.scss');
    

    main.scss:

     @font-face {
        font-family: FoundersGrotesk;
        src: url('./fonts/FoundersGroteskWeb-Bold.eot') format('eot'),
             url('./fonts/FoundersGroteskWeb-Bold.woff') format('woff'),
             url('./fonts/FoundersGroteskWeb-Bold.woff2') format('woff2');
        font-weight: bold;
    }
    
    @font-face {
        font-family: FoundersGrotesk_Cnd;
        src: url('./fonts/FoundersGrotXCondWeb-Bold.eot') format('eot'),
             url('./fonts/FoundersGrotXCondWeb-Bold.woff') format('woff'),
             url('./fonts/FoundersGrotXCondWeb-Bold.woff2') format('woff2');
        font-weight: bold;
    }
    
    @font-face {
        font-family: FoundersGrotesk;
        src: url('./fonts/FoundersGroteskWeb-Regular.eot') format('eot'),
             url('./fonts/FoundersGroteskWeb-Regular.woff') format('woff'),
             url('./fonts/FoundersGroteskWeb-Regular.woff2') format('woff2');
        font-weight: normal;
    }
    

    webpack.config.js:

     'use strict';
    
    const webpack = require('webpack');
    const PROD = JSON.parse(process.env.PROD_ENV || '0');
    
    module.exports = {
    
      entry: './src/app/App.jsx',
    
      output: {
        path: './src/public/',
        filename: PROD ? 'bundle.min.js' : 'bundle.js'
      },
    
      module: {
        loaders: [
          {
            test: /\.jsx?$/,
            loader: 'babel-loader',
            exclude: '/node_modules/',
            query: {
              presets: ['es2015', 'react', 'stage-1']
            }
          },
          {
            test: /\.s?css$/,
            loaders: ['style', 'css', 'sass']
          },
          {
            test: /\.(eot|svg|ttf|woff|woff2)$/,
            loader: 'file-loader?name=./fonts/[name].[ext]'
          }
        ]
      }
    };