年末なので Rails 依存関係の大掃除
2022年 Ruby on Rails Advent カレンダー 19日目の記事です。
Ruby on Rails はトップページ(2022年12月19日現在)で "a full-stack framework" とうたっています。実際、Web アプリ開発でよく使われるさまざまな機能が Rails にはてんこ盛りです。そのため、自分のアプリでは使わない機能を提供するジェム(依存関係)も、たくさんインストールされてしまいます。
この1年、仕事で Rails を使った開発に参加するようになって
- 使ってないジェムがバンドルサイズ 53 MB のうち 11 MB (21%)も消費している。ローカルや CI でインストールが遅くなるのはイヤだな〜
- 使ってないジェムに脆弱性のアラートや dependabot の自動更新が来てしまう。放っておくと本当に重要なアラートや更新が埋もれてしまってイヤだな〜
と気になってしまったので、使っていない Rails のジェムを削除してみました。
想定する Rails 環境
- Rails アプリ(や Engine)としての初期設定を済ませている
- 依存関係のバージョンを統一するため、Gemfile.lock をバージョン管理している
- 十分なテストカバレッジがあり、ジェム削除によるデグレに高確率で気付ける
すべて満たしていることを想定しています。
Rails に必要ないジェムを削除していく手順
rails ジェムの gemspec ファイルを見ると、rails ジェムは 12 個のジェムに依存していることがわかります。この12個すべてではなく、必要なジェムにだけ依存するようにしていきます。まずは、Gemfile に書かれた
gem 'rails', '7.0.4'
のような rails ジェムを、次のように 12個のジェムに置き換えます。
RAILS_VERSION = '7.0.4'
gem 'actioncable', RAILS_VERSION
gem 'actionmailbox', RAILS_VERSION
gem 'actionmailer', RAILS_VERSION
gem 'actionpack', RAILS_VERSION
gem 'actiontext', RAILS_VERSION
gem 'actionview', RAILS_VERSION
gem 'activejob', RAILS_VERSION
gem 'activemodel', RAILS_VERSION
gem 'activerecord', RAILS_VERSION
gem 'activestorage', RAILS_VERSION
gem 'activesupport', RAILS_VERSION
gem 'railties', RAILS_VERSION
この時点で bundle install コマンドを実行し、Gemfile.lock から rails ジェムだけが消えることを確認します。
あとは、これら12個それぞれに対して、次の手順を繰り返していきます。
- gem '...' の1行を削除する
- bundle install を実行する。更新された Gemfile.lock から該当のジェムが消えるのを確認する
- もし消えなければ、別のジェムに使われているということ。それら別のジェムを消せないか検討する
- ソースコードを検索し、削除するジェムに関するファイルや設定値を見つけて削除する
- たとえば actioncable ジェムなら Action cable や action_cable といったように、大文字小文字違い、さまざまな区切り文字もある。git grep を使い、git grep --extended-regexp --ignore-case "paction.?cable" のような正規表現で検索するとよい
- テストを実行する。問題が見つかれば修正する(後述)
- ジェムを削除して問題なさそうであればコミットする。問題あればリバートする
具体例1:activejob ジェムの削除
activejob ジェムを削除すると、NameError: unitiliazed constant ActiveJob のようなエラーが起きることがあります。"class ApplicationJob < ActiveJob::Base" のように、削除したジェムに含まれるクラスやモジュールを使っていると、それらが見つからないので起きるエラーです。
activejob を使っていない場合、ApplicationJob クラスは空の実装なので、削除できるでしょう。
具体例2: actionmailer ジェムの削除
actionmailer ジェムは、メールを送信する機能を提供します(受信は actionmailbox)。
先に示した正規表現で git grep --extended-regexp --ignore-case "action.?mailbox" と検索すると、以下のようなファイルがヒットします。
- app
- mailers
- application_mailer.rb
- views
- layouts
- mailer.html.erb
- mailer.txt.erb
- config
- environments
- development.rb
- development.rb
これらから、actionmailer に関する行やファイル自体を削除します。削除したらテストを実行し、問題がないことを確かめます。
消せそうなジェム、消せなそうなジェム
- 消せる可能性がありもの。これらはアプリによっては必要ないケースがある
- actioncable
- actionmailbox
- actionmailer
- actiontext
- activejob
- activestorage
- 消せる可能性があまりないもの。これらは Rails のコアな機能に相当し、消せないことが多い。Gemfile からは消せても、なんらかの Rails エコシステムのジェムが使っており、Gemfile.lock に残る可能性が高い
- actionpack
- actionview
- activerecord
- activemodel
- activesupport
- railties
まとめ
- rails ジェムは12個のジェムの集合体(rails 7.0.4 時点)である
- Gemfile 内で rails ジェムを最小限のジェムに置き換えると、不要なジェムをインストールしないで済む
- 場合によっては10MBなどバンドルサイズを縮めることができる。また、意味のない脆弱性アラートなども減らせる