Webpack не может загружать шрифты (ttf)

В настоящее время у меня есть 3 шрифта, которые я хочу добавить в свой проект React: a, light, bold.
Моя файловая структура:

/src
├── /fonts/
│   ├── /A.ttf
│   ├── /A-light.ttf
│   └── /A-bold.ttf
│  
├── /styles/
│   ├── /base/
│   │   └── /__base.scss
│   └── styles.scss
│ 
├── app.jsx
└── webpack.config.js

_base.scss:

@font-face {
  font-family: "A";
  font-style: normal;
  font-weight: 400;
  src: url("../../fonts/A.ttf") format("truetype");
}

@font-face {
  font-family: "A";
  font-style: normal;
  font-weight: 800;
  src: url("../../fonts/A-bold.ttf") format("truetype");
}
@font-face {
  font-family: "A";
  font-style: normal;
  font-weight: 300;
  src: url("../../fonts/A-light.ttf") format("truetype");
}
body {
  font-family: A, Helvetica, Arial, sans-serif;
}

_base.scss импортируется styles.scss, а styles.scss импортируется в app.jsx.

Мой конфиг веб-пакета выглядит так:
webpack.config.js

const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const StyleLintPlugin = require('stylelint-webpack-plugin');

process.env.NODE_ENV = process.env.NODE_ENV || 'development';
console.log(process.env.NODE_ENV);
if (process.env.NODE_ENV === 'development') {
  require('dotenv').config({path: '.env.development'});
}

module.exports = env => {
  const isProduction = env === 'production';
  const CSSExtract = new ExtractTextPlugin('styles.css');

  return {
    entry: ['babel-polyfill', './src/app.jsx'],
    output: {
      path: path.join(__dirname, 'public', 'dist'),
      filename: 'bundle.js'
    },
    resolve: {
      extensions: ['.js', '.jsx', '.json', '.css', '.scss']
    },
    module: {
      rules: [
        {
          exclude: /(node_modules|bower_components)/,
          test: /\.jsx?$/,
          use: ['babel-loader', 'eslint-loader']
        },
        {
          test: /\.s?css$/,
          use: CSSExtract.extract({
            use: [
              {
                loader: 'css-loader',
                options: {
                  sourceMap: true
                }
              },
              {
                loader: 'sass-loader',
                options: {
                  sourceMap: true
                }
              }
            ]
          })
        },
        {
          test: /\.(png|jpg|svg)$/,
          use: {
            loader: 'url-loader'
          }
        },
        {
          test: /\.(ttf|eot|woff|woff2)$/,
          loader: 'file-loader',
          options: {
            name: 'fonts/[name].[ext]'
          }
        }
      ]
    },
    plugins: [
      CSSExtract,
      new webpack.DefinePlugin({
        'process.env.API_AUTH_TOKEN': JSON.stringify(process.env.API_AUTH_TOKEN),
        'process.env.API_EMAIL': JSON.stringify(process.env.API_EMAIL),
        'process.env.API_PASSWORD': JSON.stringify(process.env.API_PASSWORD)
      }),
      new StyleLintPlugin({})
    ],
    devtool: isProduction ? 'source-map' : 'inline-source-map',
    devServer: {
      overlay: {
        warnings: true,
        errors: true
      },
      contentBase: path.join(__dirname, 'public'),
      historyApiFallback: true,
      publicPath: '/dist/'
    }
  };
};

Однако Webpack не компилируется.

Ошибка:

./src/styles/styles.scss
Module build failed: ModuleNotFoundError: Module not found: Error: Can't resolve '../../fonts/A.ttf'

Любая помощь будет оценена!

5 ответов

Начиная с webpack 5, вместо этого вы можете использовать встроенные модули ресурсов. Из официального руководства по Webpack здесь добавьте это в module.rules для загрузки файлов .ttf:

      {
  test: /\.(woff|woff2|eot|ttf|otf)$/i,
  type: 'asset/resource',
},

Использование 'ttf-loader' из npm отлично сработало для меня.

https://www.npmjs.com/package/ttf-loader

module: {
  rules: [
    {
      test: /\.ttf$/,
      use: [
        {
          loader: 'ttf-loader',
          options: {
            name: './font/[hash].[ext]',
          },
        },
      ]
    }
  ]
}

Re Webpack 5: В случае, если это будет полезно для кого-то еще, вот решение, которое, кажется, является распространенной проблемой, возникающей при загрузке шрифтов TrueType с помощью Webpack 5. На самом деле это проблема CSS.

В разделе документации Webpack 5 Asset Management под заголовком «Загрузка шрифтов» файл style.css содержит следующий пример объявления @font-face:

      @font-face {
   font-family: 'MyFont';
    src: url('./my-font.woff2') format('woff2'),
    url('./my-font.woff') format('woff');
}

Чтобы это объявление работало с другими типами шрифтов, такими как шрифты truetype или opentype, необходимо правильно указать. Допустимы любые из следующих типов:

«woff», «woff2», «truetype», «opentype», «embedded-opentype», «svg».

Если вы установите, например, тип «ttf» или «otf», шрифт не будет импортирован. В format type указывает браузеру формат шрифта, но не является обязательным, поэтому, если вы не укажете его, ваш шрифт все равно должен загружаться правильно.

Предполагая, что вы правильно настроили путь к своему шрифту, этот пример должен работать должным образом:

      @font-face {
   font-family: 'MyFont';
   src: url('./my-font.ttf') format('truetype');
}

Это также должно работать:

      @font-face {
   font-family: 'MyFont';
   src: url('./my-font.ttf');
}

Webpack требует загрузчик шрифтов для загрузки файлов шрифтов, присутствующих в вашем проекте. Вы используете загрузчик файлов для загрузки шрифтов. + Изменить

{
      test: /\.(ttf|eot|woff|woff2)$/,
      loader: 'file-loader',
      options: {
      name: 'fonts/[name].[ext]'
 }

в

 {
      test: /\.ttf$/,
      use: [
        {
          loader: 'ttf-loader',
          options: {
            name: './font/[hash].[ext]',
          },
        },
      ]
  }

установив в свой проект загрузчик шрифтов, такой как TTF Loader от NPM.

Префикс пути к шрифту с ~, чтобы сообщить Webpack, что это не относительный импорт https://github.com/webpack-contrib/sass-loader

Другие вопросы по тегам