Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deliver fonts from a non-standard directory using Asset Pipeline

I'm trying to include Fontawesome with a Rails 4 app however the assets aren't making it into the asset pipeline. However, the fonts aren't making it out in production and I can't figure out why.

File structure organisation

All my assets are stored in /assets/components so that Fontawesome appears in: /assets/components/font-awesome (they're in a different directory because I'm using Bower).

CSS manifest file:

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

Asset pipeline is set to precompile fonts

# 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
}

I added the precompile instructions so that the fonts would all be precompiled as per this question

Heroku 12 Factor gem is included

#gemfile
group :production do
  gem "rails_12factor"
end

So what's the problem?

When I push to Heroku, it shows that the application is requesting the files but that they're not loading:

enter image description here

enter image description here

And looking at the logs it seems to be a routing issue - I would have expected the font to be served from /assets/fonts but it is apparently looking in /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"):

Why aren't the assets getting served

I'm a bit confused with all of this. Why aren't these fonts being served?

like image 355
Peter Nixey Avatar asked Oct 29 '13 15:10

Peter Nixey


1 Answers

This problem maybe caused by a reason that Rails assets can't precompile url() function in CSS file.

Because your fonts files are precompiled by assets, all urls point to these files must be rewritten to MD5-digested file name. Unfortunately Rails can't precompile url() automatically, at least I think so because I tested some cases and got this conclusion :) In Rails guide, Rails provides these functions using ERB and Sass. see here .

I think there are two ways to solve your problem.

The first, set directory in .bowerrc to public/components and use them manually, don't require them in your assets.

The second, I suggest to use font-url() instead of url() in Font-Awesome, so your application.css.scss will be looked like:

   /* ...
    *= 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;
    }

Redefine the font-path with your actual font path and font-face with font-url() , this function is provided by sass-rails. After precompile, you will see your url has been rewritten to /assets/font-awesome/fonts/fontawesome-webfont-50b448f878a6489819d7dbc0f7dbfba0.eot?v=4.0.3 or something like in public/assets/application-xxxxxx.css.

You can find the same approach in various gems which include assets for example bootstrap-sass, it's a very popular gem. read this file: _glyphicons.scss. You will see:

@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() has been replaced. So I think rewrite @font-face in application.css.scss is the simplest way :)

By the way, bootstrap and font-awesome both have @font-face. I don't know whether font-awesome is necessary.

When you access the page, it shows the correct log. So you don't need change any code in bower repositories. Hope it helps.

like image 155
Bigxiang Avatar answered Sep 21 '22 08:09

Bigxiang