I have some fonts being configured in my Scss file like so:
@font-face {
font-family: \'Icomoon\';
src: asset-url(\'icoMoon.eot?#iefix\', font) format(\'
Here is a repo the demonstrates serving a custom font with Rails 5.2 that works on Heroku. It goes further and optimizes serving the fonts to be as fast as possible according to https://www.webpagetest.org/
https://github.com/nzoschke/edgecors
To start I picked pieces from answers above. For Rails 5.2+ you shouldn't need extra asset pipeline config.
app/assets/fonts
@font-face
declaration in an scss file and use the font-url
helperFrom app/assets/stylesheets/welcome.scss
:
@font-face {
font-family: 'Inconsolata';
src: font-url('Inconsolata-Regular.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
body {
font-family: "Inconsolata";
font-weight: bold;
}
I'm using CloudFront, added with the Heroku Edge addon.
First configure a CDN prefix and default Cache-Control
headers in production.rb
:
Rails.application.configure do
# e.g. https://d1unsc88mkka3m.cloudfront.net
config.action_controller.asset_host = ENV["EDGE_URL"]
config.public_file_server.headers = {
'Cache-Control' => 'public, max-age=31536000'
}
end
If you try to access the font from the herokuapp.com URL to the CDN URL, you will get a CORS error in your browser:
Access to font at 'https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf' from origin 'https://edgecors.herokuapp.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. edgecors.herokuapp.com/ GET https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf net::ERR_FAILED
So configure CORS to allow access to the font from Heroku to the CDN URL:
module EdgeCors
class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.2
config.middleware.insert_after ActionDispatch::Static, Rack::Deflater
config.middleware.insert_before 0, Rack::Cors do
allow do
origins %w[
http://edgecors.herokuapp.com
https://edgecors.herokuapp.com
]
resource "*", headers: :any, methods: [:get, :post, :options]
end
end
end
end
The asset pipeline builds a .ttf.gz
file but doesn't serve it. This monkey patch changes the asset pipeline gzip whitelist to a blacklist:
require 'action_dispatch/middleware/static'
ActionDispatch::FileHandler.class_eval do
private
def gzip_file_path(path)
return false if ['image/png', 'image/jpeg', 'image/gif'].include? content_type(path)
gzip_path = "#{path}.gz"
if File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
gzip_path
else
false
end
end
end
The ultimate result is a custom font file in app/assets/fonts
served from a long-lived CloudFront cache.
I'm using Rails 4.2, and could not get the footable icons to show up. Little boxes were showing, instead of the (+) on collapsed rows and the little sorting arrows I expected. After studying the information here, I made one simple change to my code: remove the font directory in css. That is, change all the css entries like this:
src:url('fonts/footable.eot');
to look like this:
src:url('footable.eot');
It worked. I think Rails 4.2 already assumes the font directory, so specifying it again in the css code makes the font files not get found. Hope this helps.
If your Rails version is between > 3.1.0
and < 4
, place your fonts in any of the these folders:
app/assets/fonts
lib/assets/fonts
vendor/assets/fonts
For Rails versions > 4
, you must place your fonts in the app/assets/fonts
folder.
Note: To place fonts outside of these designated folders, use the following configuration:
config.assets.precompile << /\.(?:svg|eot|woff|ttf)\z/
For Rails versions > 4.2
, it is recommended to add this configuration to config/initializers/assets.rb
.
However, you can also add it to either config/application.rb
, or to config/production.rb
Declare your font in your CSS file:
@font-face {
font-family: 'Icomoon';
src:url('icomoon.eot');
src:url('icomoon.eot?#iefix') format('embedded-opentype'),
url('icomoon.svg#icomoon') format('svg'),
url('icomoon.woff') format('woff'),
url('icomoon.ttf') format('truetype');
font-weight: normal;
font-style: normal;
}
Make sure your font is named exactly the same as in the URL portion of the declaration. Capital letters and punctuation marks matter. In this case, the font should have the name icomoon
.
If you are using Sass or Less with Rails > 3.1.0
(your CSS file has .scss
or .less
extension), then change the url(...)
in the font declaration to font-url(...)
.
Otherwise, your CSS file should have the extension .css.erb
, and the font declaration should be url('<%= asset_path(...) %>')
.
If you are using Rails > 3.2.1
, you can use font_path(...)
instead of asset_path(...)
. This helper does exactly the same thing but it's more clear.
Finally, use your font in your CSS like you declared it in the font-family
part. If it was declared capitalized, you can use it like this:
font-family: 'Icomoon';
If you don't want to keep track of moving your fonts around:
# Adding Webfonts to the Asset Pipeline
config.assets.precompile << Proc.new { |path|
if path =~ /\.(eot|svg|ttf|woff)\z/
true
end
}
Now here's a twist:
You should place all fonts in
app/assets/fonts/
as they WILL get precompiled in staging and production by default—they will get precompiled when pushed to heroku.Font files placed in
vendor/assets
will NOT be precompiled on staging or production by default — they will fail on heroku. Source!
— @plapier, thoughtbot/bourbon
I strongly believe that putting vendor fonts into
vendor/assets/fonts
makes a lot more sense than putting them intoapp/assets/fonts
. With these 2 lines of extra configuration this has worked well for me (on Rails 4):
app.config.assets.paths << Rails.root.join('vendor', 'assets', 'fonts')
app.config.assets.precompile << /\.(?:svg|eot|woff|ttf)$/
— @jhilden, thoughtbot/bourbon
I've also tested it on rails 4.0.0
. Actually the last one line is enough to safely precompile fonts from vendor
folder. Took a couple of hours to figure it out. Hope it helped someone.
Here my approach to using fonts in asset pipeline:
1) Put all your font file under app/assets/fonts/
, actually you are not restricted to put it under fonts
folder name. You can put any subfolder name you like. E.g. app/assets/abc
or app/assets/anotherfonts
. But i highly recommend you put it under app/assets/fonts/
for better folder structure.
2) From your sass file, using the sass helper font-path
to request your font assets like this
@font-face {
font-family: 'FontAwesome';
src: url(font-path('fontawesome-webfont.eot') + '?v=4.4.0');
src: url(font-path('fontawesome-webfont.eot') + '?#iefix&v=4.4.0') format('embedded-opentype'),
url(font-path('fontawesome-webfont.woff2') + '?v=4.4.0') format('woff2'),
url(font-path('fontawesome-webfont.woff') + '?v=4.4.0') format('woff'),
url(font-path('fontawesome-webfont.ttf') + '?v=4.4.0') format('truetype'),
url(font-path('fontawesome-webfont.svg') + '?v=4.4.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
3) Run bundle exec rake assets:precompile
from your local machine and see your application.css result. You should see something like this:
@font-face {
font-family: 'FontAwesome';
src: url("/assets/fontawesome-webfont-d4f5a99224154f2a808e42a441ddc9248ffe78b7a4083684ce159270b30b912a.eot" "?v=4.4.0");
src: url("/assets/fontawesome-webfont-d4f5a99224154f2a808e42a441ddc9248ffe78b7a4083684ce159270b30b912a.eot" "?#iefix&v=4.4.0") format("embedded-opentype"), url("/assets/fontawesome-webfont-3c4a1bb7ce3234407184f0d80cc4dec075e4ad616b44dcc5778e1cfb1bc24019.woff2" "?v=4.4.0") format("woff2"), url("/assets/fontawesome-webfont-a7c7e4930090e038a280fd61d88f0dc03dad4aeaedbd8c9be3dd9aa4c3b6f8d1.woff" "?v=4.4.0") format("woff"), url("/assets/fontawesome-webfont-1b7f3de49d68b01f415574ebb82e6110a1d09cda2071ad8451bdb5124131a292.ttf" "?v=4.4.0") format("truetype"), url("/assets/fontawesome-webfont-7414288c272f6cc10304aa18e89bf24fb30f40afd644623f425c2c3d71fbe06a.svg" "?v=4.4.0#fontawesomeregular") format("svg");
font-weight: normal;
font-style: normal;
}
If you want to know more how asset pipeline work, you can visit the following simple guide: https://designcode.commandrun.com/rails-asset-pipeline-simple-guide-830e2e666f6c#.6lejlayk2