我有一些字体被配置在我的Scss文件如下:

@font-face {
  font-family: 'Icomoon';
  src: asset-url('icoMoon.eot?#iefix', font) format('embedded-opentype'),
       asset-url('icoMoon.woff', font) format('woff'),
       asset-url('icoMoon.ttf', font)  format('truetype'),
       asset-url('icoMoon.svg#Icomoon', font) format('svg');
}

实际的字体文件存储在/app/assets/fonts/中

我添加了config.assets.paths << Rails.root。加入(“应用程序”,“资产”,“字体”)到我的应用程序。rb文件

编译CSS源代码如下:

@font-face {
  font-family: 'Icomoon';
  src: url(/assets/icoMoon.eot?#iefix) format("embedded-opentype"), url(/assets/icoMoon.woff) format("woff"), url(/assets/icoMoon.ttf) format("truetype"), url(/assets/icoMoon.svg#Icomoon) format("svg");
}

但当我运行应用程序的字体文件没有被发现。日志:

start GET "/assets/icoMoon.ttf" for 127.0.0.1 at 2012-06-05 23:21:17 +0100 已服务资产/icoMoon.ttf - 404 Not Found (13ms)

为什么资产管道不把字体文件压缩成/assets?

大家有什么想法吗?

亲切的问候, 尼尔。

额外信息:

当检查rails控制台的资产路径和assetprecompile时,我得到如下:

1.9.2p320 :001 > y Rails.application.config.assets.precompile
---
- !ruby/object:Proc {}
- !ruby/regexp /(?:\/|\\|\A)application\.(css|js)$/
- .svg
- .eot
- .woff
- .ttf
=> nil



1.9.2p320 :002 > y Rails.application.config.assets.paths
---
- /Users/neiltonge/code/neiltonge/app/assets/fonts
- /Users/neiltonge/code/neiltonge/app/assets/images
- /Users/neiltonge/code/neiltonge/app/assets/javascripts
- /Users/neiltonge/code/neiltonge/app/assets/stylesheets
- /Users/neiltonge/code/neiltonge/vendor/assets/images
- /Users/neiltonge/code/neiltonge/vendor/assets/javascripts
- /Users/neiltonge/code/neiltonge/vendor/assets/stylesheets
- /Users/neiltonge/.rvm/gems/ruby-1.9.2-p320@neiltonge/gems/jquery-rails-2.0.0/vendor/assets/javascripts
- /Users/neiltonge/.rvm/gems/ruby-1.9.2-p320@neiltonge/gems/coffee-rails-3.2.1/lib/assets/javascripts
- /Users/neiltonge/.rvm/gems/ruby-1.9.2-p320@neiltonge/gems/bourbon-1.3.0/app/assets/stylesheets
- !ruby/object:Pathname
  path: /Users/neiltonge/code/neiltonge/app/assets/fonts
 => nil

当前回答

这里是一个repo演示了在Heroku上使用Rails 5.2提供自定义字体。它进一步优化服务字体,根据https://www.webpagetest.org/尽可能快

https://github.com/nzoschke/edgecors

首先,我从上面的答案中挑选了一些。对于Rails 5.2+,您不需要额外的资产管道配置。

资产管道和SCSS

将字体放置在app/assets/fonts中 将@font-face声明放在一个scss文件中,并使用font-url帮助器

从app /资产/样式表/ 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;
}

从CDN与CORS服务

我正在使用CloudFront,添加了Heroku Edge插件。

首先在生产端配置CDN前缀和默认的Cache-Control头。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

如果您尝试从herokuapp.com URL访问CDN URL的字体,您将在浏览器中得到一个CORS错误:

从“https://edgecors.herokuapp.com”访问“https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf”的字体已被CORS政策阻止: 被请求的资源上没有'Access-Control-Allow-Origin'标头。edgecors.herokuapp.com/ GET https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf net::ERR_FAILED

因此,配置CORS以允许从Heroku到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

服务gzip字体资产

资产管道构建一个.ttf.gz文件,但不为它服务。这个monkey补丁将资产管道gzip白名单更改为黑名单:

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

最终的结果是app/assets/fonts中的自定义字体文件,这些文件由CloudFront长期缓存提供。

其他回答

这里是一个repo演示了在Heroku上使用Rails 5.2提供自定义字体。它进一步优化服务字体,根据https://www.webpagetest.org/尽可能快

https://github.com/nzoschke/edgecors

首先,我从上面的答案中挑选了一些。对于Rails 5.2+,您不需要额外的资产管道配置。

资产管道和SCSS

将字体放置在app/assets/fonts中 将@font-face声明放在一个scss文件中,并使用font-url帮助器

从app /资产/样式表/ 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;
}

从CDN与CORS服务

我正在使用CloudFront,添加了Heroku Edge插件。

首先在生产端配置CDN前缀和默认的Cache-Control头。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

如果您尝试从herokuapp.com URL访问CDN URL的字体,您将在浏览器中得到一个CORS错误:

从“https://edgecors.herokuapp.com”访问“https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf”的字体已被CORS政策阻止: 被请求的资源上没有'Access-Control-Allow-Origin'标头。edgecors.herokuapp.com/ GET https://d1unsc88mkka3m.cloudfront.net/assets/Inconsolata-Regular.ttf net::ERR_FAILED

因此,配置CORS以允许从Heroku到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

服务gzip字体资产

资产管道构建一个.ttf.gz文件,但不为它服务。这个monkey补丁将资产管道gzip白名单更改为黑名单:

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

最终的结果是app/assets/fonts中的自定义字体文件,这些文件由CloudFront长期缓存提供。

只需要把你的字体放在app/assets/fonts文件夹中,并在app开始使用application.rb中编写代码时设置自动加载路径

config.assets.paths << Rails.root。加入("app", "assets", "fonts") 而且

然后在css中使用以下代码。

@font面{

 font-family: 'icomoon';
 src: asset-url('icomoon.eot');
 src: asset-url('icomoon.eot') format('embedded-opentype'),
      asset-url('icomoon.woff') format('woff'),
      asset-url('icomoon.ttf') format('truetype'),
      asset-url('icomoon.svg') format('svg');
 font-weight: normal;
 font-style: normal;

}

试一试。

谢谢

这里有一个转折:

你应该把所有的字体放在app/assets/fonts/中,因为它们在默认情况下会在登台和生产中被预编译——当推送到heroku时,它们会被预编译。 默认情况下,放置在vendor/assets中的字体文件不会在登台或生产时预编译-它们将在heroku上失败。源!

- @plapier,以为机器人/波旁威士忌

我坚信把厂商字体放到厂商/资产/字体中 这比把它们放到app/assets/字体中更有意义。与 这两行额外的配置对我来说工作得很好 Rails 4):

app.config.assets.paths << Rails.root.join('vendor', 'assets', 'fonts')  
app.config.assets.precompile << /\.(?:svg|eot|woff|ttf)$/

- @jhilden, thoughtbot/波旁威士忌

我还在rails 4.0.0上测试了它。实际上,最后一行已经足够从供应商文件夹安全预编译字体了。花了几个小时才弄明白。希望它能帮助到某人。

把你的字体文件(woff, woff2, eot, ttf,…)放在/app/assets/fonts目录下。

然后添加以下到您的配置/初始化/资产。rb:

Rails.application.config.assets.paths << Rails.root.join('app', 'assets', 'fonts')
Rails.application.config.assets.precompile << /\.(?:svg|eot|woff|woff2|ttf)\z/

在上面的答案中,woff2没有包括在内(为了将来的参考,你可能需要添加其他扩展,只需在这里添加|{font-file-extension})

使用css文件中的字体:

重要的是,你需要将它从stylesheet.css重命名为stylesheet.css.scss(这是为了让font-url在资产预编译后正确地在生产中转换字体的url):

@font-face {
  font-family: 'MyFont'
  src: font-url('myfont.woff') format('woff');
}

body{
  font-family: 'MyFont'
}

然后运行:

rails assets:precompile

在运行资产预编译后,你的字体文件从app/assets/fonts/myfont复制。woff到public/assets/myfont-{SOME_DIGEST_KEY}。woff的位置。现在上面的css在生产中也很像图像资产。

您还可以看到,在预编译资产命令之后创建了一个应用程序-{somedigest}.css,在其中您将看到 现在,我们的font-url('myfont.woff')将被转换为url(/assets/myfont.woff-{SOME_DIGEST_KEY}.woff),并且摘要与文件移动到的位置匹配。通过这种方式,更新你的字体文件也可以适当地破坏浏览器缓存等。

确保你的nginx也服务于public/assets文件夹以获得更好的性能。这是用rails 5和rails 6在生产中测试的。它也应该工作与rails 4最有可能。

如果你不想跟踪字体的移动:

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