monoの開発ブログ

SinatraアプリでもAsset Pipelineを使う

Rails 3.1で追加されたAsset Pipelineという超便利な機能をSinatraでも使ってみます。

# Railsを使ったことはないですが。

Asset Pipelineとは

Asset Pipelineとは何か、ざっくり言うとJavaScript/CSSの依存関係を解決したり、複数ファイルを1つにまとめてリクエストを減らしたり、ついでに圧縮したりできる機能です。詳しくは以下のページが参考になると思います。

Asset Pipelineはsprocketsというgemを使って実現されており、Rails以外のRackアプリでも利用することができます。この記事では、Sinatraアプリでsprocketsを使ってみた例を紹介します。

利用方法

Sinatraからsprocketsを利用したサンプルを用意しました。

bundle installしてrackupすれば動作すると思います。が、私はpowでしか試していません。

$ git clone https://github.com/mono0x/sinatra-easy-template.git
$ cd sinatra-easy-template
$ bundle install
$ rackup

Gemfile

必要なのはsprocketsだけですが、sprockets-helpersも入れておくと便利です。yui-compressorはコードを圧縮する場合に必要です。

gem 'sprockets'
gem 'sprockets-helpers'
gem 'yui-compressor', require: 'yui/compressor'

Sass(とCompass)を利用する場合は以下のgemを追加します。

gem 'sass'
gem 'compass'
gem 'sprockets-sass'

CoffeeScriptを利用する場合は以下のgemを追加します。

gem 'coffee-script'

application.rb

sprocketsに関する設定を行います。

set :sprockets, Sprockets::Environment.new
configure do
  Sprockets::Helpers.configure do |config|
    config.environment = sprockets
    config.prefix = '/assets'

digestをtrueにすると、生成されるファイル名にファイルのハッシュ値が含まれるようになります。ファイルの中身が変わるたびにファイル名が変わるようになるので、ブラウザのキャッシュが読み込まれてしまってうまく表示できないトラブルを避けることができます。

    config.digest = true
  end

ファイルを置く場所のパスを指定します。

  sprockets.append_path 'assets/javascripts'
  sprockets.append_path 'assets/stylesheets'

js_compressorとcss_compressorにコードの圧縮を行うオブジェクトを指定できます。ここでは、production環境でのみYUI Compressorを利用するよう指定しています。

  if production?
    sprockets.js_compressor = YUI::JavaScriptCompressor.new(munge: true, optimize: true)
    sprockets.css_compressor = YUI::CssCompressor.new
  end
end

sprockets-helpersのメソッドを利用できるようにしておきます。

helpers Sprockets::Helpers

config.ru

/(root)はApplicationで、/assets以下はsprocketsで処理するようにします。

map '/assets' do
  run Application.sprockets
end
map '/' do
  run Application
end

assets/stylesheets/application.css.scss

application.rbで指定したassets/stylesheetsディレクトリにCSSを配置します。.css.scssのように.cssの後ろにscss/sass/lessなどをつけておくと、それぞれの言語で記述したものとして認識されます。

sprocketsでは、ファイルの先頭に特別なディレクティブを記述すると、それを認識して動作します。以下の例では、requireディレクティブでlayout.css(.scss)を結合したあと、require_treeディレクティブでassets/stylesheets以下のすべてのスタイルシートを結合して1つのファイルにまとめています。requireディレクティブは結合する順序が重要な場合にのみ利用するもので、基本的にはrequire_treeディレクティブでごっそり結合しておけばよいと思います。なお、結合は一度のみしか行われないため、最後のrequire_treeディレクティブでは先にrequireしたlayoutは結合されません。

//= require layout
//= require_tree .

views/layout.haml

stylesheet_pathメソッドにcssの名前を渡すことでパスを取得できます。cssがどんな形式で書かれているかを気にする必要はなく、名前のみを指定すればOKです。

%link{rel: 'stylesheet', type: 'text/css', href: stylesheet_path('application')}

実行結果

/index.html

ハッシュ値を含んだファイル名が生成されていることがわかります。

<link href="/assets/application-92ad097f0f535b5601a1b8a69fe89ffc.css" rel="stylesheet" type="text/css">ylesheet" type="text/css">

/assets/application-92ad097f0f535b5601a1b8a69fe89ffc.css

YUI Compressorで圧縮されたCSSが生成されています。

section,article,aside,header,footer,nav{display:block}#container{min-width:950px;width:80%;margin:0 auto;overflow:hidden;*zoom:1}#container>header{display:inline;float:left;overflow:hidden;width:99.974%;margin-right:1.042%}#container>section{display:inline;float:left;overflow:hidden;width:66.302%;margin-right:1.042%}#container>aside{display:inline;float:left;overflow:hidden;width:32.63%;margin-right:0}

さらに、以下のようなHTTPヘッダが付加されてキャッシュされるようになりました。

Cache-Control:public, max-age=3153600

つかってみた感想など

デフォルトでAsset Pipelineが使えるRailsと比べると準備が若干面倒ですが、設定さえしてしまえば便利だと感じました。

# ただ、Sinatraにいろいろ自分で足して使っていると、いい加減Railsを使った方がいいんじゃないかという気がしないでもないです。Padrinoなんてのもあるみたいですけど、それならメジャーなRailsにしたほうが無難かなと思いますし……。