Rails7から色々なオプションが増え、整理ができていなかったので、いろいろ試して整理してみました。
同じような人がいるかと思ったので、参考になると嬉しいです。
rails ver: 7.0.4.2
Rails7ではデフォルトの構成に変化が色々ありました。特にフロントエンドに関する部分が大きく変わったので、そこを重点的に説明していきます。
オプションの確認
rails new -h
(結果は長いので省略します)
1. JavaScript に関するオプション
新たにJavaScriptのビルドのツールを選択できるようになりました。
デフォルトは「importmap」となっています。 (Import mapsについては後で説明します)
-j, [--javascript=JAVASCRIPT]
# Choose JavaScript approach [options: importmap (default), webpack, esbuild, rollup]
# Default: importmap
importmap-rails
importmap
を選択すると、rails newで以下のコマンドが実行され、importmap-railsのデフォルト設定が作成されます。
rails importmap:install
今まではwebpackerが使われていましたが、importmap-railsがデフォルトとなりました。
importmap-railsを使うことで、Node.jsを使ったJSファイルのビルドが不要になります。
この変更の背景について、DHHの記事で説明されています
- IE11のEOLにより、JavaScriptをES5に変換する必要がなくなった
- HTTP2の普及により、多くのファイルを1つにまとめる必要がなくなった
- バンドルをすると少しの変更でもキャッシュのexpireが必要というデメリットがある
- Import mapsにより、モジュールの依存関係にファイル名を使わずに済むので、モジュールの内容が変わっても呼び出している側のファイルのキャッシュを使い回せる
というものです。
Import mapsとは、JavaScriptモジュールをimportする際に、モジュール解決の方法を制御できるJSONオブジェクトです。モジュールと、その名前のマッピングを用意しておくことで、import
文を使ったときに対応するモジュールを解決してくれます。1
これにより、import React from 'react'
のように書かれたJavaScriptが、そのままブラウザ上で動かせるようになります。
importmap-railsではconfig/importmap.rb
でその対応表を作ります。
# Pin npm packages by running ./bin/importmap
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
このように書くことで、モジュール解決ができ、JavaScriptをビルドしなくてもブラウザ上で動作させることができるようになります。
ちなみに、Import mapsがまだ対応していないブラウザでも、es-module-shims がインストールされるので動作するようです。
その他のオプションを選択したい (bun, webpack, esbuild, rollup)
2023/9/29追記 Rails v7.1.0.beta1でBunが追加されたので別記事にまとめています
importmap以外にもbun, webpack, esbuild, rollupを選択することができます。
importmapだとTypeScriptを使ったり、JSXを使ったりができないので、これらを使いたいときには他のツールが候補になります。
これらを選択した場合、rails newで以下のようなコマンドが実行されます。
rails javascript:install:esbuild
このとき、./package.json
が生成され、esbuildがインストールされます。
そして、Railsとこのビルドツールの間をうまくつなぐ役割として jsbundling-rails があります。
assets:precompile
を実行すると、yarn build
の結果がapp/assets/builds
に出力され、Asset pipilineと組み合わせることができます。
2. CSS に関するオプション
-c, [--css=CSS]
# Choose CSS processor [options: tailwind, bootstrap, bulma, postcss, sass... check https://github.com/rails/cssbundling-rails]
Tailwind CSS, Bootstrap, Bulma, PostCSS, Dart Sassが選択できます。
JavaScriptのときと同様に、以下のコマンドが実行されます。
rails css:install:tailwind
またCSSの場合は cssbundling-rails がRailsとの間をつなぐ役割を担ってくれます。
CSSのオプションの中でtailwind以外は、一緒にesbuildがインストールされます。tailwindだけはデフォルトでimportmap-railsと tailwindcss-rails がインストールされます。
3. Asset pipeline に関するオプション
これも新しく追加されたオプションです。
-a, [--asset-pipeline=ASSET_PIPELINE]
# Choose your asset pipeline [options: sprockets (default), propshaft]
# Default: sprockets
Asset pipelineについては、Sprocketsの他に新たにPropshaftが選択できるようになりました。
Asset pipelineに関するオプションを何も指定しない場合、デフォルトでSprocketsがインストールされます。不要な場合は、明示的に--skip-asset-pipeline
オプションを指定する必要があります。
Sprockets
元々Asset pipelineは、JavaScriptやCSSなどのアセットをバンドル、minify、圧縮、トランスパイルなどをかんたんに行うために使われていました。また、必要なプロセッサをgemを用いて組み合わせることで、柔軟に処理できました。しかし、importmap-railsがデフォルトになったことで、一部の使い方が今までと変わりました。
例えば、Sprocketsとimportmap-railsを一緒に選択した場合、トランスパイルは行われません。TypeScriptを使用するといったようにトランスパイルが必要な場合は、importmap-railsではなく、esbuildなどの別のツールを使う必要があります。
読み込むファイルはapp/assets/config/manifest.js
に設定します。
そしてbin/rails assets:precompile
コマンドを実行してプリコンパイルすると、public/assets
ディレクトリに配置され、配信できるようになります。
JavaScriptのファイルはapp/assets/javascripts
ではなく、app/javascript
ディレクトリにありました。
Propshaft
Propshaftは、Sprocketsに代わる新しいAsset pipeline用のライブラリです。
importmap-railsと組み合わせることで、Asset pipelineにおいてバンドルやminify、コンパイルが不要になるケースが出てきました。そこでSprocketsよりもシンプルで高速なプリコンパイルを実現する目的で開発されました。
ただし、Sprocketsを使用しているアプリケーションをPropshaftに移行する場合、多くの変更が必要になる可能性があります。例えば、Sprocketsでトランスパイルなどを行っている場合、それらの処理を別のツールに置き換える必要があります。そのため、すぐにSprocketsを代替するものにはならないようです。
しかし、新規で rails new
をする場合、SprocketsよりもシンプルなAsset pipelineを実現できるので、候補にはなりうると思われます。
importmap-rails や jsbundling-rails/cssbundling-rails と併用する
先程も出てきましたが、デフォルトではSprocketsと一緒にimportmap-railsもインストールされます。Asset pipelineを無効化しないかぎり、これらの組み合わせてでどれにするかを選択します。
4. Hotwire に関するオプション
こちらも新たに追加されたHotwireに関するオプションです。
HotwireはJavaScriptをあまり書かなくても、既存のHTMLとの組み合わせることでSPAのようなページを作ることができるツールです。
[--skip-hotwire], [--no-skip-hotwire]
明示的に--skip-hotwire
を指定しない場合、turbo
, stimulus
がインストールされます。
rails turbo:install stimulus:install
gemはturbo-rails
, stimulus-rails
、npmパッケージは@hotwired/turbo-rails
, @hotwired/stimulus
です。
(importmapを使うときは@hotwired/stimulus-loading
もインストールされました)
Hotwire以前
Railsには、 rails-ujs (Rails UJS) と Turbolinks がありました。
Rails UJSによって、JavaScriptをほぼ書かなくてもAjaxを使ったformの挙動を実現できていました。また、Turbolinksによって、静的なHTMLであってもページ遷移をSPAっぽくすることができていました。
Rails7でHotwireが導入されるにあたり、TurbolinksはTurboの機能の1つのTurbo Driveとなっています。
また、Rails UJSはdeprecatedになりました。
Turbo + Stimulus
HotwireはTurbo、Stimulus (とStrada)で構成されています。
Turbo
TurboはJavaScriptを書かなくてもSPAのようなページ遷移を実現できるツールです。
Turbolinksが持っていた機能(Turbo Drive)の他にもいくつか機能が追加されています。
JavaScriptを一切書かなくても、Turbo Frameのdata-turbo-frame
を使って、HTMLの一部だけを差分更新したりすることができるようになります。
Stimulus
StimulusはJavaScriptのフレームワークです。ただ、Reactなどのように、JavaScriptがHTMLを生成するのではなく、生成されたHTMLにJavaScriptで機能を追加します。
jQuery等では、HTMLを動的に変更するには、セレクタを使って要素を選択し、イベントリスナーの設定をしますが、Stimulusではそれは行いません。HTMLにdata-controller
やdata-action
といった属性の設定をすることによって、HTMLとJavaScriptを紐付けます。
<div data-controller="hello">
<input data-hello-target="name" type="text">
<button data-action="click->hello#greet">
Greet
</button>
<span data-hello-target="output"></span>
</div>
import { Controller } from "stimulus"
export default class extends Controller {
static targets = [ "name", "output" ]
greet() {
this.outputTarget.textContent =
`Hello, ${this.nameTarget.value}!`
}
}
TurboもStimulusもRailsと切り離されたライブラリなので、素のHTMLの上でも動作させることができますし、他のフレームワークと組み合わせて使うことも可能です。
このあたりについては、他の方が色々と分かりやすい記事を書いているので、そちらを参考にしてみてください。
5. APIモード に関するオプション
APIモードは元々ありましたが、試してみました。
[--api], [--no-api] # Preconfigure smaller stack for API only apps
APIモードにすると、config/application.rbでconfig.api_only = true
が設定されますが、それ以外にも不要なファイルや設定が読み込まれなくなります。
ファイルやディレクトリを削除しているログ
remove app/assets
remove lib/assets
remove tmp/cache/assets
remove app/helpers
remove test/helpers
remove app/views/layouts/application.html.erb
remove public/404.html
remove public/422.html
remove public/500.html
remove public/apple-touch-icon-precomposed.png
remove public/apple-touch-icon.png
remove public/favicon.ico
remove config/initializers/assets.rb
remove app/assets/config/manifest.js
remove app/assets/config
remove app/assets/stylesheets/application.css
remove config/initializers/content_security_policy.rb
remove config/initializers/permissions_policy.rb
remove config/initializers/new_framework_defaults_7_0.rb
ソース: railties/lib/rails/generators/rails/app/app_generator.rb
またimply_options2として、 --skip-asset-pipeline
, --skip-javascript
, --skip-hotwire
も設定されます。
6. minimal (最小限のRailsアプリケーション)
minimalも元々ありましたが、使ったことがなかったので試してみました。
[--minimal], [--no-minimal] # Preconfigure a minimal rails app
minimalはメタオプションです。メタオプションとは、その他の複数のオプションをまとめて指定するためのオプションです。
ちなみに、api
はオプションをまとめる以外の機能もあるので、メタオプションではありません。
minimalをつけると、以下のオプションをまとめて指定することになります。
- skip_action_cable
- skip_action_mailbox
- skip_action_mailer
- skip_action_text
- skip_active_job
- skip_active_storage
- skip_bootsnap
- skip_dev_gems
- skip_hotwire
- skip_javascript
- skip_jbuilder
- skip_system_test
そのため、最小構成のRailsアプリケーションを作りたいときにrails new hoge --skip-action-mailer --skip-action-mailbox --skip-action-cable ...
のようにたくさんオプションをつけなくてもよくなるので便利です。
minimailを設定してもtest_unitはインストールされてしまうので、RSpecを使いたいときは-T
をつけると良いです。
その他のimply options
api
, minimal
以外にも、これを指定すると、他のオプションも指定されるというものがあります。
- skip_active_job:
skip_action_mailer
,skip_active_storage
- skip_active_record:
skip_active_storage
- skip_active_storage:
skip_action_mailbox
,skip_action_text
- skip_javascript:
skip_hotwire
詳しくはソースコードを読んでみてください。
- rails/railties/lib/rails/generators/app_base.rb · GitHub
- rails/railties/lib/rails/generators/rails/app/app_generator.rb · GitHub
感想
最近は、Asset pipelineを使っていないということもあり、Import mapsとかAsset pipeline周りとか、Hotwireとか知っても使わないしなーと思っていたのですが、調べてみるとどうしてこの変更をしたのか等が知れて、とてもおもしろかったです。
正直、bundleやminifyが必要ない!というのは早い気がしますが、今のフロントエンドのトレンドに対して、違った観点からの考え方が知れて新鮮でした。
参考
- Rails 7
- importmap
- Asset pipeline
- Hotwire
- Turbo
- Stimulus
- rails-ujs, turbolinks
- minimal