Aseets Pipeline ってなに?
- Rails3.1から実装
- Rails4から別gemに
- sprockets-rails
- sprockets(および、sprockets-rails)を使って、以下の処理を行う
- CoffeeScriptや、SCSS等の高級言語を変換
- マニフェスト(後述)に従って、js, css を1ファイルにまとめる
- ファイル名の末尾にHash値を付ける(Fingerprinting)
- ブラウザキャッシュの問題を回避
- ここまでの一連の処理をプリコンパイルと呼ぶ
#javascript_include_tag
や#stylesheet_link_tag
が呼ばれた時に、上記の処理で生成されたファイルをリンクする
具体的にどうすれば良いの?
何もしなくても、rails new
した時にお膳立てはできてる
# app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>Dictionary</title> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> <%= csrf_meta_tags %> </head> <body>
これをHTMLにすると...
<link rel="stylesheet" media="all" href="/stylesheets/application-908e25f4bf641868d8683022a5b62f54.css" data-turbolinks-track="true" /> <script src="/javascripts/application-908e25f4bf641868d8683022a5b62f54.js" data-turbolinks-track="true"></script>
こんなかんじになる(production環境の場合)
- 開発環境ではファイルの結合は行われず、バラバラのcss,js が貼られる
Aseetsのディレクトリ構成
application.css
と、application.js
が置かれているのが、app/aseets
app/aseets ├── images ├── javascripts │ └── application.js └── stylesheets └── application.css
application.js の中身を見てみる
// This is a manifest file that'll be compiled into application.js, which will include all the files // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the // compiled file. // // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // //= require jquery //= require jquery_ujs //= require turbolinks //= require_tree .
こんな感じでjsは何も書いてない
//=
で書かれているのが、sprocketsのマニフェスト
マニフェストの書き方
require
: gemにあるAseetsを読むこむrequire_tree ${path}
: path にあるAseetsを再帰的に読み込む
なので、application.js
は、
- jQuery関係のgemのjs
- taurbolinks関係のjs
app/assets/javascripts/
以下のjs を読み込んでいる
だいたいそんな感じ
Asset を追加したい!!
例えば JavaScript なら app/assets/javascripts/
に、js ファイルか、coffeeファイルを置く
- 後は、Aseets Pipeline がよしなにやってくれる
アプリケーション特有じゃないAssetの置き場所
lib/assets
: 共有のAssetvendor/assets
: JavaScriptプラグインやCSSフレームワーク等外部から提供されたAsset
Aseets Pipelineは、これらのディレクトリも勝手に見て読み込んでくれる
lib/assets や、vendor/assets にある画像や、fontファイルが読み込まれない!!
Rails4から lib/assets
や vendor/assets
にある、非css, js については、プリコンパイルの対象外になったらしい
Rails 4.0のアセットのプリコンパイルでは、vendor/assetsおよびlib/assetsにある非JS/CSSアセットを自動的にはコピーしなくなりました。Railsアプリケーションとエンジンの開発者は、これらのアセットを手動でapp/assetsに置き、config.assets.precompileを設定してください。
README.md とか不要なファイルをプリコンパイルしなくするのが目的らしい
対策
- 手動で、必要なファイルを
app/assets
にコピーする - プリコンパイル対象の拡張子を追加する
#config/application.rb config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)
参考
- Rails4でGemの資産がAssets Precomplieに含まれないときは · THINKING MEGANE
- Only compile non-js/css under app/assets by default by josh · Pull Request #7968 · rails/rails
Asset内でerbを使いたい
拡張子をerbにすれば、普通に使えます。スゴイ!!
/app/assets/anything/greeting.txt.erb hello world <%= 1+1%>
ブラウザで、aseets/greeting.txt
にアクセスすると以下のように表示される
hello world 2
もし、SCSSでerbを使いたければ、hoge.sess.erb
とかすれば、ERB, SCSS の順に Aseets Pipelineが処理してくれる
- Pipelineっぽい!!
必要なgemを用意すれば、hamlとか好きな拡張子を追加できるはず(未確認)
画像の話
画像もハッシュ値がつくから、path直書きだと正しく表示されないので、
-erbなら #asset_path
を呼ぶか、SCSSならimage-url
を経由する必要がある
<img src="<%= asset_path "hoge.png" %>" /> <div style="background-image:url(<%= asset_path "hoge.png" %>)" />
background-image: image-url("hoge.png");
Railsのアップグレード等で対応が面倒なら、画像をpublic/images
に置く方法も無くはない
参考
production環境の話
- 開発環境では、アクセスがあった時に必要なAssetを生成している
- 本番環境では、事前にプリコンパイルを行い、Aseetを予め生成しておく必要がある
プリコンパイルの実行方法
$ rake assets:precompile RAILS_ENV=production
これで、public/assets
直下にAseetが生成される
- 普通は、Capistrano等のデプロイレシピに書いてデプロイ時に生成する
- リポジトリには含めない
assetだけ別サーバにおいといて処理を分散する手法(asset_sync)もあるらしい
古いファイルの削除
プリコンパイルするだけだと以前のファイルは残り続ける
$ rake assets:clean
その他メモ
コントローラーやアクション毎に異なるjsやcssを呼び出したい
Rails way 的にはやってほしくない様子
一応やりかたは無くはない →Rails - コントローラ・アクションごとに固有のasset (CSS, JS) を読み込ませる - Qiita