webpack项目如何正确打包引入的自定义字体?

一. 如何在Vue或React项目中使用自定义字体

在开发前端项目时,经常会遇到UI同事希望在项目中使用一个炫酷字体的需求。那么怎么在项目中使用自定义字体呢?

其实实现起来并不复杂,可以借用CSS3 @font-face 来实现。

本文着重介绍一下 webpack 项目如何正确打包引入的自定义字体。

@font-face有什么用

总结一下就是:用户借助该规则,可以为引入的字体包命一个名字,并指定在哪里可以找到它(指定字体包的存储路径)后,就可以像使用通用字体那样去使用它了。

具体实现步骤

例如现在的需求是:需要在项目中使用 KlavikaMedium-Italic 字体。

则只需以下三个步骤即可。

1. 将字体包放入项目目录下

这里放到根目录下的 tool/fonts 文件夹里。

2. 在index.css文件中定义

@font-face {

 font-family: 'myFont';

 src: url(tool/fonts/KlavikaMedium-Italic.otf);

}

3. 使用自定义字体

新建一个index.vue文件,引入样式:

import './index.css'

<template>

<h1>使用自定义字体</h1>

<style>

 h1 {

 font-family: 'myFont'

 }

</style>

</template>

效果如下:

image

二. webpack项目如何正确打包自定义的字体

1. 打包时报错

既然在本地开发环境实现了效果,于是就使用 webpack 打包准备上线,却发现 webpack 在打包过程中报错:

image

2. 打包时为什么会报错

我们在定义自定义字体时使用URL指定了字体包的路径,由于 webpack 默认是无法处理 css 中的 url 地址的,因此这里会报错。

3. 解决报错

3.1 认识file-loader

这时就需要借助 loader 来大显身手了,解决这个问题需要使用 file-loader,它主要干了两件事儿:

  • 根据配置修改打包后图片、字体包的存放路径;
  • 再根据配置修改我们引用的路径,使之对应引入。

3.2 安装file-loader

yarn add file-loader

3.3 配置file-loader

在 webpack.config.js 中,配置file-loader:

module.exports = {

 module: {

 rules: [

 {

 // 命中字体包

 test: /.(woff2?|eot|ttf|otf)(?.*)?$/,

 // 只命中指定 目录下的文件,加快Webpack 搜索速度

 include: [paths.toolSrc],

 // 排除 node_modules 目录下的文件

 exclude: /(node_modules)/,

 loader: 'file-loader',

 },

 ]

 }

}

再次执行打包命令,不再报错。

4. 自定义字体为什么不生效

于是将打包出来的 dist 目录重新部署到服务器上后访问页面,却发现由于找不到字体导致没有生效:

image

从图中可以看出,http请求字体包的路径为:根目录下(打包出来的静态文件index.html所在目录)的 css/620db1b997cd78cd373003282ee4453f.otf

4.1 字体不生效的原因

看了一下打包命令生成的 dist 目录结构:

├── 620db1b997cd78cd373003282ee4453f.otf

├── css

│   ├── backend.66a35.css

│   └── backend.66a35.css.map

├── favicon.ico

├── images

│   ├── bg.5825f.svg

│   ├── data-baseTexture.c2963.jpg

│   ├── data-heightTexture.6f50d.jpg

│   └── logo.7227a.png

├── index.html

└── js

 ├── backend.66a35.js

却发现,字体包和 index.html 是在同一级。因此字体无法生效的原因就很明朗了:

  • 由于http请求的字体包路径与实际的存放路径一致,就导致了404;
  • 找不到字体包的实际路径,因此使用的字体无法生效。

4.2 字体不生效的解决办法

可以通过修改字体包打包后的实际存储路径去解决这个问题,在 webpack.config.js 中,借助 options 参数可以继续给 file-loader 设置更多的配置项:

module.exports = {

 module: {

 rules: [

 {

 // 命中字体包

 test: /.(woff2?|eot|ttf|otf)(?.*)?$/,

 // 只命中指定 目录下的文件,加快Webpack 搜索速度

 include: [paths.toolSrc],

 // 排除 node_modules 目录下的文件

 exclude: /(node_modules)/,

 loader: 'file-loader',

 // 新增options配置参数:关于file-loader的配置项

 options: {

 limit: 10000,

 // 定义打包完成后最终导出的文件路径

 outputPath: 'css/fonts/',

 // 文件的最终名称

 name: '[name].[hash:7].[ext]'

 }

 },

 ]

 }

}

再次打包,生成的 dist 目录结构如下:


├── css

│   ├── backend.66a35.css

│   ├── backend.66a35.css.map

│   └── fonts

│       └── KlavikaMedium-Italic.620db1b.otf

├── favicon.ico

├── images

│   ├── bg.5825f.svg

│   ├── data-baseTexture.c2963.jpg

│   ├── data-heightTexture.6f50d.jpg

│   └── logo.7227a.png

├── index.html

└── js

 ├── backend.66a35.js

可以看到字体包正如配置时预期的那样存储在 css/fonts 目录下面。

重新部署项目,再次查看:

这一次 http 请求的字体包路径与实际的存放路径一致,因此自定义字体生效。

可以通过下面这个梳理流程图看的更清楚一些:
image

三. 总结

为什么本地开发的时候可以看到字体,部署到服务器后却看不到了呢?

  • 由于 webpack 项目在本地开发中使用的是 webpack-dev-server,实时编译后的文件都保存到了内存当中,引用字体包的时候使用的是绝对路径,因此在本地开发中使用的自定义字体能够生效;
  • 使用webpack打包后的 dist 目录,字体包的实际存储路径与 http 请求字体包的路径不一致,因此导致找不到字体包;
  • 借助 file-loader 解决 webpack 打包报错,通过使用 options 参数去设置字体包在打包后的实际存储路径,从而解决问题。

四. 更多文章

欢迎访问更多关于webpack系列的原创文章:

关注微信公众号

欢迎大家关注我的微信公众号阅读更多原创文章:
微信公众号二维码.jpg


全栈在路上
记录自己全栈工程师成长道路中的点点滴滴,不定时更新工作中遇到的问题、当前流行的技术栈。

可以访问 这里 查看更多关于大数据平台建设的原创文章。

445 声望
30 粉丝
0 条评论
推荐阅读
「多图预警」完美实现一个@功能
一天产品大大向 boss 汇报完研发成果和产品业绩产出,若有所思的走出来,劲直向我走过来,嘴角微微上扬。产品大大:boss 对我们的研发成果挺满意的,balabala...(内心 OS:不听,讲重点)产品大大:咱们的客服 I...

wuwhs40阅读 4.8k评论 5

封面图
ESlint + Stylelint + VSCode自动格式化代码(2023)
安装插件 ESLint,然后 File -&gt; Preference-&gt; Settings(如果装了中文插件包应该是 文件 -&gt; 选项 -&gt; 设置),搜索 eslint,点击 Edit in setting.json

谭光志34阅读 20.8k评论 9

vue UI框架比较
最好基于vue2.0PC端:因为用过的是饿了么UI,所以比较以饿了么UI为基础element UI 饿了么UI支持vue2.x80分优点:组件的API方法、属性等封装的较为完善缺点:样式有些生硬,不够炫酷美观N3 N3支持vue2.x70分优点:...

chinawzc22阅读 39.9k评论 17

涨姿势了,有意思的气泡 Loading 效果
今日,群友提问,如何实现这么一个 Loading 效果:这个确实有点意思,但是这是 CSS 能够完成的?没错,这个效果中的核心气泡效果,其实借助 CSS 中的滤镜,能够比较轻松的实现,就是所需的元素可能多点。参考我们...

chokcoco24阅读 2.3k评论 3

你可能不需要JS!CSS实现一个计时器
CSS现在可不仅仅只是改一个颜色这么简单,还可以做很多交互,比如做一个功能齐全的计时器?样式上并不复杂,主要是几个交互的地方数字时钟的变化开始、暂停操作重置操作如何仅使用 CSS 来实现这样的功能呢?一起...

XboxYan25阅读 1.7k评论 1

封面图
在前端使用 JS 进行分类汇总
最近遇到一些同学在问 JS 中进行数据统计的问题。虽然数据统计一般会在数据库中进行,但是后端遇到需要使用程序来进行统计的情况也非常多。.NET 就为了对内存数据和数据库数据进行统一地数据处理,发明了 LINQ (L...

边城17阅读 2k

封面图
Vue2 导出excel
2020-07-15更新 excel导出安装 {代码...} src文件夹下新建一个libs文件夹,新建一个excel.js {代码...} vue页面中使用 {代码...} ===========================以下为早期的文章今天在开发的过程中需要做一个Vue的...

原谅我一生不羁放歌搞文艺14阅读 20.1k评论 9

可以访问 这里 查看更多关于大数据平台建设的原创文章。

445 声望
30 粉丝
宣传栏