如何通过 Webpack 管道在 React 应用程序中正确加载 .otf/.ttf 字体?

How to correctly load .otf/.tff fonts in a React app via a Webpack pipeline?

我在实现这件事时遇到了麻烦,我一直遵循的各种指南可能已经过时或者我搞砸了。我知道这是一个常见的问题,我玩过很棒的字体,通过 scss 等加载它......但它没有用,而且我发现它过于复杂,下面的方法也应该起作用并且更直接。

webpack 错误(在底部)是由 css-loader 引发的,它不是 file-loaderurl-loader(我都试过了),所以我怀疑问题出在css-loader 正在尝试 import/find 通过 .otf 字体文件但不能。

如果有人知道,那真的很有帮助。我需要打包字体文件,以便我的应用程序可以 运行 离线。

这是我的文件结构:

./webkacp.config.js
./src/
   ./fonts/AvenirLTStd-Roman.otf
   ./index.css
   ./index.jsx

这是我的 webpack.config.js:

var HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                loader: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'fonts/'
                        }
                    }
                ],
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'images/'
                        }
                    }
                ],
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx'],
        alias: {
            '@': path.resolve(__dirname, 'src/'),
        }
    },
    plugins: [new HtmlWebpackPlugin({
        template: './src/index.html'
    })],
    devServer: {
        historyApiFallback: true
    },
    externals: {
        // global app config object
        config: JSON.stringify({
            apiUrl: 'http://127.0.0.1:4000'
        })
    }
}

这是我的 index.css:

@font-face {
font-family: "MyFont";
src: url("./fonts/AvenirLTStd-Roman.otf") format("otf");
/* Add other formats as you see fit */
}

html, body {
    font-family: 'MyFont', sans-serif;
}

这是我的 index.jsx:

import React from 'react';
import { render } from 'react-dom';

import { App } from './App';

import 'bootstrap/dist/css/bootstrap.min.css';
import '@/index.css';

render(
    <App />,
    document.getElementById('app')
);

最后,这是 webpack 错误:

ERROR in ./src/index.css (./node_modules/css-loader/dist/cjs.js!./src/index.css)
Module not found: Error: Can't resolve './fonts/AvenirLTStd-Roman.otf' in '/var/sphyrna/csdpac-services/images/csdpac-unified/frontend/src'
 @ ./src/index.css (./node_modules/css-loader/dist/cjs.js!./src/index.css) 4:36-76
 @ ./src/index.css
 @ ./src/index.jsx

知道了。

需要进行两项更改:

  1. 跳过 css-loader 中的 url,这样它就不会尝试 import/resolve 文件。
  2. 删除我的 css 中的 san-serif。

现在有效。希望这可以帮助别人。 None 的在线指南提到跳过 url。

这是我的更新 css:

@font-face {
font-family: "MyFont";
src: url("./fonts/AvenirLTStd-Roman.otf") format("otf");
/* Add other formats as you see fit */
}

html, body {
    font-family: 'MyFont';
}

Webpack.config.js:

var HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    mode: 'development',
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                loader: 'babel-loader'
            },
            {
                test: /\.css$/,
                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {url:false}
                    }
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'fonts/'
                        }
                    }
                ],
            },
            {
                test: /\.(png|svg|jpg|gif)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: '[name].[ext]',
                            outputPath: 'images/'
                        }
                    }
                ],
            }
        ]
    },
    resolve: {
        extensions: ['.js', '.jsx'],
        alias: {
            '@': path.resolve(__dirname, 'src/'),
        }
    },
    plugins: [new HtmlWebpackPlugin({
        template: './src/index.html'
    })],
    devServer: {
        historyApiFallback: true
    },
    externals: {
        // global app config object
        config: JSON.stringify({
            apiUrl: 'http://127.0.0.1:4000'
        })
    }
}