プログラミング学習記録

主にRuby on Railsを使ったプログラミングを学んでいます。

アセットパイプラインとマニフェストファイル

アセットパイプラインとは

ブラウザが認識できる言語は、HTML,CSS,JavaScriptの三種類。
しかし、Railsでアプリケーションをつくる場合、当然ながらERB(埋め込みRuby)を使用している。画像などのリソースもブラウザで表示させる場合がほとんどだ。
つまりそのままでは、ブラウザが認識・解釈し表示させることができない。
そこでRailsに限らず他の言語で作成されたWebアプリでも、ブラウザが認識できる言語へ変換する必要がある。
その仕組みこそがアセットパイプラインというフレームワーク

アセットパイプラインは画像、CSSJavaScriptといったアセットファイルを連結/圧縮することでRailsアプリを高速化します。また、より高級な言語で書かれたCSSJavaScriptコンパイルする機能も備えています。

引用元

【Rails】アセットパイプライン(Sprockets)の基本情報と実装方法 - AUTOVICE

Railsではsprockets-rails gem(SprocketsをRails用にカスタマイズしたもの)によって実装され、デフォルトで有効になっている。
Rails 6からはWebpackerが標準となっているが、Sprocketsも使われている。

アセットパイプラインの機能・処理

1 高級言語コンパイル
2 アセットの連結
3 アセットの最小化
4 ダイジェスト(フィンガープリント)の付与

という順で処理される

高級言語コンパイル

より高級な言語で記述されたコードはプリコンパイルされ、実際のアセットになる。(ブラウザが認識できるJavaScript,CSSファイルとして扱えるようにする。)
デフォルトでサポートされている言語は、CSSに代わるSass、JavaScriptに代わるCoffeeScriptCSS/JavaScriptに代わるERB。

アセットの連結

複数のJavaScript,CSSファイルをそれぞれ一つのファイルに連結することで、ブラウザがWebページをレンダリングするためのリクエスト数を減らすことができる。Webブラウザが同時に処理できるリクエスト数には限りがあるため、同時リクエスト数を減らすことができればその分読み込みが高速になる。
SprocketsはすべてのJavaScriptファイルを1つのマスター.jsファイルに連結し、すべてのCSSファイルを1つのマスター.cssファイルに連結する。

アセットの最小化

スペース、改行、コメントを削除してファイルを最小化(一種の圧縮)し、通信量を節約する。
Railsではsass-rails gemが自動的にGemfileに追加される。Sprocketsはアセット圧縮の際にこのgemを使用する。

ダイジェスト(フィンガープリント)の付与

コードの内容からハッシュ値を算出してファイル名の末尾に付与する。
このようにすると、コードが変更されればファイル名が変更されるので、ブラウザのキャッシュの影響で修正が反映されないという問題を防ぐことができる。


※アセットパイプラインはdevelopment環境とproduct環境で挙動が変わる。
development環境では、高級言語コンパイル、ダイジェストの付与は逐次自動で行われる。処理速度は良くないが、開発者が自らコンパイルする必要はない。
アセットの連結と最小化は行われない。連結が行われず、ファイル数分のlink,scriptタグが生成されるのでデバッグしやすい。
production環境では全ての処理が行われる。

アセットの読み込み

RailsではCSSを読み込むにはstylsheet_link_tag、JavaScriptを読み込むにはjavascript_include_tagというヘルパーメソッドを使う。
共通のビューである、app/views/layouts/application.html.erbの<head>~</head>内で読み込んでいる。
デフォルトでここから読み込んでいるのはapplication.css、application.js。

<%= stylesheet_link_tag "application", media: "all" %>
<%= javascript_include_tag "application" %>

このapplication.css、application.jsとは、アセットパイプラインによって連結された結果のファイルを指す。

マニフェストファイル

ファイルをどう連結して出力するかは、app/assets配下のapplication.cssやapplication.jsといったマニフェストファイルに記述する。
どのファイルを読み込むのかを取りまとめたファイルを、マニフェストファイルと呼ぶ。

マニフェストファイルには ディレクティブ (directive: 命令、指示) を含めます。ディレクティブを使用して必要なファイルを指定し、それに基いて最終的に単一のCSSJavaScriptファイルがビルドされます。Sprocketsはディレクティブで指定されたファイルを読み込み、必要に応じて処理を行い、連結して単一のファイルを生成し、圧縮します。

引用元

アセットパイプライン - Railsガイド

app/assets/javascripts/application.js

// ...
//= require rails-ujs
//= require turbolinks
//= require_tree .

デフォルトでこのような記述がある。
JavaScriptマニフェストファイルでは//=で始まる行は、Sprocketの独自仕様でアセットパイプラインに指示(ディレクティブ)を与えるためのもの。
require_tree .は「同階層に存在している全てのファイルを読み込む」という意味。

app/assets/stylesheets/application.css

/* ...
*= require_self
*= require_tree .
*/

require_selfは「自分自身を読み込む」という意味。

ここで注意が必要なのが読み込む順番
基本的に上から下へ順に読み込むのだが、require_treeディレクティブで読み込まれるファイルの読み込み順序は指定できない。そのため、特定の読み込み順に依存しないようにする必要がある。順序を間違えるとエラーの原因となることがある。通常はrequire_tree .は一番下に記述しておくのがいい。

CSSとSCSS(Sass)

まずは用語の確認から
CSS
HTMLで作られた文書構造にデザインを加えてWebページの見栄えを整える言語。「Cascading Style Sheets」 の頭文字をとったものであり、スタイルシートとも呼ばれる。


Sass
Sass(サス)はCSSを効率的に書くことができるメタ言語CSSに対して機能を拡張する。Syntactically Awesome StyleSheetsの略。
CSSではHTMLのクラスがネストになっている箇所でも、入れ子の構造で記述できないため、分けて書くしかないので直感的に関係の把握がしづらい。
Sassだとコードを入れ子で記述できるので書く量を減らしたり、クラス名がかぶってしまい、ほかにもスタイルが適用されてしまうということを防げる。また、Sassでは変数を定義して使うことができるので、文字色や文字サイズが変わっても、全部の箇所を変更する手間が省ける。 SCSS記法とSASS記法がある。
SASS記法はインデント制御で記述する(記述量を必要最小限にできる)。SCSS記法ではCSSと同じように{}を使い記述し、普通のCSSをそのまま記述しても動くのが利点。
SassはRailsでBootstrapを導入するときにも必要。


なぜここでSassについて言及するかというと、Sassはそのままではブラウザが解釈してくれない、つまりCSSコンパイルさせる必要があるからだ。
マニフェストファイルの書き方に注意が必要

Sassファイルを複数使用しているのであれば、Sprocketsディレクティブで読み込まずにSass @importルールを使用する必要があります。このような場合にSprocketsディレクティブを使用してしまうと、Sassファイルが自分自身のスコープに置かれるため、その中で定義されている変数やミックスインが他のSassから利用できなくなってしまいます。

引用元 

アセットパイプライン - Railsガイド

RailsでSCSSを導入する

Railsはデフォルトでsass-railsというgemが導入されているで、ファイル名を変更し、追加したCSSファイルが全て読み込まれるよう記述していく。
デフォルトではapp/assets/stylesheets/application.cssマニフェストファイルになっているので、これを削除して新しくapp/assets/stylesheets/application.scssを作る。
そこに読み込むファイルを@importを使って個別に読み込むファイルを記述する。 拡張子は省略。

@import "top";
@import "task";
@import "bootstrap-sprockets";
@import "bootstrap";

上記はあくまで例。
require_treeを使わないのは、ここでも読み込む順番の問題があるから。@importを使って必要なファイルのみ読み込む方がファイル管理を安全にできる。

参考

アセットパイプライン - Railsガイド

www.amazon.co.jp

アセットパイプラインとマニフェストファイルについて - プログラミングの備忘録

【Rails】アセットパイプライン(Sprockets)の基本情報と実装方法 - AUTOVICE

アセットパイプラインの概要を理解する - Wataruの技術備忘録

CSSとSCSSの違い - プログラミングの備忘録

SassとSASSとSCSSの違いについて | UX MILK

Sassとは? Sassの基本について | UX MILK

初学者(私!)にとっては「現場で使える Ruby on Rails 5速習実践ガイド」のChapter6のアセットパイプラインの説明がわかりやすかったです。
Railsガイド「ん?」→現場RailsのChapter6-8 アセットパイプライン参照→その後またRailsガイド でやっと腑に落ちました。