読者です 読者をやめる 読者になる 読者になる

おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

sprockets の README 意訳

rails

Rails3.1 から同梱されるようになった sprockets の README の意訳です。
sstephenson/sprockets - GitHub

はじめに

Sprockets は assets ファイルのコンパイルと配信を行うための Ruby のライブラリです。JavaScriptCSS ファイルの依存関係を宣言でき、さらにプリプロセッサを使うことで CoffeeScript, Sass, SCSS, LESS 等の言語を assets の記述に利用出来ます。

インストール

いわゆる普通のやり方でインストール可能です。

gem install sprockets

Gemfileなら

gem 'sprockets', '~> 2.0'

Sprockets Environment

assets ファイルにアクセスして配信するなら、 Sprockets::Environment クラスのインスタンスが必要です。Rails 3.1 以降なら、YourApp::Application.assets でSprockets::Environment のインスタンスにアクセスできます。Rack ベースのアプリなら、config.ru の中でインスタンスを作りましょう。

Sprockets::Environment は assets ファイルの取得と配信、ロードパスの操作、プロセッサの登録用のメソッドを持っています。それはまた URL にマウントすることが出来て静的ファイルを配信する Rack アプリでもあります。

ロードパス

ここで言うロードパスとは、Sprockets が assets ファイルを探すときに使うディレクトリの順序づけられたリストのことです。

最も単純なケースでは、Sprockets のロードパスはアプリの assets ファイルを含む単一のディレクトリから構成されるでしょう。Sprockets の environment がマウントされたら、environment はこのディレクトリの assets をまるで public root にある静的ファイルのように配信します。

ロードパスによって複数ディレクトリ内のソースファイルを管理して、これらのディレクトリを単一の仮想ファイルシステムにすることができます。さらにアプリの外のディレクトリを指定することもできます。つまりこれは、Ruby のライブラリに同梱されている JavaScript, CSS, 画像を簡単にアプリにインポートすることが出来ると言うことを意味します。

ロードパスの操作方法

ロードパスにディレクトリを加えたい場合、 append_path と prepend_path メソッドが使えます。ロードパス内では最初のパスが後のパスよりも優先されます。通常、パスを追加するときにはデフォルトのパスの後に追加して、既存の assets を上書きしたいときのみデフォルトのパスの前に追加するようなやり方が一般的です。

environment = Sprockets::Environment.new
environment.append_path 'app/assets/javascripts'
environment.append_path 'lib/assets/javascripts'
environment.append_path 'vendor/assets/jquery'

assets へのアクセス

environment にロードパスをセットしたら、Rackサーバのように environment をマウントして、HTTP経由で assets をリクエストすることが出来るようになります。また、アプリの中からassetsにアクセスすることも出来ます。

論理パス

Sprockets 中の assets は常に論理パスで参照されます。論理パスとは、ロードパス中に含まれるディレクトリからの相対パスのことを指します。例えば、ロードパスに app/assets/javascripts を含めていたとすると、下記のようになります。

asset 論理パス
app/assets/javascripts/application.js application.js
app/assets/javascripts/models/project.js models/project.js

このような方法でロードパス中の全てのディレクトリがマージされて、論理パス用の仮想的なファイルシステムが作られます。

HTTP越しにassetsを配信する

environment をマウントすると、マウントポイント配下の論理パス越しに全ての assets にアクセスすることが出来ます。例えば、environment を /assets にマウントして /assets/application.js にリクエストを飛ばすと、Sprockets はロードパス中の application.js を探して配信します。

Rails 3.1 以降では、Sprockets の environment は自動で /assets にマウントされます。もし(Rails以外の) Rack アプリで Sprockets を使うなら、手動で environment をマウントする必要があります。config.ru 中で、map メソッドを使うのがよいでしょう。

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

assets にアクセスするには

find_asset メソッド([]がエイリアス)を使うことで、Sprocket の environment から asset を受け取ることが出来ます。論理パスを引数として渡すと、Sprockets::BundledAsset インスタンスを返します。

environment['application.js']
# => #<Sprockets::BundledAsset ...>
Sprockets::BundledAsset のインスタンスメソッド
to_s
asset の内容を返します
length
asset のバイト数を返します
mtime
asset の最終修正日時を返します
pathname
asset のフルパスを返します。

エンジンを使う

asset のソースは SCSS や CoffeeScript 等の他の言語で書くことが出来ます。その場合 Sprockets によって自動で CSSJavaScriptコンパイルされます。これらの言語用のコンパイラはエンジンと呼ばれます。

使用されるエンジンは asset のファイル名に追加された拡張子で判断されます。例えば、SCSS で書かれた CSS ファイルは例えば layout.css.scss のようになるでしょう。一方 CoffeeScript で書かれた JavaScript ファイルは dialog.js.coffee のようになるでしょう。

Sass と SCSS を使う

Sass は CSS にネストや変数やmixinやセレクタの継承を加えた言語です。もし sass gem が使えるなら、CSS assets を 書くのに Sass が使えます。

Sprockets は Sass と SCSS 両方をサポートしています。Sass を使いたい場合は . css.sass、SCSS を使いたい場合は .css.scss のように拡張子を指定します。

LESS を使う

LESS コンパイラJavaScript で書かれています。less gem は Ruby で書かれた V8 JavaScript ランタイムである therubyracer に依存しています。LESS を使いたい場合は .css.less のように拡張子を指定します。

CoffeeScript を使う

coffee-script gem が使えるなら、CoffeeScript を使うことが出来ます。CoffeeScript コンパイラJavaScript で書かれているため、ExecJS がサポートしているランタイムが必要です。CoffeeScript が使いたい場合は .js.coffee のように拡張子を指定します。

EJS と Eco で JavaScript テンプレートを扱う

Sprockets は クライアントサイドでのレンダリングを扱うJavaScript テンプレートをサポートしています。JavaScript テンプレートは特別な拡張子 .jst をもち、JavaScript の関数にコンパイルされます。

JavaScript テンプレートをロードしたとき、グローバルの JST オブジェクトを通して、JavaScript テンプレートの関数にアクセスすることが出来ます。テンプレートの関数は、文字列でテンプレートを描画するためのものです。戻り値となる文字列は DOM に挿入できます。

<!-- templates/hello.jst.ejs --><div>Hello, <span><%= name %></span>!</div>

// application.js
//= require templates/hello
$("#hello").html(JST["templates/hello"]({ name: "Sam" }));

Sprockets は二つの JavaScript テンプレート言語をサポートしています。JavaScript に組み込むための EJSCoffeeScript に組み込むための Eco です。両方の言語とも<% … %> でテンプレート内に埋め込む事が出来ます。

もし ejs gem が使える状態なら、EJS テンプレートを使うことが出来ます。EJS を使いたい場合は.jst.ejsのように拡張子を指定します。
eco gem が使える状態なら、Eco テンプレートを使うことが出来ます。Eco を使いたい場合は .jst.eco のように拡張子を指定します。eco gem は CoffeeScript コンパイラに依存しているので、前述の CoffeeScript エンジンを使う際の注意点と同じ内容が適用されます。

ERB で Ruby を実行する

Sprockets は ERB エンジンを提供しています。.erb を CSS または JavaScript asset のファイル名の後に付けると、ERBエンジンを有効に出来ます。

注意:Sprockets が複数のエンジンを使う場合、拡張子の右側から順番に適用していきます。ERB を処理してから CoffeeScriptコンパイルしたい場合は .js.coffee.erb のように拡張子を指定します。

assets は Sprockets::Context インスタンスのコンテキストで評価されます。

このあたりちょっと省略してます

文字列埋め込みのシンタックス

asset 中で Rubyにアクセスしたいけれど <%= %> が使えないときには、.str 拡張子を使うと #{ … } が使えます。

依存関係を解決する

各ソースファイルの頭で特別なコメント風シンタックスを使うことにより、asset ファイルを順序づけて結合した *asset bundles* を作ることが出来ます。

Sprockets は assets ファイル中のディレクティブと呼ばれるコメントを解析し、依存関係のグラフを作成します。もし依存関係のある asset ファイルをリクエストした場合、ファイルの頭で指定されている依存ファイルが include されます。

ディレクティブプロセッサ

Sprockets は CSSJavaScript ソースファイルでディレクティブプロセッサを走らせます。ディレクティブプロセッサはファイル頭の "=" で始まるコメントを見ます。"=" の後の最初の単語がディレクティブ名になり、続く文字列は引数として取り扱われます。Sprockets はコードが始まったらディレクティブを探すことをやめます。

サポートしているコメントの種類

/* 複数行のコメント形式 (CSS, SCSS, JavaScript) 
*= require foo
 */

// 一行コメント形式 (SCSS, JavaScript)
//= require foo

# 一行コメント形式 (CoffeeScript)
#= require foo

Sprockets のディレクティブ

下記のディレクティブが使えます。それぞれパスを引数としてとります。指定できるパスは論理パスまたは相対パスです。相対パスは "./" で始まり、現在のファイルの場所からの位置を指定します。

require ディレクティブ
require path

path に指定されたファイルを挿入します。同じファイルが複数回 require されても有効なのは一回だけです。

include ディレクティブ
include path

require と似た働きをしますが、複数回 include されたときに、複数回内容が挿入される部分が異なります。

require_directory ディレクティブ
require_directory path

ディレクトリ中のファイルをアルファベット順で全部 require します

require_tree ディレクティブ
require_tree path 

require_directory と似た働きをしますが、path から再帰的にディレクトリを辿って require していく部分が異なります。

require_self ディレクティブ
require_self

require_self で指定した後の require や include の前に現在のファイルを挿入するように Sprockets に伝えます。

depend_on ディレクティブ
depend_on path

bundle 中に含まない path に依存していることを宣言します。依存しているファイルが変更されたときにキャッシュを expire したいときに便利です。