Next.js 引入字体包踩坑记录

2,067 阅读1分钟

1. 背景

最近项目中引用的可以商用字体包D-DIN,引入过程中遇到字体样式不生效,最终排查在webpack打包文件时出现错误,下文问踩坑过程以及解决方法

文中使用的file-loader 为6.x, file-loader esModule选项已在4.3.0版本的文件加载器中引入,而在5.x以上版本中,默认情况下已将其设置为true

2.导入字体包

在next.js 中的app.less 文件下引入字体,定义全部字体变量

  @font-face {
    font-family: 'D-DIN';
    src: url('../assets/fonts/D-DIN.otf');
  };

  @font-face {
    font-family: 'D-DIN-Bold';
    src: url('../assets/fonts/D-DIN-Bold.otf') format("opentype");
  };

但是在页面上,字体的样式并没有发生变化,最终在打包后的样式文件styles.chunk.css中发现url居然是[object Module]

3.解决问题

在网上查找资料发现,webpack的loader 处理url时会通过以下方式导入:

src: require('../image.png')  // require()是CommonJS模块语法

这就导致了我们在上面看到的[object Module]问题,要解决这个问题,可以在处理字体文件的file-loader中添加esModule: false属性

config.module.rules.push({
    test: /.otf$/,
    use: [
            {
                loader: 'file-loader',
                options: {
                        esModule: false, // 这里设置为false
                },
            },
    ],
})

配置完我们重新运行项目,重新查看style.chunk.css可以发现,文件已经可以正确的被解析(.oft前的一大串经过webpack通过hash进行编译后的结果)

看到了胜利的曙光有木有,回到页面上看字体还是没有变化,还有什么地方不对!(眼神逐渐迷失),后来想到在网络请求过程中会有一个单独请求字体的Font流,点看nextwork的Font中看到居然是404

通过Request URL发现还是webpack在打包过程中的问题,我们打包后的字体包并不在static/css文件夹下

继续优化,在file-loader的option中添加

  • name:对编译后的字体名截取前8位(微弱的性能优化,减小http头部长度)
  • publicPath: 访问路径
  • outputPath: 打包路径,将字体文件打包到fonts文件夹

PS: 由于next.js框架 有服务端渲染,所以需要判断isServer将fonts文件夹存放在正确的位置

config.module.rules.push({
    test: /.otf$/,
    use: [
            {
                loader: 'file-loader',
                options: {
                        esModule: false, // 这里设置为false
                        name: '[hash:8].[ext]',
                        publicPath: '/_next/static/fonts',
                        outputPath: `${isServer ? '../' : ''}static/fonts/`,
                },
            },
    ],
})

补充: 也可以使用url-loader 将url转换成base64同样也可以解决[object Module]问题

{
  loader: 'url-loader',
  options: {
    fallback: 'file-loader',
    name: '[hash:8].[ext]',
    publicPath: '/_next/static/fonts',
    outputPath: `${isServer ? '../' : ''}static/fonts/`,
  },
},

webpack 5 可以使用generator更方便

{
    test: /\.ttf|eot|otf|woff2?$/i,
    type: "asset/resource",
    generator: {
      filename: "fonts/[name].[hash:8][ext]"
    }
 }

加入以上的代码,再次重启我们的项目,发现netwotk中请求字体包已经可以正常的访问

回到页面上看字体已经生效了

4. 总结

本次踩坑主要还是在webpack的配置上,webpack的配置还是必须要掌握

相关链接

vue-loader

github.com/webpack-con…

github.com/webpack-con…

stackoverflow.com/questions/5…