他ライブラリとの組み合わせ

Sprockets, Webpacker後の世界

Sprockets, Webpacker時代

下記の歴史については私もよくわからないところがありますので、参考程度と考えてください

Ruby on RailsはGoogle V8エンジンやnode.jsよりも古いフルスタックフレームワークで、昔から積極的にJavaScriptやCSSのビルド技術を取り入れていました。

特にSprocketsは歴史が古く、少なくとも2011にリリースされたRails 3.1にRails Guideがありました。この頃はCSS, SASS, JavaScript, CoffeeScriptのビルドに使用されていました。Webpackはまだ登場していませんでしたので、CSSやJavaScriptの中にERBのタグを入れるやり方は当時は必要でした。

例えば下記のような書き方は(今では非常に気持ち悪がられますが)よく見かけました。

css
.class { background-image: url(<%= asset_path 'image.png' %>) }
js
$('#logo').attr({
  src: "<%= asset_path('logo.png') %>"
});

その後、アプリっぽいJavaScript (React等)の処理はSprocketsからWebpackに委譲され、SprocketsとWebpackを繋げるのがWebpackerが使われるようになりました。WebpackerはCSSや画像のビルド等にも使用できました。

Rails 7以降のRailsのJavaScript

2021年のRails 7以降は、Webpackerではない新しいJavaScriptのビルド方法が採用されました。大きく3種類用意されています

  1. Import mapsを使用したノービルド JavaScript: JavaScriptを一切ビルドしないアプローチです。Sprocketsの誕生以前は効率が悪かった伝統的なアプローチが、HTTP2, ES6, import mapsが登場したおかげで再び現実的になったのです。それを最大限に活かしたのがImport mapsを使用したノービルド JavaScriptです
  2. JavaScriptのエコシステムを活用したビルドツール: React SPAのようにどうしてもビルドが必要な場合のために、無理にRailsベースのWebpackerを使うのではなく、JavaScriptのエコシステムのツールを活用した方法としてjsbundling-gemが用意されています。公式のgemです。これはBun, esbuild, rollup.js, Webpackのうちの好きなものを使ってJavaScriptをビルドするものです。特に強い希望がなければ推奨はesbuildです。Basecamp 3はWebpackerからjsbundling-gem + esbuildに移行されたようです。また本サイトはReactを使用していますので、jsbundling-gem + esbuildでJavaScriptをビルドしています
  3. RailsをAPIモードで使用する: フロントエンドとバックエンドのリポジトリを完全に分離しているのならRailsをAPIモードで使用して、Rails側では一切JavaScriptに関与しないというアプローチもあります

Rails 7以降のCSS

CSSについてはSASS等を使わずに生のCSSを使う方法がデフォルトとして用意されています。最新のCSSはネスト化された定義やCSS変数など、従来はSASSがなければ実現できなかった機能が最初から用意されています。以前に比べて、大きいプロジェクトであっても生のCSSが現実的に使えるようになっています。

Tailwind CSSやSASSを使うのであれば、CSSをビルドするツールが必要になります。Tailwind CSSについては別個のtailwindcss-rails gemが用意されていますし、SASSを使いたいのであればdartsass-rails gemが用意されています。またJavaScriptビルド時にどっちみちNode.jsを使っていたのであれば、それを使うcssbundling-rails gemが用意されています。すべて公式のgemです。

tailwindcss-rails gemおよびdartsass-rails gemはNode無しで使えるのに対して、cssbundling-rails gemはNodeを必要とするぐらいの違いです。(ビルド用のDockerコンテナにnodeをインストールするところだけが面倒ですが、そこもさまざまにオプションを変えながらrails newで生成されるDockerfileを参考をみて、それをコピペすれば対応できます)

本サイトでは、Reactを使う関係でどうしてもNodeを使用しますので、ついでにTailwind CSSもcssbundling-rails gemでビルドさせています。Reactを使わずに、またJavaScriptはimport mapsにするのであれば、私もtailwindcss-rails gemを使用したかもしれません。

Rails 8以降の画像等のアセットの処理

非常に長い歴史を持つSprocketsでしたが、ノービルドが可能になったこと、およびJavaScript, CSS周りのエコシステムが充実してことを受けて、だんだん役割が狭まってきました。最初はJavaScriptのビルド、CSSのビルド、そしてdigestの付与等の役割を担っていたのが、今ではdigestの付与ぐらいしか役割がなくなってしまいました。そこで登場したのがPropshaftです。

Propshaftはdigestの管理が主な仕事になります。ERBを使った気持ち悪い手段を取らなくてもCSSやJavaScriptからアセットファイルを参照できますし、esbuild等がすでにdigestをつけてくれるのならば、propshaftが二重にdigestをつけるのを防ぐこともできます

まとめ

このようにRails 7, 8でRailsのアセット管理は大きく見直されました。ノービルドでやる場合であっても、あるいはReact/JSXを使ってJavaScriptをビルドする場合であっても、アセット管理は大幅に簡略化されています

特にフロントエンドエンジニアに嫌われていたのは、Webpackerによる独自のRailsとの統合だったのではないかと思います。これを嫌ってReact/VueフロントエンドとRailsバックエンドのリポジトリを完全に分けていたプロジェクトも多いかと思います。しかし今のRailsはフロントエンドのエコシステムとより親和性のある方法を採用しています

SprocketsやWebpackerがどうしても必要だった時代はもう過ぎ去りました。新しいツールと簡素な管理で、今まで以上に充実したアセット管理ができるようになったと言えるでしょう。