Aseets Pipeline についてまとめた

Aseets Pipeline ってなに?

  • Rails3.1から実装
  • Rails4から別gemに
  • 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の置き場所

Aseets Pipelineは、これらのディレクトリも勝手に見て読み込んでくれる

lib/assets や、vendor/assets にある画像や、fontファイルが読み込まれない!!

Rails4から lib/assetsvendor/assets にある、非css, js については、プリコンパイルの対象外になったらしい

Rails 4.0のアセットのプリコンパイルでは、vendor/assetsおよびlib/assetsにある非JS/CSSアセットを自動的にはコピーしなくなりました。Railsアプリケーションとエンジンの開発者は、これらのアセットを手動でapp/assetsに置き、config.assets.precompileを設定してください。

README.md とか不要なファイルをプリコンパイルしなくするのが目的らしい

対策

  1. 手動で、必要なファイルを app/assets にコピーする
  2. プリコンパイル対象の拡張子を追加する
#config/application.rb
config.assets.precompile += %w(*.png *.jpg *.jpeg *.gif)

参考

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

参考