深入 Webpack5 等构建工具系列三(5) - webpack 对字体文件的打包

2,279 阅读4分钟

这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战

开发中,除了图片资源,可能还会有其它的资源需要打包,比如说字体文件。如果我们需要使用某些特殊的字体或字体图标,就会引入很多字体相关的文件,对于这些文件的处理也可以用 Asset Modules type 来做。

比如我们从阿里图标库中任意找两个字体图标,添加入库后去下载代码:

image-20210831192934780.png

image-20210831192902561.png

下载下来后解压,把里面的 iconfont.cssiconfont.ttficonfont.eoticonfont.wofficonfont.woff2 文件(如果有后面三个文件)拷贝到项目中去(我们需要在 src 目录下新建一个 font 目录,用来存放这些字体文件):

image-20210831193828277.png

  • 补充:

    • .eot.ttf.woff.woff2 表示不同的字体格式,我们不同的浏览器会支持不同的字体格式;
    • 这里的 iconfont.css 中已经默认将这些不同的字体格式文件加载好了,我们后面直接使用这个 css 文件即可。我们可以从这个 css 文件的开头看到加载各种字体格式文件的代码:

    image-20210831200944998.png

然后在 src/css/index.css (当前项目所有 css 的入口文件)中引入这个 iconfont.css 文件(这样就加入进了 webpack 的依赖关系图,后续我们使用 webpack 打包项目时才会对它进行加载、打包):

// ...
@import "../font/iconfont.css";

// ...

我们来思考一下,这时如果我们运行 npm run build 命令打包项目,会成功吗?

显然,不会成功,因为我们当前 index.css 文件中会加载 iconfont.css 文件,而 iconfont.css 文件中又通过 url 加载 .eot.woff.woff2.ttf 文件,但 webpack 默认情况下并不认识这些格式的字体文件,所以当 webpack 将这些字体文件当做模块去解析时就会解析失败,因此需要我们使用合适的 loader 去处理这些字体文件,在 webpack 5 之前,我们可以用 file-loaderurl-loader 处理这些字体文件,但在 webpack 5 中,我们已经没有必要再去安装对应的 loader 了,因为我们可以使用 Asset Modules 来处理这些文件。

而且,像这些字体文件,我们一般不会对它进行 base64 编码,而是直接对它进行复制,也就是使用 asset/resource 类型来处理,webpack 配置文件修改如下:

module: {
  rules: [
    // ...
    // 添加字体文件的处理规则
    {
      test: /.ttf|eot|woff2?$/i,
      type: 'asset/resource',
      generator: {
        // 输出到 font 目录中,占位符 [name] 保留原始文件名,
        // [hash] 防止出现相同文件名无法区分,[ext] 拿到后缀名
        filename: 'font/[name].[hash:6][ext]'
      }
    }
  ]
}

添加完上述规则后,删除项目根目录下的 build 文件夹,再来运行 npm run build,就不再报错了,再来看打包后的文件夹:

image-20210831203625656.png

可以看到,字体文件都已经成功打包进 build/font 目录中了。

字体文件的打包没问题了,我们再来看下字体的使用有没有问题。我们打开 src/js/component.js 文件,在 component() 函数中创建并添加一个 i 元素用来显示字体图标:

function component() {
  // ...

  // 创建一个 i 元素,设置一个图标字体
  const iEl = document.createElement('i');
  iEl.className = 'iconfont icon-ashbin';
  element.appendChild(iEl);

  return element;
}

然后删除项目根目录下的 build 文件夹,再来运行 npm run build 重新打包项目,打包成功后,用 Live Server 打开 index.html 页面,效果如下:

image-20210831205431031.png

当然,我们还可以自己再给字体图标添加些样式,比如再给前面创建的 i 元素添加一个 class,前面的代码修改如下:

function component() {
  // ...

  // 创建一个 i 元素,设置一个图标字体
  const iEl = document.createElement('i');
  iEl.className = 'iconfont icon-ashbin custom-ashbin';
  element.appendChild(iEl);

  return element;
}

并在 index.css 文件的最后添加代码:

.custom-ashbin {
  color: red;
  font-size: 60px;
}

再来删除项目根目录下的 build 文件夹后重新打包项目(后面我们讲了 devServer 后就不用一直手动重新打包了),用 Live Server 打开 index.html 页面,效果如下:

image-20210831210317252.png

总结:以后在项目中用到了字体文件,或者像 MP3MP4 文件,都可以通过 Asset Modules type 来进行加载打包。