はじめに
herokuへデプロイした際にアセットパイプラインやマニフェストファイルについて理解を深めたので、その内容をまとめました。
※こちらは前回の投稿です。
【エラー】Error: node is not installed. の解決方法
開発環境
Ruby | 3.2.3
Ruby on Rails | 7.1.3
MySQL | mysql5.7
Docker Compose
前提
アセットパイプライン
Railsでアセットファイル(画像・CSS・JavaScriptなど)を効率的に配信するためのフレームワークです。
アセットファイルは以下の例のようなディレクトリ構造になっています。
app
└─ assets
├─ config
| └─ manifest.js
├─ images
| └─ default_avatar.png
└─ stylesheets
└─ application.css
アセットプリコンパイル
Railsアプリケーションのアセット(JavaScript、CSS、画像など)を事前にコンパイルするためのコマンドです。
以下のコマンドで、本番環境向けに手動でプリコンパイルすることができます。
$ RAILS_ENV=production rails assets:precompile
manifest.js
アセットをコンパイルするときに、アセットのcssファイルやjsファイルなどをまとめて読み込むための設定を行う、Sprocketsのマニフェストファイルです。
ディレクティブという独自のコメントを記述することによって、対象のファイルを指定することができます。
//= link_tree ../images
//= link_directory ../stylesheets .css
//= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js
このファイルにはディレクティブ(directive)が含まれています。ディレクティブは、単一のCSSファイルやJavaScriptファイルをビルドするためにどのファイルが必要かをSprocketsに指示します。
上のマニフェストファイルは、./app/assets/imagesディレクトリやそのサブディレクトリにあるすべてのファイル、./app/javascriptディレクトリや./vendor/javascriptで直接JSとして認識されるすべてのファイルの内容をインクルードすることを意味しています。
このマニフェストファイルは ./app/assets/stylesheetsディレクトリにあるすべてのCSSを読み込みます(ただしサブディレクトリは含めません)。
./app/assets/stylesheetsフォルダにapplication.cssファイルとmarketing.cssファイルがあると仮定すると、ビューに<%= stylesheet_link_tag "application" %>または<%= stylesheet_link_tag "marketing" %>と書くことでこれらのスタイルシートを読み込めるようになります。
Q.javascriptファイルがassetsディレクトリから読み込まれないのはなぜ?
その理由は、./app/javascriptが既にimportmap-rails gemのデフォルトのエントリポイントになっていて、vendorフォルダはダウンロードしたJSパッケージの置き場所になっているからです。
Sprockets
端的に言うと、アセットファイル(cssファイルや画像ファイルなど)をひとまとめにして、圧縮してくれる機能です。
アセットプリコンパイルの実行結果
$ RAILS_ENV=production bin/rails assets:precompile
I, [2024-06-08T03:33:49.625772 #159] INFO -- : [dotenv] Loaded .env
I, [2024-06-08T03:33:52.526211 #159] INFO -- : Writing /event-management-app/public/assets/application-af22eef2d991d90a3c42d9384913469543786a9e07f8575a15308052a8a6e48d.css
I, [2024-06-08T03:33:52.526843 #159] INFO -- : Writing /event-management-app/public/assets/application-af22eef2d991d90a3c42d9384913469543786a9e07f8575a15308052a8a6e48d.css.gz
I, [2024-06-08T03:33:52.531707 #159] INFO -- : Writing /event-management-app/public/assets/login-ed2245a88bb76e43ed8d3494c42c9d40a6c0294533fe1304f7fd420b26fd18a3.css
I, [2024-06-08T03:33:52.531923 #159] INFO -- : Writing /event-management-app/public/assets/login-ed2245a88bb76e43ed8d3494c42c9d40a6c0294533fe1304f7fd420b26fd18a3.css.gz
I, [2024-06-08T03:33:52.535468 #159] INFO -- : Writing /event-management-app/public/assets/bootstrap.min-9c65d9e27926afe0cb1ca7bd76bef901e6271544f59549d308fc11d62bb6d7fe.css
アセットファイルはどこに保存される?
この時にSprocketによってアセットが読み込まれます。
またSprocketは、ひとまとめにしたアセットファイルをpublicフォルダ配下にコピーします。
app
└─ assets
| ├─ config
| | └─ manifest.js
| ├─ images
| | └─ default_avatar.png
| └─ stylesheets
| └─ application.css
└─ public
└─ assets
├─ .sprockets-manifest-0e17426482147bbe2b1dcc26aa8c7b01.json
├─ application-5dfd84014934ea2834c32c61ca4f95059397f0251a70ba4ae985abe8fe7e377a.css
└─ default_avatar-d15493959b5c7f75a17701785b0641a74400150c7b44830ecd5e95b5864a434b.png
manifest.jsに記載がない場合はどうなる?
アセットパイプラインの仕様か、本番環境でアセットファイルがプリコンパイルされません。
そのため、以下のasset.rbファイルに手動でプリコンパイルするファイルを指定します。
(非常に非効率で面倒くさい)
Rails.application.config.assets.precompile +=
%w(
*.js *.css *.png
bootstrap.min.js
popper.js
javascript/controllers/application.js
javascript/controllers/hello_controller.js
javascript/controllers/index.js
application.js
flash.js
preview.js
default_avatar.png
events/no_image.png
categories/art.png
categories/medical_care.png
application.css
login.css
events/index.css
events/pagination.css
shared/colors.css
shared/footer.css
shared/common.css
users/mypage.css
)
なお、categoriesやeventsなどのサブディレクトリ直下のファイルを一つずつ追記しているのは、サブディレクトリが含まれずコンパイルされないから
以下のようにワイルドカードを指定してできると思ったのになぁ...
categories/*.png
events/*.png
(もしサブディレクトリ下のファイルを含める方法があれば教えてください🙏)
デプロイ実行結果
$ git push heroku main
Enumerating objects: 12, done.
Counting objects: 100% (12/12), done.
Delta compression using up to 8 threads
Compressing objects: 100% (6/6), done.
Writing objects: 100% (7/7), 780 bytes | 260.00 KiB/s, done.
//(省略)
remote: -----> Detecting rake tasks
remote: -----> Preparing app for Rails asset pipeline
remote: Running: rake assets:precompile
remote: Asset precompilation completed (1.50s)
remote: Cleaning assets
remote: Running: rake assets:clean
remote: -----> Detecting rails configuration
(省略)
remote: -----> Compressing...
remote: Done: 250.3M
remote: -----> Launching...
remote: Released v5
remote: https://event-manage-app-13c44e27b30b.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/event-manage-app.git
1c6fcbb6..aa2c83d1 main -> main
デプロイ時に自動的にプリコンパイルが実行されます。
まとめ
- アセットパイプラインを使うことで複数のファイル(css,js,画像など)を連結/圧縮してまとめてコンパイルできる。
- マニフェストファイル(manifest.js)には、アセットファイルを連結する対象のファイルを設定する。
参考記事
1 アセットパイプラインについて
3.1 マニフェストファイルとディレクティブ
4.1 アセットをプリコンパイルする
【Rails】アセットパイプライン(Sprockets)の基本情報と実装方法
Railsのマニフェストファイルを使ったJsとStylesheetの呼び出し
コードのデプロイ(heroku)