Rails 7の新規アプリで遊んでいると、やはりライブリロード機能(ファイル更新を監視してブラウザを自動リロードする、いわゆるホットリロード)が欲しくなったので、guard-livereload gemでDocker環境にライブリロード機能を導入しました。Rails 7でちょっと便利になった点があります。
環境
- Docker(docker-compose)環境が前提
- Docker Desktop for Mac: 4.4.2 (73305)
- Engine: 20.10.12
- Compose: v2.2.3
- Rails 7 + Ruby 3.1
- Rails 7サーバーを
./bin/dev
で起動できることが前提
- Rails 7サーバーを
インストール方法
- Gemfileに以下を追加し、
bundle install
を実行します。
group :development do
# (略)
+ gem "guard-livereload", require: false
+ gem "rack-livereload"
end
- プロジェクトディレクトリで以下を実行し、設定ファイルを生成します。
guard init livereload
プロジェクトディレクトリの直下に以下のファイルが生成されます。
# Guardfile
# A sample Guardfile
# More info at https://github.com/guard/guard#readme
## Uncomment and set this to only include directories you want to watch
# directories %w(app lib config test spec features) \
# .select{|d| Dir.exist?(d) ? d : UI.warning("Directory #{d} does not exist")}
## Note: if you are using the `directories` clause above and you are not
## watching the project directory ('.'), then you will want to move
## the Guardfile to a watched dir and symlink it back, e.g.
#
# $ mkdir config
# $ mv Guardfile config/
# $ ln -s config/Guardfile .
#
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
guard 'livereload' do
extensions = {
css: :css,
scss: :css,
sass: :css,
js: :js,
coffee: :js,
html: :html,
png: :png,
gif: :gif,
jpg: :jpg,
jpeg: :jpeg,
# less: :less, # uncomment if you want LESS stylesheets done in browser
}
rails_view_exts = %w(erb haml slim)
# file types LiveReload may optimize refresh for
compiled_exts = extensions.values.uniq
watch(%r{public/.+\.(#{compiled_exts * '|'})})
extensions.each do |ext, type|
watch(%r{
(?:app|vendor)
(?:/assets/\w+/(?<path>[^.]+) # path+base without extension
(?<ext>\.#{ext})) # matching extension (must be first encountered)
(?:\.\w+|$) # other extensions
}x) do |m|
path = m[1]
"/assets/#{path}.#{type}"
end
end
# file needing a full reload of the page anyway
watch(%r{app/views/.+\.(#{rails_view_exts * '|'})$})
watch(%r{app/helpers/.+\.rb})
watch(%r{config/locales/.+\.yml})
end
Rack::LiveReload
を有効にします。
# config/environments/development.rb
Rails.application.configure do
config.after_initialize do
# (略)
+ config.middleware.insert_after ActionDispatch::Static, Rack::LiveReload
end
end
- Procfile.devに以下を追記してguardがDockerコンテナ内で起動されるようにします。
./bin/dev
はこのProcfile.devを呼び出します。
# Procfile.dev
web: bin/rails server -p 3000
css: bin/rails tailwindcss:watch
+livereload: bundle exec guard start -i -g livereload
guard
を別途起動する必要がないので、Rails 6以前よりも便利になりました😋。
- LiveReloadで使うポート35729をDockerの外部に転送します。方法はいろいろありますが、自分はdocker-compose.ymlにポート35729を追加しました。
# (略)
rails:
<<: *backend
command: bin/dev
ports:
- "3000:3000"
+ - "35729:35729"
- ChromeブラウザにLiveReload拡張をインストールします。
- これで、
./bin/dev
を実行し、http://localhost:3000
をブラウザで開けば、ライブリロードが有効になります。
$ ./bin/dev
02:23:21 web.1 | started with pid 8
02:23:21 css.1 | started with pid 9
02:23:21 livereload.1 | started with pid 10
02:23:23 livereload.1 | 02:23:23 - INFO - LiveReload is waiting for a browser to connect.
02:23:23 web.1 | => Booting Puma
02:23:23 web.1 | => Rails 7.0.1 application starting in development
02:23:23 web.1 | => Run `bin/rails server --help` for more startup options
02:23:25 web.1 | Puma starting in single mode...
02:23:25 web.1 | * Puma version: 5.6.1 (ruby 3.1.0-p0) ("Birdie's Version")
02:23:26 web.1 | * Min threads: 5
02:23:26 web.1 | * Max threads: 5
02:23:26 web.1 | * Environment: development
02:23:26 web.1 | * PID: 8
02:23:26 web.1 | * Listening on http://0.0.0.0:3000
02:23:26 web.1 | Use Ctrl-C to stop
02:23:26 css.1 |
02:23:26 css.1 | Rebuilding...
02:23:26 livereload.1 | 02:23:26 - INFO - Guard is now watching at '/app'
02:23:27 css.1 | Done in 619ms.
02:23:27 livereload.1 | 02:23:27 - INFO - Reloading browser: /assets/tailwind.css
02:23:27 livereload.1 | 02:23:27 - INFO - Browser connected.
ctrl-cでの終了処理もforeman gemがまとめてやってくれます。
^C02:24:42 css.1 | rails aborted!
02:24:42 web.1 | - Gracefully stopping, waiting for requests to finish
02:24:42 css.1 | Interrupt:
02:24:42 livereload.1 |
02:24:42 system | SIGINT received, starting shutdown
02:24:42 web.1 | === puma shutdown: 2022-02-04 02:24:42 +0000 ===
02:24:42 css.1 |
02:24:42 - INFO - Bye bye...
02:24:42 web.1 | - Goodbye!
02:24:42 css.1 | Tasks: TOP => tailwindcss:watch
02:24:42 web.1 | Exiting
02:24:42 css.1 | (See full trace by running task with --trace)
02:24:43 system | sending SIGTERM to all processes
02:24:43 web.1 | exited with code 0
02:24:43 css.1 | exited with code 1
02:24:43 livereload.1 | exited with code 0
$
おまけ
Rails 7でimportmap-railsとsprockets(またはpropshaft)のみを使う場合は、./bin/dev
というbinstubは追加されません。
しかしguard-livereload用に自分でbinstubとProcfile.devを追加すれば、./bin/dev
でguard-livereloadも起動できるので楽ですね。何となく、今後は./bin/dev
で起動するのが主流になりそうな気がしています。
# bin/dev
#!/usr/bin/env bash
if ! command -v foreman &> /dev/null
then
echo "Installing foreman..."
gem install foreman
fi
foreman start -f Procfile.dev
# Procfile.dev
web: bin/rails server -p 3000
livereload: bundle exec guard start -i -g livereload
なお、foreman gemはGemfileに追記する必要はありません。見てのとおり、初期実行時にbundlerの管理の外でgem install foreman
で勝手にインストールされます。