Webpack 4: css-loader + file-loader to add fonts and their stylesheets in the build process
Asked Answered
D

2

13

Given this setup:

fonts/styles.css

@font-face {
  family: 'MyFont';
  src: url('fonts/myfont.otf');
}

How can I:

  1. in my JS bundle, obtain a reference to the URL of the CSS file, as a string, e.g. [name].[hash].css
  2. the generated CSS file should be a plain CSS file, but with url()s pointing to the generated webfont files?

Something like:

@font-face {
  family: 'MyFont';
  src: url('myfont.dds9394u329d9sa9r8439.otf');
}

I'm trying with:

webpack.config.js

{
  test: /\.(woff|woff2|eot|ttf|otf|svg)$/,
  loader: 'file-loader',
  include: [/fonts/]
},

{
  test: /\.css$/,
  use: ['file-loader', 'css-loader'],
  include: [/fonts/]
}

JS file

const myfont = {
  family: 'MyFont',
  stylesheet: require('fonts/styles.css')
}

As per a previous question, using file-loader and require() works well to get the URL for the CSS, but the generated file is not plain CSS.

How can I combine file-loader and css-loader (+ possibly other loaders) to obtain this CSS file?

Thanks!

P.S. I would like to avoid copy-webpack-plugin for this, because I want the CSS / font files to be hashed and addressable in code.

Domineering answered 21/8, 2018 at 8:42 Comment(0)
D
13

For posterity: this is the Webpack configuration with which I was able to obtain the result I was looking for.

module: {
  rules: {
    // Font stylesheets
    {
      test: /\.css$/,
      use: [
        {
          loader: 'file-loader',
          options: {
            name: 'css/[hash].[ext]'
          }
        },
        'extract-loader',
        'css-loader',
        'postcss-loader'
      ],
      include: [/fonts/]
    },

    // Font files
    {
      test: /\.(woff|woff2|ttf|otf)$/,
      loader: 'file-loader',
      include: [/fonts/],

      options: {
        name: '[hash].[ext]',
        outputPath: 'css/',
        publicPath: url => '../css/' + url
      }
    },
  }
}
Domineering answered 24/8, 2018 at 19:19 Comment(1)
Thanks for keeping this into posterity, It helped me :)Departmentalism
N
1

I know it's been a while since this question was asked but same as Dan I leave this for posterity.

So this is the setup that works in my case:

const path = require("path");

module.exports = (env, argv) => ({
  ...
  module: {
       rules: [
       {
         test: /\.css$/,
         use: ["style-loader", {loader: "css-loader", options: {modules: true}}],
         exclude: /node_modules/,
      },        
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        use: [
          {
            loader: 'file-loader', 
            options: {
              outputPath: (url, resourcePath, context) => {
                if(argv.mode === 'development') {
                  const relativePath = path.relative(context, resourcePath);
                  return `/${relativePath}`;
                }
                return `/assets/fonts/${path.basename(resourcePath)}`;
              }
            }
          }
        ]
      }]
    }
});

Complete working setup can be found here: https://github.com/przemek-nowicki/multi-page-app-with-react/blob/master/webpack.config.js

Nettie answered 22/5, 2019 at 10:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.