RailsプロジェクトのJavaScriptをWebpackerで書いていたのですが、Sprocketsの方がいい場面、というのが出てきました。
プロジェクトの状況
もともとRails 4から続くプロジェクトで、JavaScriptもCSSもSprocketsに載せていました。そして、JavaScriptのES6対応や依存関係管理の都合もあって、JavaScriptのほうはWebpackerに載せ替えていきました。一方で、CSSはSCSSで必要十分だったので、Sprockets管理のままで運用を続けています。
別プロセスのコスト
その中で、Rails側から値を取ってくる必要のあるimage_path
(参考)や、Railsにある定数をJavaScriptにも持ち込みたいような場合、.js.erb
としてERBでJavaScriptを生成する、という方法があります。
もちろん、Webpackerでも.js.erb
を使う方法があって、その名もrails-erb-loader
(GitHub)というローダーを使えば、読み込むこと自体は可能です。
ただ、rails-erb-loader
は、1ファイルの処理につき1つRailsのプロセスを立ち上げてしまうために、.js.erb
ファイルが増えれば加速度的に処理時間がかかるようになってしまいます。
Rubyの道はRuby
ここで、Sprocketsに視点を戻してみましょう。もともとSprocketsはRubyの枠内で処理を行うので、ERBが来ても別プロセスを立てるようなコストは発生せず、通常のファイルと大差ないプロセスで処理ができます。
ということで、もともとCSSのためにSprocketsの運用を続けていたこともあるので、ERB処理の必要なものだけSprocketsで書いて、Webpackerからはそれを参照するように書くのがいいのではないか、と思い始めてきました。
// Sprocketsで書くERB
<%
imgs = {}
Dir.chdir("#{Rails.root}/app/assets/images/") do
imgs = Dir["**/*"].inject({}) do |h,f|
h.merge!(f => image_path(f)) unless Dir.exist? f
h
end
end
%>
window.fromRuby = {};
window.fromRuby.imagePath = function(name){
return <%= imgs.to_json %>[name];
}
// Webpacker側に書くJavaScript
// 依存性の管理が混乱するので、直接fromRubyを呼ぶ箇所は、減らした方がいい
// このファイルをimportして使う
const imagePath = window.fromRuby.imagePath;
export default imagePath;