🌟

Rails 7 でファイルごとに JavaScript を分けて使えるようにする

2022/12/26に公開

Rails 7 では node.js や yarn を使用せずに JS のパッケージ管理をする方向に動いています。
そこで代わりに使用するのが importmap です。
詳しくは以下を参考にさせていただきました。
https://techracho.bpsinc.jp/hachi8833/2022_06_29/112183
https://zenn.dev/takeyuweb/articles/996adfac0d58fb

今回はこれまでの Rails で使用していた assets.precompile を使用せずに、それぞれのファイルごとに JavaScript ファイルを紐付ける方法を記します。

概要

目的

  • Rails 7 で importmap を使用して JavaScript を使用する
  • ファイル個別に JavaScript を効かせる

前提

  • yarn などは使用せず importmap を使用する

手順

importmap でファイル毎に javaScript を使用できるようにする

まずは前提として Rails 7 では環境構築した段階で以下ファイルから JS を使用することが可能です。

app/javascript/application.js
console.log("JS 使えてるねん!");

個別にファイルを作ってみる。。。

app/javascript/top/js
+ console.log("JS 使えてまっか?")

↑↑ 今回は View のtop/index.html.erbというファイルに JS を適用させたいので、ディレクトリ名とファイル名を揃えました。
もちろんこれだけではtop/index.html.erb側にはこのファイルの JS は適用されていません。

ここで使用するのが「importmap」です。
importmap のファイルに以下のよう「top/index」をピン留めします。

config/importmap.rb
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
+ pin "top/index"

ピン留めをすることで HTML の Head にあるimportsに以下のように追加されます。

あとはこれをtop/indexのファイルで呼び出すように書けば機能するはずです。
以下の通りjavascript_importmap_tagsという箇所で、importmap を呼び出しています。
この下にyield(:js)を追記します。

app/views/layouts/application.html.erb
<%= javascript_importmap_tags %>
+     <%= yield(:js) %>

そして呼び出し元であるファイルに以下を追記します。

app/views/top/index.html.erb
+ <% content_for :js do %>
+   <%= javascript_import_module_tag "top/index" %>
+ <% end %>

すると、無事に console.log が表示されました!

上記ではtop/indexという JS ファイルを指定しているので、それが反映されます。
なので、他のページではここを変更してやればよいわけです。

また、top ディレクトリ以下のファイルに同じ JS を適用させたい時は inportmap を以下のように編集してやります。

config/importmap.rb
- pin "top/index"
+ pin_all_from "app/javascript/top", under: "top"

合わせて以下も変更

app/views/top/index.html.erb
<% content_for :js do %>
-   <%= javascript_import_module_tag "top/index" %>
+   <%= javascript_import_module_tag "top" %>
<% end %>

これでtop/showなどでも同じ JS が適用されます!

まとめ

ファイル個別に適用する場合

config/importmap.rb
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
+ pin "top/index"
app/views/layouts/application.html.erb
<%= javascript_importmap_tags %>
+     <%= yield(:js) %>
app/views/top/index.html.erb
+ <% content_for :js do %>
+   <%= javascript_import_module_tag "top/index" %>
+ <% end %>

ディレクトリ全体に適用する場合

config/importmap.rb
pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
+ pin_all_from "app/javascript/top", under: "top"
app/views/layouts/application.html.erb
<%= javascript_importmap_tags %>
+     <%= yield(:js) %>
app/views/top/index.html.erb
+ <% content_for :js do %>
+   <%= javascript_import_module_tag "top" %>
+ <% end %>

お疲れ様でした◎

Discussion