この記事は「つながる勉強会 Advent Calendar 2022」の 13日目の記事です。
12日目の記事はこちら⏩ 「JavaScriptの日付型の罠」
どうも、リリーです。
昨年12月にRails 7リリースされましたが、皆さん使ってますか?
僕が担当しているプロダクトではいずれもRails 6を使用しているためあまり馴染みがないのですが、そろそろリリースから1年ということで、改めてその特徴について調べてみました。
なお、今回はAPIサーバーとしてではなくフルスタックフレームワークとしてのRails、つまりフロントエンドもRails内で完結させる場合を対象としています。
Rails 7になって何が変わった?
Rails 7の最大の特徴はフロントエンドの開発環境の刷新です。
JavaScriptのモジュールバンドラとしてRails 5ではSprockets、Rails 6ではwebpackerが標準装備されていましたが、Rails 7ではそれらに代わりimportmap-railsが標準となっています。(ただし、従来通りWebpackerを使うこともできます)
また、フロントエンド開発のアプローチとしてHotwireが導入されました。
Rails 6から7になっていきなり上記やjsbundling-rails, Hotwire, Turbo, esbuild, ...など色々な登場人物が現れて、混乱した方もいるのではないでしょうか?かく言う僕もその一人なので、今回改めて諸々の用語を整理しました。
まず、Rails 7で新たに登場したフロントエンド周りの技術として、その役割を大別すると以下の2つになります。
- フロントエンドの記述方法に関するもの
- JavaScriptの読み込みに関するもの
フロントエンドの記述方法に関するもの
こちらはERBやJavaScriptの書き方に関わってくる技術で、具体的にはHotwire(HTML Over The Wire)が当てはまります。HotwireはTurbo, Stimulus, Stradaという3つの技術から構成される、Railsでのフロントエンド開発の新しいアプローチです。
Turbo
Hotwireの中核技術がTurboで、これによりJavaScriptを書かずにSPA風のUIを作ることができます。
Stimulus
StimulusはJavaScriptのライブラリで、HTMLとJSの紐付けを分かりやすくしてくれる役割を持ちます。
Stradaについては詳細未発表なので割愛します。
JavaScriptの読み込みに関するもの
こちらには以下のものが分類されます。
importmap-rails
jsbundling-rails
esbuild
rollup
webpack
Import MapsはJavaScriptをバンドルせずにブラウザで直接モジュールをインポートできる技術で、これをRailsで使用するためのgemが importmaps-rails
です。Node.js環境が不要になる一方で、JSXやTypeScriptが使用できないなどのデメリットがあります。
先述の通り、Rails 6ではwebpacker
がデフォルトだったのに対し、Rails 7ではimportmaps-rails
がデフォルトになっています
これに対して、jsbundling-rails
は従来通りバンドルを行う方式で、バンドラとしてesbuild
, rollup.js
, webpack
のいずれかを選択できます。
Hotwire vs React 比較
Rails 7で導入された技術について、個別の内容は上記の通りですが、全体としてJavaScriptの記述量を少なく済ませるという方向性に寄ったバージョンアップとなっており、「Railsはフルスタックフレームワークである」というDHHの思想が色濃く出ている方針です。
最近のフロントエンド全盛のトレンドに逆行した方向性なので、正直個人的にはそこまで好きではないものの、少人数・小規模の開発においてはHotwireによりかなり効率化できるプロダクトもありそうです。
何はともあれ、実際に触ってみないと始まらないので、Hotwireを使って簡単なメモリストを作ってみました。
https://github.com/shu-illy/rails7hotwiresample
なお、こちらではscaffoldに毛が生えた程度の超シンプルなUIなので、Stimulusは使わずTurboのみで対応しています。
TurboでSPA風のUIを作る方法はこちらの記事が参考になりました。
https://zenn.dev/shita1112/books/cat-hotwire-turbo/viewer/tutorial-2
また、比較対象としてRails + Reactを使用して同様のメモリストを作りました。
https://github.com/shu-illy/rails7_vite_react
こちらはバンドラにViteを使用しており、viewにReactコンポーネントをマウントする形になっています。
RailsでViteを使う方法はこちらをご覧ください。
https://zenn.dev/shu_illy/articles/a0ad61ef62e0d4
(記事ではVueを使用していますが、ReactでもViteの導入方法は同様です)
Hotwireを使ってみての所感
Hotwire(Turbo)を実際に使ってみて、SPA風のメモリストのUIが驚くほど簡単に実装できました。JSを1行も書かずにこれが実現できるのはかなり驚きです。
UIにこだわらない管理画面などであれば、Turboだけでサクッと作れそうです。
React/Vueの導入コストを考えると、このレベルのUIならTurboの方が有利そうですね。
Stimulusは今回使用していませんが、使用方法はこちらの記事が参考になりました。
https://abillyz.com/moco/studies/540
JSファイルでコントローラ名とアクション名を定義して処理を記述し、viewファイルからコントローラ名・アクション名を指定して処理を呼び出すという使い方です。
webpackerでは、viewとJSファイル内に書いたロジックの対応関係が分かりにくいというデメリットがありました。
一方でStimulusではview側で呼び出すコントローラ名・アクション名を明示しているため、viewとロジックの対応関係がかなり分かりやすくなりそうです。
webpackerでは発火させるために document.addEventListener
を何度も書く必要があるのが辛いところでしたが、Stimulusではそれがないところも良いですね。
ただ、Stimulusでの(イベントリスナーの設定を除いた)ロジックの記述量に関しては、従来のVanilla JS / jQueryと大きく変わることはなさそうです。
この辺の命令的な記述量が増えて複雑になるほど、ReactやVueによる宣言的UIの方が効率的になってきますし、モダンフロントのエコシステムの恩恵に預かることもできます。
以上を踏まえて、Rails 7でのフロントエンド開発は以下の方針にするのが効率が良いと思います。
- シンプルなCRUDや画面遷移のみのUI → Hotwire
- 上記以外で、ある程度複雑なDOM操作・非同期処理・状態管理等が必要なUI → React / Vue
また開発効率以外の観点だと、Hotwireは独自記法の癖が強めです。慣れてくるとスムーズに書けるようにはなりますが、他の言語・FWに横展開できるものではないですし、Railsのメジャーアップデートにより使われなくなる未来もありえます。
(このあたりも積極的にHotwireを使いたいと思えない理由です)
まとめ
今回の調査・検証をまとめると以下の通りです。
- Rails 7ではフロントエンドの開発環境が大きく刷新された
- フロントエンドの記述に関する技術として、Hotwireが導入された
- Rails 7でのJavaScriptの読み込みに関する技術(gem)として、
importmap-rails
とjsbundling-rails
が導入された - シンプルなUIであればHotwire、ある程度複雑なUIであればReact / Vueを使うのが効率が良い
この記事の内容が参考になれば幸いです。
また、内容に間違いなどあればTwitterにてご連絡頂ければと思います。