解决 Rails 7 下 Sass 引用 Font Awesome 的问题
问题
Rails 7 引入了新的前端方案 CSS/JS bundling,让开发者更容易选择适合自己的打包工具。不过新方案要求开发者对 Assets Pipeline 的工作原理有更深的了解,不然会出现各种状况。
例如在引用 Font Awesome 的时候,可能会发生编译了 CSS,但没有编译字体文件的情况,这要怎么解决呢?
解决
假设项目已经配置了 Sass 作为 CSS bundling 方案。
首先安装 Font Awesome:
$ yarn add @fortawesome/fontawesome-free
然后在 config/initializers/assets.rb
添加以下内容:
Rails.application.config.assets.paths << Rails.root.join('node_modules/@fortawesome/fontawesome-free/webfonts')
最后在 app/assets/stylesheets/application.sass.scss
添加以下内容:
$fa-font-path: ".";
@import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
@import "@fortawesome/fontawesome-free/scss/solid.scss";
以上就是引用 Font Awesome 所需的配置.
讨论
如果只是拷贝配置,可能并不明白它工作的原理,下次遇到别的库出现问题还是无法解决。所以接下来解释它的原理。
首先要了解,Assets Pipeline + CSS Bundling 的流程中,CSS 会经历以下处理:
- Sass 将
.sass
编译成.css
。 - Assets Pipeline 处理
.css
,将里面url()
引用的资源路径替换成包含哈希值的路径。 - 将处理后的
.css
文件加上哈希值,储存在资源列表中,供 layout 引用。
假设在 app/assets/stylesheets/application.sass.scss
只有以下内容:
@import "@fortawesome/fontawesome-free/scss/fontawesome.scss";
@import "@fortawesome/fontawesome-free/scss/solid.scss";
Sass 会把该文件编译到 app/assets/builds/application.css
,其中包含以下内容:
@font-face {
font-family: "Font Awesome 6 Free";
font-style: normal;
font-weight: 900;
font-display: block;
src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype");
}
可以看到,Font Awesome 的 CSS 内容已经编译成功了,但其中字体的 url()
指向的资源并不在 Assets Piepeline 的资源列表中,Assets Pipeline 会保留 url()
原本模样不做处理。最终导致浏览器去下载 ../webfonts/fa-solid-900.woff2
, 得到 404 错误,字体无法呈现。
要解决这个问题,首先我们要把字体文件添加到 Assets Pipeline 的引用路径中,这就是以下这行代码的作用:
Rails.application.config.assets.paths << Rails.root.join('node_modules/@fortawesome/fontawesome-free/webfonts')
添加这行代码后,Assets Pipeline 的资源列表中就能找到 fa-solid-900.woff2
这个文件。
另一个问题是,Font Awesome 的默认字体路径处于 ../webfonts/
目录,依然跟资源地址不匹配。所以需要加上以下配置:
$fa-font-path: ".";
这个变量是 Font Awesome 提供,用来修改字体地址的。修改变量后,编译后的 CSS 内容为:
@font-face {
font-family: "Font Awesome 6 Free";
font-style: normal;
font-weight: 900;
font-display: block;
src: url("./fa-solid-900.woff2") format("woff2"), url("./fa-solid-900.ttf") format("truetype");
}
由于 application.css
和 fa-solid-900.woff2
在 Assets Pipeline 的路径中都处于根目录,这样就能找到对应的资源。
如果在浏览器中查看最终的 CSS,还会看到字体地址已经加上了哈希值:
@font-face {
font-family: "Font Awesome 6 Free";
font-style: normal;
font-weight: 900;
font-display: block;
src: url(/assets/fa-solid-900-addc97d14257b43232b89194f73bd3b862007d5eedcb4569362b8f26356d8db3.woff2) format("woff2"), url(/assets/fa-solid-900-a0cc38b88839387e4451bb1ebdd9ecd821b2df0f7fcd5b26df75630f4171ee32.ttf) format("truetype");
}
总结
除了 Font Awesome,其他需要引用字体、图片的前端库,在 Rails 7 的打包方案下也可能遇到以上问题。如果是资源地址不正确、没有编译相关文件的问题,可以参照本文的方法解决。