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的配置还是必须要掌握