アセットとアセットパイプライン
アセット(Asset)とは、 HTML ファイルに付随するCSS, JavaScript, 画像ファイルといった直接のレスポンスでないファイル を指します。
アセットパイプライン(Asset Pipeline)とは、 複数のアセットファイルをコンパイルし、1つのファイルに統合する ための仕組みのこと。複数あるアセットファイルを1つに統合することでクライアント側のリクエストを減らし、より素早いレスポンスを返すことができるといったメリットがあります。
Sprockets (Rails でアセットパイプライン機能を提供する gem) について
Rails におけるアセットパイプラインという仕組みは、 Sprockets と呼ばれる gem によって実現しています。
Sprockets は以下の機能を提供しています。
- アセットファイルにアクセスするためのパスを管理する
- アセットのコンパイル
- アセットファイル同士の依存性の管理
1つずつ詳細を見ていきます。
アセットファイルにアクセスするためのパスを管理する
様々なディレクトリに置かれているアセットファイルのパスを管理し、 仮想的に1つのディレクトリにまとめて置いてあるようにクライアント側に見せる機能 です。
Sprockets の最も基本的な機能です。
例えば、普段開発を行う上で CSS ファイルは /assets/stylesheets
に、 JS ファイルは /assets/javascripts
という感じでファイルの種類ごとに分けてアセットパスを管理すると思います。これらの異なるディレクトリ下で管理されているファイル群を /assets
に仮想的にまとめることができ、/assets/main.css
というようにアセットファイルを参照することができるようになります。
Rails におけるアセットファイルの置き場所
rails new
をした時点であらかじめいくつかのアセットパスが用意されています。
app/assets
…アプリケーションの主要な機能に関わるアセットファイルlib/assets
…複数のアプリケーションで使われるような機能に関わるアセットファイルvendor/assets
…外部から取得したアセットファイル
CoC (設定より規約)に反しないためにも、適切な場所に適切なアセットファイルを置くように心がけましょう。
config/application.rb
でアセットパスの追加ができます。
アセットのコンパイル
JS や CSS のアセットファイルを コンパイル してくれます。元々 JS, CSS のファイルは何も起きません。
Rails ではデフォルトで CoffeeScript, Sass をコンパイルします。
例えば、 hello.js.coffee
といった拡張子が連なって記述されたようなファイルを Rails でみかけたことがあるとおもいます。 Sprockets では拡張子からファイルの種類を判別しコンパイルします。この場合は、 hello.js.coffee
は .coffee
から CoffeeScript ファイルと判別しコンパイルして、最終的に生 JS ファイルとして出力されます。
hello.js.coffee.erb
というアセットファイルは、 ERB → CoffeeScript という順番でコンパイルを行い JS ファイルとして出力されます(後ろの方から順番にコンパイルが走る)。
コンパイルする種類は増やすことができます。
TypeScript を追加したい場合は、以下の方法で可能なようです。
Ruby on RailsでTypeScriptを使ってみよう! | nanapi TechBlog
アセットファイル同士の依存性の管理
アセットファイル同士で起こる依存関係を『マニフェストファイル』と呼ばれるファイルで管理することができます。依存関係というのは、例えば hoge.js
で jQuery を使ってる…みたいなパターンです。hoge.js
は jQuery の機能を使っているので、 jQuery がないと動かない、つまり依存関係にあるということです。
rails new
した時に作られるマニフェストファイルは app/assets/javascripts/application.js
と app/assets/stylesheets/application.css
になります。
実際に中身を見てもらうとわかりますが、 //=require jquery
という記述があります。この記述がアセットファイル同士の依存性を管理している構文になります。コメント内で記述されているのはその他のツールで読み込んだ時に影響を与えないようにです。
require
の部分は ディレクティブ と呼ばれ、 require
以外にも何種類かディレクティブがあります。その一部を紹介します。
ディレクティブ | 説明 |
---|---|
require | 引数として与えられたファイルが自身よりも前に挿入される。2回目以降呼び出されても読み込まれない |
include | require と同じ動きをするが、2回目以降呼び出されると都度ファイルの内容が挿入される |
require_directory | 与えられたディレクトリ以下のファイルを、自身よりも前に挿入する。順番はアルファベット順(さらに大文字→小文字)になる |
require_tree | require=directory と同じ動きをするが、再帰的に読み込む |
読み込みはコードの 上から順番に 読み込まれます。
Rails で生成したマニフェストファイルには //=require_tree .
という記述があります。//=require_tree .
はカレントディレクトリ以下の全てのファイルを再帰的に読み込んでいきます。自作したアセットファイルが自動で読み込まれるのは //=require_tree .
がマニフェストファイル内にデフォルトで書いてあるからですね。
開発環境において、マニフェストファイルが正常に読み込まれているかデバッグするためのヘルパーメソッドがあります(stylesheet_link_tag, javascript_link_tag)。これを利用することでマニフェストファイルで読み込まれた順にアセットファイルが記述されていることを確認できます。
また、 config/environments/development.rb
内で config.assets.debug=true
と設定しなければなりません(デフォルトは true)。false の場合は本番環境と同じく1つのアセットファイルに纏められます。
アセットファイルのプリコンパイル
リクエストが来た時点で事前にコンパイルしたアセットファイルを渡すことができる機能です。
$ rake assets:precompile
というコマンドでアセットファイルのプリコンパイルを行なうことが出来ます*1。
プリコンパイルを行なうことで、リクエストのたびにコンパイルをする手間が省けより効率的にレスポンスを返すことができるようになります。
Rails のデフォルトでプリコンパイルはしてくれますが、デプロイ時にプリコンパイルした静的ファイルを一緒にデプロイするのを忘れずに。
フィンガープリントについて
Sprockets でコンパイルされたアセットファイルは ファイル名-MD5 値.rb
という形式のファイル名になります(例えば application.css
のフィンガープリントは application-5eece9848f909164a45045f6a24bc6b1.css
となる)。 MD5 値は元のファイルの内容から生成されたもので、これはファイルの更新があったかファイル名を参照するだけで済むというメリットがあります。
参考
書籍:パーフェクトRuby on Rails(p.94~104)