Asset Pipelineでハマった
Railsでアプリケーションを開発していると、Asset周りに問題が生じてdevelopment環境ではうまくいくのにProduction環境ではうまくいかないことがあります。私はフォントファイルを含むフレームワーク(Onsen UI)でハマったので、なぜうまくいかなかったのか検証してみました。
ここではRailsでFont Awesomeを使うアプリケーションを作ってみたいと思います。(普通RailsでFont Awesomeを使うときはgemかCDNを使ってください)
環境は、OS X 10.11,Chrome 47,Rails 4.2.4
Assetを配置する
less
とscss
はいらなそうなので削除しました。
Font Awesomeを置く場所
Railsでは、Assetを配置する場所は以下のように3箇所あります。
- /app/assets/
- /lib/assets/
- /vendor/assets/
/lib/assets/
は自作のライブラリ、/vendor/assets/
は外部のライブラリを置くみたいですね。
RailsでJavaScriptライブラリの配置に迷う
http://shin.hateblo.jp/entry/2013/01/20/164924
Asset Pipelineに組み込む
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any styles
* defined in the other CSS/SCSS files in this directory. It is generally better to create a new
* file per style scope.
*
*= require_tree .
*= require_self
*= require_tree ../../../vendor/assets/font-awesome-4.5.0/.
*/
require_tree
でfont-awesome-4.5.0
配下をディレクトリごとAsset Pipelineに追加します。
development環境で試す
適当にcontroller,viewを作成します。
<h1>Test</h1>
<i class="fa fa-fort-awesome"></i>
できました。このときfont-awesome-4.5.0/css/font-awesome.css
からfont-awesome-4.5.0/font/fontawesome-webfont.woff2
を読み込んでいます。ブラウザはこのfontawesome-webfont.woff2
に、http://localhost:3000/assets/fonts/fontawesome-webfont.woff2?v=4.5.0
でアクセスしています。
Production環境で試す
Production環境でサーバーを立ち上げるときはいくつか初期設定をする必要があります。
secretを設定
rake secret
でシークレットキーを生成します。
secret_key_base
はgitにcommitしたくないので環境変数で設定するのがいいらしいです。でも今回はローカルでテストするだけなので直接書いてしまうことにしました。
- http://qiita.com/kanpe777/items/cb11dc88ced544d10bd5
- http://qiita.com/kenjiszk/items/2e45660ce3b46596dfa1
development:
secret_key_base: 1bd92e6851e6a8fd5a6b828644a4a2c33d955866d65e65b956d69fde30cc05aad84f410abdb9adcedc8524bc7c29bdd72abbc8edd0222ebeb964d4a05992d28e
test:
secret_key_base: 19c7e9c5fb7cb68f4995c0fc571b33527036122ef92494634be1288dddf6b9f4d048975ea0ca761c640b009fe18c4d00fff3509dc666ce4b423c20d0c31ad943
production:
secret_key_base: 5eabd1e39824217842cbfdd187baac88d1dc7efc0da865bdeabd2ce0a2bea03a79a0c548be9126f92e95911fc2dbc4f1152b307b41e5f5152bac4c0a1833a07c
serve_static_filesをtrueに
静的なAssetを配信するのでtrue
にします。
config.serve_static_files = true
フォントをprecompileの対象にする
以下の行を追加します。
Rails.application.config.assets.precompile += %w( *.svg *.eot *.woff *.woff2 *.ttf )
これでpublic/
にフォントファイルがdigest付きでコピーされるようになります。
Rails4 でフォントの precompile に関する問題の解決策
http://qiita.com/onjiro/items/809dbc3c61b1fa576b26
assetをprecompile
development環境では、ページにアクセスするときにAssetがコンパイルされますが、production環境ではAssetを予めコンパイルしておく必要があります。このときにdigestが付加されたり、複数のcssやscriptが1つのファイルにまとめられる処理がされます。これが原因でproduction環境でうまくいかないことがしばしば...
rake assets:precompile
サーバーを立ち上げる
rails s -e production
はい、うまくいきませんでした。
フォントのファイルが404吐いてますね。。。ちなみにブラウザはこれらのファイルにhttp://localhost:3000/fonts/fontawesome-webfont.woff2?v=4.5.0
のようなURLでアクセスしようとしています。
fontawesome-webfont.woff2
のURLの違い
ブラウザがアクセスするURLはdevelopment
環境とproduction
で異なっていました。
development
http://localhost:3000/assets/fonts/fontawesome-webfont.woff2?v=4.5.0
→OK!
production
http://localhost:3000/fonts/fontawesome-webfont.woff2?v=4.5.0
→NG!
なぜこの違いが生まれるのでしょうか。ここでfont-awesome.css
を見てみたいと思います。
/*!
* Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
/* FONT PATH
* -------------------------- */
@font-face {
font-family: 'FontAwesome';
src: url('../fonts/fontawesome-webfont.eot?v=4.5.0');
src: url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
.fa {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.
.
.
.
ご覧のように相対パスで外部のフォントファイルを読み込んでいます。development環境では問題なくフォントファイルを読み込めるのですが、production環境ではcssがapplication.cssにまとめられてしまうので、パスに問題が生じると考えられます。
それぞれの環境でfont-awesome.css
が含まれるcssのパスを見てみると、
development:
http://localhost:3000/assets/css/font-awesome.self-096a1cf4b422c9c89eb905af2ee7bff3a955fc2ceefa7c0047237a0dddb7ce84.css?body=1
production:
http://localhost:3000/assets/application-586178e847adcc8902faa9d49adfc88c6c2df004a6ba8571cc56e726159e6172.css
となっていました。
フォントを読み込むには?
今の構成だと、ほしいフォントファイルには以下のURLでアクセスでます:
http://localhost:3000/assets/fonts/fontawesome-webfont-ff82aeed6b9bb6701696c84d1b223d2e682eb78c89117a438ce6cfea8c498995.woff2
パスも修正する必要がありますが、まずdigestをなんとかしましょう。
non-stupid-digest-assetsを使う
non-stupid-digest-assetsはdigestなしのassetも書き出してくれるgemです。
Gemfile
にgem 'non-stupid-digest-assets'
を追加してbundle install
を実行します。
次に、non_digest_assets.rb
を作成します。
NonStupidDigestAssets.whitelist += [/fonts\/.*/]
パスはpublic/assets/
からの相対パスを指定しましょう。
これでhttp://localhost:3000/assets/fonts/fontawesome-webfont.woff2
でフォントファイルを読み込めるようになりました。
次にパスの修正を行います。
方法1 publicにfontを保存
このようにfonts
ディレクトリをコピーすればうまくいきます。Font Awesomeののファイルが分散してしまうのが難点です。
方法2 cssを書き換える
以下のようにパスを修正すればフォントファイルを読み込めるようになります。font-awesome.css
とfont-awesome.min.css
がありますが、後者は削除しておきましょう。
/*!
* Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
/* FONT PATH
* -------------------------- */
@font-face {
font-family: 'FontAwesome';
src: url('fonts/fontawesome-webfont.eot?v=4.5.0');
src: url('fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'), url('fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'), url('fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'), url('fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'), url('fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');
font-weight: normal;
font-style: normal;
}
.fa {
display: inline-block;
font: normal normal normal 14px/1 FontAwesome;
font-size: inherit;
text-rendering: auto;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.
.
.
.
これでフォントを正常に読み込めるようになります。でも外部のライブラリに手を加えるのはなるべく避けたいところです。
Asset Pipelineを諦める
結局のところ全部public/
に配置してしまうのが一番簡単だと思います。Asset Pipelineの恩恵は受けられなくなりますが。。。
HTMLでfont-awesome.min.css
を読み込みます。
<link rel="stylesheet" href="font-awesome-4.5.0/css/font-awesome.min.css">
<h1>Test</h1>
<i class="fa fa-fort-awesome"></i>
まとめ
- Asset PipelineではCSSとJSが一つのファイルにまとめられるので、CSSやJSから別ファイルを読み込んでいる場合、パスの問題が起きることがある。
- 外部のAssetでAsset Pipeline周りでハマったときは、Asset Pipelineを諦めて
public/
に配置したほうがいいかもしれない。