Time to Read

5分

アセットパイプラインなどで使えるとして話題の Sprockets gem 、自分向けまとめ。確認しないで書いているところもあります。

アセットパイプラインを支える技術 – sprockets

Web assets 、具体的には主に CSS と JavaScript の圧縮/依存性の解決/各種ソースからの変換をサポートするための Rubygem 。 asset とは資産、財産の意。

執筆時点現在のバージョンは 2.0.3 。なお、 rack-sprockets gem は、 sprockets(<~ 1.0) 、要するに1.x系に依存するので利用をお勧めしない。

具体的には、

1
2
3
4
5
6
7
8
9
10
11
require 'sprockets'
map '/assets' do
  environment = Sprockets::Environment.new
  environment.append_path 'app/assets/javascripts'
  environment.append_path 'app/assets/stylesheets'
  run environment
end
 
map '/' do
  run YourRackApp
end

こういうコードが出現する。

Sprockets::Environment のインスタンスを、たとえば /assets, /resources のようなディレクトリの下にマッピングして用いることが多い。 Sprockets::Environment のインスタンス自体は Rack Middleware ではないRack アプリケーションそのもの

上記コードのように、 /assets 以下に配備し、ロードパス 'app/assets/javascripts','app/assets/stylesheets'append_path メソッドにより追加すると、実際にクライアントからアクセスする PATH_INFO と実ファイルの対応付けはたとえば以下のようになる。

PATH_INFO 実ファイルの場所
/assets/application.js app/assets/javascripts/application.js
/assets/models/project.js app/assets/javascripts/models/project.js.coffee
/assets/style.js app/assets/stylesheets/style.js

要するに、

  • ブラウザで /assets/application.js にアクセス
  • app/assets/javascripts/application.js を探す
  • app/assets/javascripts/application.js.coffee などを探す
  • app/assets/stylesheets/application.js などを探す
  • app/assets/stylesheets/application.js.sass などを探す
  • → Load Path にあるだけ繰り返す
  • → (public/assets/application.js などを探す)
  • どこにもなければ 404

ということ。

これだけではなく、CoffeeScript, Sacc/Scssといった各種エンジンのプロセス、ヘッダの適切な付与、キャッシュ、圧縮、//= require foo といったディレクティブの展開……、と言ったことも一手に引き受ける。

Rackベースのアプリケーション – 例えば Sinatra – で使う

以下のようなファイル構成とする。

$ tree .
.
├── Gemfile
├── Gemfile.lock
├── app/
│   ├── javascripts/
│   │   └── application.js.coffee
│   └── views/
│       └── index.haml
├── app.rb
├── config.ru
└── public/

Gemfile:

1
2
3
4
5
6
source :rubygems
gem 'sinatra'
gem 'haml'
gem 'coffee-script'
 
gem 'sprockets', '~> 2.0'

config.ru:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$LOAD_PATH << File.expand_path(".")
require 'rubygems'
require 'bundler'
Bundler.setup
Bundler.require
 
require 'app'
 
map '/assets' do
  environment = Sprockets::Environment.new
  environment.append_path 'app/javascripts'
  run environment
end
 
map '/' do
  run App
end
  • Sprockets::EnvironmentApp は別のアプリケーションであるため、別々にマウントする。

app.rb:

1
2
3
4
5
6
7
class App < Sinatra::Base
  set :public_folder, "public"
  set :views, "app/views"
  get "/" do
    haml :"index"
  end
end

index.haml:

1
2
3
4
5
6
7
8
!!! 5
%html
  %head
    %title Hello Sprockets
  %body
    %h1 Hello
    %p hi
    %script{:type => "text/javascript", :src => "assets/application.js"}
  • /assets/application.js を読み込ませにいく。これが、実ファイル app/javascripts/application.js.coffee と対応する

application.js.coffee:

1
document.write "Hi, coffee"
  • 関数は一緒。

rackup し、 http://localhost:9292 を見てみると、確かに

JavaScriptが実行されている。

application.js.coffee は以下のように展開されているというわけだ:

1
2
3
(function() {
  document.write("Hi, coffee");
}).call(this);

ここで、CoffeeScriptを以下のように変更、追加すれば、

application.js.coffee:

1
2
3
#= require countup
 
document.write "Hi, coffee"

同じフォルダに countup.js.coffee:

1
2
3
for i in [1..5]
  do (i) ->
    document.write "count" + i + "<br />"

こうなる。

忘れがちだが、 #= require などはファイルの先頭にあるディレクティブしか展開されない。

あとはじゃんじゃんバリバリと CoffeeScript を書いていこう。

さらに楽するために – Padrino::Sprockets

padrino-sprockets というシンプルな gem がある。簡単なクラスマクロを定義して、より楽にアセットパイプラインを利用できるようになる。ただし、素の Sinatra で利用する際には、 rubygems にホストされている 0.0.1 は不都合なので、 edge 版を使う。 0.0.2 からは何も考えず使えるといいですね……。

1
gem 'padrino-sprockets', :git => "https://github.com/nightsailer/padrino-sprockets.git", :require => "padrino/sprockets"

app.rb を以下のようにする。

1
2
3
4
5
6
7
8
9
10
class App < Sinatra::Base
  register Padrino::Sprockets
  sprockets
 
  set :public_folder, "public"
  set :views, "app/views"
  get "/" do
    haml :"index"
  end
end

そして、 padrino-sprockets は assets のロードパスとして、

#{root}/assets/javascripts
#{root}/assets/images
#{root}/assets/stylesheets

決め打ちするという一種の規約があるので、それにしたがう必要がある。この辺もう少し柔軟にしたければ、 pull request などをするとよいのでは。なお、 root は、 Sinatra であればデフォルトはそのアプリが定義されたファイルのあるディレクトリとなる。

具体的な作業としては、 app/javascripts にある CoffeeScript スクリプトを、 assets/javascripts と言うディレクトリを作ってその先にコピーしよう。

次に:

1
2
bundle update
bundle exec rackup

以上を実行すれば、同じような実行結果を見ることができるはずだ。

併せて

ただし、 1.0 系列の解説であることに注意。

10/28 もう一点追記。

「どうして」「どういうときに」高速になるかが分かると思います。