はじめに
はじめまして、プログラミングスクールにて学習中のmizuki (@mimc11_0) と申します。
現在、個人開発アプリにて検索機能(オートコンプリート)の追加実装作業を行っており、その過程でエラーが起きたので解決までの流れ、考えなどを記事にまとめたいと思います。
初記事のため拙い点が多々あるかと思われますが、よろしくお願いいたします。
※ 注意 ※
初学者のため誤った情報、考え方がある可能性がございます。
大変申し訳ございませんが、予めご了承いただけますと幸いです。
前提環境
- OS : Windows(WSL)
- Ruby : Ruby 3.3.8
- Ruby on Rails : 7.2.2.1
- Dockerを使用
- Sprockets と Importmapを同時使用している。
エラー内容
オートコンプリート機能の実装過程において、
stimulus-autocomplete
を Importmap で管理するようピン止めする以下のコマンドを実行しました。
# ▼コマンドで実行
docker compose exec web bin/importmap pin stimulus-autocomplete
JavaScriptライブラリ本体を Importmap にピン留めすることで、ようやくオートコンプリートの準備が整ったと思っていました。
しかし、開発環境では以下のようなエラーが出てしまっています。
エラーの要約としては、
Railsの古いアセット管理システム(Sprockets)が、HTMLで参照されたJavaScriptファイル(@hotwired--stimulus.js)をプリコンパイル対象として認識できず、処理が停止してしまった。
つまり、Sprockets が事前ビルドの対象に入っていない Importmap のアセットを参照したがmanifest.js
に登録されていなかったため、参照できずエラーになった と考えます。
以下がエラー時のapp/assets/config/manifest.js
//= link_tree ../images
//= link_directory ../stylesheets .css
//= link_tree ../../javascript .js
//= link_tree ../builds
根本の原因としては、 Sprockets と Importmap が同時に稼働しており、アセット管理が統一されておらず混在していたことだと考えています。
もちろん最善としては Sprockets ではなく Importmap に統一することが理想ではありますが、現時点ではTailwind CSSや画像などの一部アセットが Sprockets に依存しているため、完全移行は現実的ではありませんでした。
そこで今回は、JavaScriptは Importmap 、CSSと画像は Sprockets という形で責務を分離し、両者の衝突を防ぐ構成に整理することで、問題を解決する方針を取りました。
役割分担してもらう
結論、//= link_tree ../../javascript .js
を削除することで、 Importmap と Sprockets の責務の衝突を防ごうと思います。
この記述は、app/javascript ディレクトリ以下のすべての .js ファイルを Sprockets にリンクしてくれ!という意味で記述しておりました。
しかし、app/javascript は Importmap が管理する領域であり、 Sprockets とは別の仕組みで動いています。
この記述を残すと今回のように、 Sprockets が Importmap の成果物(ピン留めされたライブラリなど)を誤って処理しようとし、エラーの原因になると考えました。
そこで、 JavaScript は Importmap 、CSS/画像は Sprockets という明確な役割分担を行うために削除し、責務の衝突を防ぎます。
//= link_tree ../images
//= link_directory ../stylesheets .css
- //= link_tree ../../javascript .js
//= link_tree ../builds
+ //= link application.js
+ //= link stimulus-autocomplete.js
ここで、//= link application.js
と //= link stimulus-autocomplete.js
記載した理由としては、 Sprockets に存在を認識してもらって本番環境でのエラーを防ぐために記載しています。
※ Importmap タグを未記載だった場合、<%= javascript_importmap_tags %>
をapplication.html.erb
に記載してください。
JavaScriptライブラリをピン留め
最後に以下コマンドで、RailsのImportmap機能を使って Stimulus と stimulus-autocomplete というJavaScriptライブラリを「ピン留め」します。
# ▼コマンドで実行
docker compose exec web bin/importmap pin stimulus
docker compose exec web bin/importmap pin stimulus-autocomplete
ピン留めすることで、Railsはそのライブラリを config/importmap.rb
に登録し、HTMLに <script type="importmap">
として出力できるようにします。
そして、以下コマンドでDocker環境でプリコンパイルテストを行い、エラーなどがないことを確認しました。
# ▼コマンドで実行
docker compose exec web rails assets:precompile
========== DEBUG LOG LEVEL IS SET: debug ==========
Rebuilding...
Done in 1090ms.
INFO -- : Writing /app/public/assets/manifest-xxxx.js
プリコンパイル時に Done in XXXXms.
の表示と、INFO -- : Writing
ログが連続して出力されたことで、すべてのアセットが正常にビルドされ、エラーなく public/assets/
に書き出されたことが確認できました。
念のため、本番環境でもテストを行いました。
# ▼コマンドで実行
docker compose exec web rails assets:precompile RAILS_ENV=production
Rebuilding...
Done in 1106ms.
INFO -- : Writing /app/public/assets/manifest-xxxx.js
本番環境でのプリコンパイルでは、Tailwind CSSのビルドが Done in 1106ms.
で完了し、manifestファイルが正常に出力されました。
Sprockets によるアセット書き出しも INFO -- : Writing ...
のログで確認でき、Importmap との責務分離が構造的に成功していることが証明されたと思います。
最後に
今回のエラーは、Importmap と Sprockets の責務が混在していたことによる構造的な衝突でした。
最善策としては Importmap に完全統一することが理想ですが、現時点では Tailwind CSS や画像など一部のアセットが Sprockets に依存しているため、完全移行は現実的ではありませんでした。
そこで今回は、機能追加に伴い manifest.js
を整理し、JavaScript は Importmap、CSS・画像は Sprockets という形でアセット管理の責務を明確に分離しました。
その結果、開発環境・本番環境ともに安定した構成が実現できたと考えています。
もちろん、より良い別の方法でも解決できる可能性はありますので、本記事はあくまで一事例として参考にしていただければ幸いです。
これからも継続的に学習していきます~