4
4

【Ruby on Rails, Sprockets】app/assets/とmanifest.jsを複数配置してアセットパイプラインを走らせたい!🏃‍♂️💨

Last updated at Posted at 2024-03-08

こんにちは、akitoshigaです。

先日、アセットファイルをapp/assets/**以外の場所に配置した上でmanifest.jsを利用して複数の場所からアセットパイプラインを走らせる必要が生じたのですが、類似の事例が見つからず自身が実践した方法を共有します。

1. 前提:アセットパイプラインとは

アセットパイプラインとは、アセットファイル(画像・CSS・JavaScriptなど)を効率的に配信するためのフレームワークでありRuby on Railsに組み込まれています。

複数のCSSファイルを圧縮して一つにまとめたり、フィンガープリントを利用したキャッシングの管理をしてくれます。

アセットパイプラインは内部でsprocketsimportmap-railsというgemを利用しています。

詳しい説明はRailsガイドをご覧ください。

2. やりたいこと

下記のように、Ruby on Rails指定のアセットファイルの置き場であるapp/assets/配下に加えてpacks/new_module/app/assets/配下にアセットファイルを配置します。
その上でpacks/new_module/app/assets/config/manifest.jsを読み込んでビューのレイアウトからアセットファイルの読み込みを行おうとしていました。

※ 以降一部のディレクトリ名やファイル名は実際のものから変更しています。

project_root
└── app Rails指定
│   └── assets
│       ├── config
│       │   └── manifest.js
│       ├── images
│       ├── javascripts
│       └── stylesheets
└── packs ⭐追加
    └── new_module
        └── app
            └──assets
               ├── config
               │   └── manifest.js
               ├── images
               ├── javascripts
               └── stylesheets

3. 何故やりたいのか

モジュラーモノリスなRailsアプリケーションを構築するために、packs-railsを用いてビューファイルやそこで使うアセットファイルを一部別のディレクトリに切り出したかったためです。

packs-railsを簡単に説明すると、ドキュメントルートのapp/と同じ階層にpacks/というディレクトリを作り、その配下で複数のパッケージ構成を可能にするgemです。

packs-rails指定のディレクトリ構成に従う代わりに面倒なオートロードの設定を省略してくれます。
しかし、利用する過程でassetsは対象外だったことが発覚したため今回自力での対応に至りました。

4. 最初に行ったこと

4.1. アセットファイルの追加

  1. 上記のディレクトリにアセットファイルを追加します。
  2. 追加したアセットファイルを読み込むためのmanifest.jspacks/new_module/assets/config/配下に追加します。
packs/new_module/apps/assets/config/manifest.js
//= link_tree ../images
//= link_tree ../stylesheets .css
//= link_tree ../javascripts .js

4.2. 追加したファイルをアセットパイプラインに追加

追加したファイルをアセットファイルパイプラインの対象とするためにassets.rbに定義を追加します。
今回のケースではpacks-railsを利用しているためpacks/new_module/config/initializers/assets.rbを追加してそこにnew_moduleで使用するアセットファイルの定義を追加しました。

packs/new_module/config/initializers/assets.rb
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','config')
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','stylesheets')
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','javascripts')
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','images')

5. しかし、反映されない

Railsを再起動して、アセットファイルを使用しているビューにアクセスしてみるとSprockets::Rails::Helper::AssetNotPrecompiledErrorというエラーが発生します。
スクリーンショット 2024-03-07 15.22.30.png
新しく配置したアセットファイルがプリコンパイルされず読み込むことができないためにエラーが送出されているようです。

6. 検証してみる 

6.1 パスの確認

assets.rbで指定したパスが正しく読み込まれているか確認します。
Railsコンソールを開いて以下の値を確認します。

Rails.application.config.assets.paths

そうすると以下のような形で読み込み対象のパスの一覧が出力されるようになります。

=> ["/path/to/document/app/assets/config",
 "/path/to/document/app/assets/images",
 "/path/to/document/app/assets/javascripts",
 "/path/to/document/app/assets/others",
 "/path/to/document/app/assets/stylesheets",
 "/path/to/document/vendor/assets/javascripts",
 "/path/to/document/vendor/assets/stylesheets",
 #<Pathname:/path/to/project_root/packs/new_module/app/assets/config>,
 #<Pathname:/path/to/project_root/packs/new_module/app/assets/stylesheets>,
 #<Pathname:/path/to/project_root/packs/new_module/app/assets/javascripts>,
 #<Pathname:/path/to/project_root/packs/new_module/app/assets/images>]

出力されたパスを環境のlsコマンドの引数にわたすと意図したファイルが出力されるのでパスはあっていそうです。

6.2 プリコンパイルしてみる

rakeタスクassets:precompileを実行してアセットファイルを出力してみます。

$ bundle exec rails assets:precompile

このタスクを実行すると開発環境でもpublic/assets/にアセットファイルがプリコンパイルされてひとまとめに出力されます。
その中を確認するとやはり新しく配置した静的アセットファイルが入っていませんでした。

上記のことからパスは合っている、呼び出し先が間違っているのではなくプリコンパイルがされていないことが確認できました。

7. 解決方法

試行錯誤の結果、以下の解決方法にたどりつきました。

7.1. manifest.jsのファイル名を変更

新しく追加した方のmanifest.jsのファイル名を変更します。
自分の場合は下記のようにモジュール名をプレフィックスにしました。
new_module_manifest.js

7.2 プリコンパイルの対象に追加する

new_module_manifest.jsがプリコンパイルの対象となるように新しい方のassets.rbに定義を追加します。

packs/new_module/config/initializers/assets.rb
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','config')
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','stylesheets')
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','javascripts')
Rails.application.config.assets.paths << Rails.root.join('packs','new_module','app','assets','images')

Rails.application.config.assets.precompile += %w[new_module_manifest.js] # ⭐追加

これらを実施することで無事アセットファイルを読み込めるようになりました!

sproketsはapp/assets/config/配下のmanifest.js以外で、トップレベルターゲットを定義するファイルを用意する場合は、都度対象となるファイルを定義しなければいけないようです。(ドキュメント等確認しましたが明確に記載されておらず、、、どなたか情報提供お待ちしています。)

8. まとめ

おわって見れば単純な問題でしたが、解決に結構かかりました。

現在Ruby on Railsアプリケーションのモジュラーモノリス化は注目されていると思うので、同じような試みをされている方の一助になれば幸いです🙏

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4