Railsのプロダクションモードでは、デフォルトで app/assetsフォルダ配下にあるCSSとJavaScriptを全てまとめて圧縮し、それぞれ application_xxxxx.css、application_xxxxx.jsファイルを作成する。実行時にはこの圧縮されたCSSとJSだけ読み込むので軽量でいいよ!という仕様のようである。この機能を実現しているのがアセットパイプラインというやつで、アセットパイプラインはマニフェストファイルに記載された内容を見て、どのファイルを対象とするか判断している。

マニフェストファイルとは
app/assets/stylesheets/application.css
app/assets/javascripts/application.js
の2つである。
そのファイルの中にインクルードすべきファイルが特殊なコメント記法で記載されている。
イメージとしては以下のような感じ。
[js mark=”4″]
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .
[/js]
これで、jqueryとjquery_ujsとturbolinksの JavaScriptを全Viewに組み込む。これはまぁ良しとしよう。問題は最後の1行である。このrequire_tree .
この命令は、app/assets/javascripts/ フォルダ配下にある全ファイルを対象とするよという意味を持つ。これはいくら何でも気持ち悪い。実際に試したことがないので、正確なところは把握していないが、プロジェクトで利用する自作のJavaScriptファイルを全部まとめちゃうということになるので、変数名がバッティングしたり、function名がバッティングしたり、ページロード時にやたらと多くのfunctionが実行されたりすることになるんじゃないだろうか??
CSSの方についても、同じような不具合が考えられる。自分で記述したCSSですら、別ページで利用するものと内容がバッティングしていないかなどいちいち構っていられないのに、プロジェクトの別のメンバーが書いたCSSともバッティングを避けてCSSを記述するなんて芸当はまず無理である。と、思うんだが、みなさんどうお考えですか? require_tree を生かしたまま実際に開発なんて出来るんでしょうか??
で、どうするのがベストか対策をあれこれ考えました。
パターン1
・ require_tree は取っ払う
・ コントローラー毎に固有のCSS、JSは Viewの html.erb内でインクルードする
・ CSS、JSの配置場所は assets配下とする
パターン2
・ require_tree は取っ払う
・ コントローラー毎に固有のCSS、JSは Viewの html.erb内でインクルードする
・ CSS、JSの配置場所は public配下とする
開発モード(development) では、どちらの対応でもOKなんですが、プロダクションモードにした際に、パターン1の方法では、CSS、JSがインクルードされないという現象が起こります。仕方がないので publicフォルダに直接配置するパターン2の方法を取りました。が、ここでも問題が発生します。
・publicフォルダはアセットパイプラインの対象外なので、SCSSでCSSを記述できなくなります。
・publicフォルダはアセットパイプラインの対象外なので、JavaScriptが圧縮されず、丸裸でクライアントに配布されることになります。
いまいちな対応ですね。でも、うまい解決法がわからなかったので、仕方なくこの方法で運用していました。で、やっぱり気持ち悪いので、気合を入れて、あれこれ調べた結果、ようやく望ましい解決方法が見つかりましたので、紹介してみます。
パターン3
・ require_tree は取っ払う
・ layoutファイルを調整し、コントローラー名と一致する CSS/JSをインクルードする
・ CSS、JSの配置場所は assets配下とする
・ コントローラー名と一致するCSS/JSには直接、CSSとJSを記載するのではなく、マニフェストファイルとする
・ production.rbを調整し、アセットパイプラインの対象ファイルを拡張する
例)コントローラー名 aaas の場合。
ファイル名: application.js
このファイルにはプロジェクト全体で共通利用するJavaScriptを記述する。
[js]
//= require jquery
//= require jquery_ujs
//= require turbolinks
[/js]
ファイル名: application.css
このファイルにはプロジェクト全体で共通利用するCSSを記述する。
[css]
/*
*= require_self
*= require font-awesome
*= require_tree ./pepper-grinder
*= require ./ui.jqgrid
*/
[/css]
ファイル名: layouts/application.html.erb
レイアウトファイルには、application に加えて、コントローラー名に合致する CSS/JSをインクルードする。
[html mark=”6,8″]
Log Analyzer
<%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %>
<%= stylesheet_link_tag controller.controller_name , media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= javascript_include_tag controller.controller_name , "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
[/html]
ファイル名: app/assets/javascripts/aaas.js
コントローラー名に合致するJSファイルには直接JavaScriptは記載せず、このコントローラーで利用したい汎用的なJSと、このコントローラー固有で利用するJSのファイル名を記載する。
[js]
//= require jquery-ui-1.10.3.custom.min
//= require grid.locale-ja
//= require aaas_main
[/js]
ファイル名: app/assets/stylesheets/aaas.css
コントローラー名に合致するCSSファイルには直接CSSは記載せず、このコントローラーで利用したい汎用的なCSSと、このコントローラー固有で利用するCSSのファイル名を記載する。
[css]
/*
*= require_self
*= require aaas_main
*/
[/css]
ファイル名: config/environments/production.rb
アセットパイプライン対象としたいマニュフェストファイルを追記する。今回のケースでは コントローラー aaas に対応する2ファイルを追記したが、必要に応じて、どんどん追記していけばOKでしょう。
[ruby]
#コメントアウト
#config.serve_static_assets = false
config.assets.precompile += %w( aaas.js )
config.assets.precompile += %w( aaas.css )
[/ruby]
動作確認
実際にアセットをコンパイルして、プロダクションモードで動作確認してみてください。
[bash]
$ rake assets:precompile RAILS_ENV=production
[/bash]
[bash]
$ rails s -e production
[/bash]
application-xxxxx.js、application-xxxxx.cssに加えて、
コントローラー名-xxxx.js、コントローラー名-xxxx.css のみがインクルードされる形でページがロードされていたらメデタシメデタシです。
Leave a comment