如何使用 Asset Pipeline 从非标准目录传递字体

Posted

技术标签:

【中文标题】如何使用 Asset Pipeline 从非标准目录传递字体【英文标题】:How to deliver fonts from a non-standard directory using Asset Pipeline 【发布时间】:2013-11-08 21:51:02 【问题描述】:

我正在尝试将 Fontawesome 包含在 Rails 4 应用程序中,但资产并未进入资产管道。但是,字体并没有在生产中出现,我不知道为什么。

文件结构组织

我所有的资产都存储在/assets/components 这样 Fontawesome 就会出现在:/assets/components/font-awesome(它们位于不同的目录中,因为我使用的是 Bower)。

CSS 清单文件:

# application.css.scss
/* ...
*= require bootstrap/dist/css/bootstrap
*= require font-awesome/css/font-awesome
*= require_self
*= require_tree .
*/

资产管道设置为预编译字体

# Version of your assets, change this if you want to expire all your assets
config.assets.version = '1.0'
config.assets.paths << Rails.root.join('vendor', 'assets', 'components')

# Adding Webfonts to the Asset Pipeline
config.assets.precompile << Proc.new  |path|
  if path =~ /\.(eot|svg|ttf|woff|otf)\z/
    true
  end

我添加了预编译指令,以便所有字体都被预编译as per this question

包括 Heroku 12 Factor gem

#gemfile
group :production do
  gem "rails_12factor"
end

那么问题出在哪里?

当我推送到 Heroku 时,它显示应用程序正在请求文件但它们没有加载:

查看日志,这似乎是一个路由问题 - 我原以为字体会从 /assets/fonts 提供,但它显然在 /fonts 中查找

   app[web.1]: Started GET "/fonts/fontawesome-webfont.ttf?v=4.0.1" for 86.161.231.181 at 2013-10-29 15:53:01 +0000
   app[web.1]: Started GET "/fonts/fontawesome-webfont.ttf?v=4.0.1" for 86.161.231.181 at 2013-10-29 15:53:01 +0000
   app[web.1]: 
   app[web.1]: ActionController::RoutingError (No route matches [GET] "/fonts/fontawesome-webfont.ttf"):

为什么没有提供资产

我对这一切有点困惑。为什么不提供这些字体?

【问题讨论】:

它说'没有路由匹配 [GET] "/fonts/fontawesome-webfont.ttf',但你不想从 /assets/fontawesome-webfont.ttf 加载吗?在 fontawesome。 css,我使用了 url('../fontawesome-webfont.ttf') 而不是 url('fonts/fontawesome-webfont.ttf') 嗨@AmyHua。你是对的,但是你不应该需要指定单独的字体文件。清单文件和单行 require font-awesome/css/font-awesome 应该处理所有其他文件。此外,字体确实在开发中正确加载,只是链轮无法正确解析。 Heroku 有一个临时文件系统,您可以在会话中创建文件,但这只是您的 dyno 的一个实例,文件不会出现在新会话中,因为它将是新实例。也许你应该在推送之前确定文件是否在你的仓库中。 【参考方案1】:

这个问题可能是由于 Rails 资源无法在 CSS 文件中预编译 url() 函数引起的。

由于您的字体文件是由资产预编译的,所有指向这些文件的 url 都必须重写为 MD5 消化的文件名。不幸的是,Rails 不能自动预编译url(),至少我是这么认为的,因为我测试了一些案例并得出了这个结论:) 在 Rails 指南中,Rails 使用 ERB 和 Sass 提供了这些功能。见here。

我认为有两种方法可以解决您的问题。

首先,将.bowerrc中的目录设置为public/components并手动使用它们,不要在资产中要求它们。

第二个,我建议在 Font-Awesome 中使用font-url() 而不是url(),这样你的application.css.scss 就会变成这样:

   /* ...
    *= require bootstrap/dist/css/bootstrap
    *= require font-awesome/css/font-awesome
    *= require_self
    *= require_tree .
    */    

    @font-face 
      font-family: 'FontAwesome';
      src: font-url('font-awesome/fonts/fontawesome-webfont.eot?v=4.0.3');
      src: font-url('font-awesome/fonts/fontawesome-webfont.eot?#iefix&v=4.0.3') format('embedded-opentype'),
      font-url('font-awesome/fonts/fontawesome-webfont.woff?v=4.0.3') format('woff'),
      font-url('font-awesome/fonts/fontawesome-webfont.ttf?v=4.0.3') format('truetype'),
      font-url('font-awesome/fonts/fontawesome-webfont.svg?v=4.0.3#fontawesomeregular') format('svg');
      font-weight: normal;
      font-style: normal;
    

用你的实际字体路径重新定义字体路径,用font-url()重新定义字体,这个功能由sass-rails提供。预编译后,您会看到您的 url 已被重写为 /assets/font-awesome/fonts/fontawesome-webfont-50b448f878a6489819d7dbc0f7dbfba0.eot?v=4.0.3public/assets/application-xxxxxx.css 中的类似内容。

您可以在各种包含资产的 gem 中找到相同的方法,例如 bootstrap-sass,它是一个非常受欢迎的 gem。阅读此文件:_glyphicons.scss。你会看到:

@font-face 
  font-family: 'Glyphicons Halflings';
  src: font-url('#$icon-font-path#$icon-font-name.eot');
  src: font-url('#$icon-font-path#$icon-font-name.eot?#iefix') format('embedded-opentype'),
       font-url('#$icon-font-path#$icon-font-name.woff') format('woff'),
       font-url('#$icon-font-path#$icon-font-name.ttf') format('truetype'),
       font-url('#$icon-font-path#$icon-font-name.svg#glyphicons_halflingsregular') format('svg');

url() 已被替换。所以我认为在application.css.scss 中重写@font-face 是最简单的方法:)

顺便说一下,bootstrap 和 font-awesome 都有@font-face。我不知道是否需要font-awesome。

当您访问该页面时,它会显示正确的日志。因此,您无需更改 bower 存储库中的任何代码。希望对您有所帮助。

【讨论】:

你好。这太棒了,谢谢你花了这么多时间。令人沮丧的是,这是所需的解决方案类型。我想知道font-url() 声明是否是问题所在。修复需要的东西太多了,以至于我几乎想知道将文件简单地放入目录并忽略 bower 是否更容易。这似乎很遗憾,但实际上也似乎更容易。你认为什么更易于维护? 嗨彼得,我已经改进了答案,请看一下。我认为如果有可以使用资产的 gem,使用 gem 会更易于维护。 Bower 可用于在没有url() 的情况下轻松包含 javascript 和 css。 Rails、bower/bower-rails 和 font-awesome/bootstrap 字体也有同样的问题。 @Bigxiang您的解决方案运行良好,但我仍然很困惑是否设置不正确或者这是完成此操作的正确(不幸)方式。

以上是关于如何使用 Asset Pipeline 从非标准目录传递字体的主要内容,如果未能解决你的问题,请参考以下文章

如何加快 Rails Asset Pipeline 预编译过程?

Rails Asset Pipeline 预编译,如何正确执行?

带有 3rd 方库的 Grails Asset-Pipeline 系统

使用 Grails Asset-Pipeline 将 JavaScript 置于底层

在asset_pipeline中包含来自rails应用程序之外的资产

markdown Rails Asset Pipeline:`require`指令