ビューファイル毎に読み込ませるjsファイルを変えたい

ビューファイル毎に読み込ませるjsファイルを変えたい

ビューファイル毎に読み込ませるjsファイルを分ける方法を自分の備忘録として、こちらにまとめます。
Railsでは、アセットパイプラインによりマニフェストファイルからアセット(CSSファイルやJSファイル)をまとめて読み込み、アセットをまとめて読み込んでいるマニフェストファイルをレイアウトファイルで読み込んでいるというロジックになっている為、特定のページでのみで使用するjsファイルも違うページで読み込んでしまい存在しないDOMに対してaddEventListenerなどが実行されてしまい開発者ツール上で以下のようなエラーになってしまう。

Image from Gyazo

これの解決方法としては、ビュー毎に読み込むjsファイルを分ければ良い。
方法は、以下のようになります。

現時点では、以下のようになっています。
app/javascriptsフォルダ以下にそれぞれの機能毎のjsファイルが以下のように存在します。

Image from Gyazo

上記の機能毎のjsファイルを以下のようにマニフェストファイルで読み込んでいる。

[app/javascript/packs/application.js]

// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require('jquery')
require("@rails/ujs").start()
require("@rails/activestorage").start()
require("channels")
require('bootstrap')

import 'bootstrap';
import '@fortawesome/fontawesome-free/js/all';
import '../javascripts/search_cooking_select_box';       # ここで読み込んでいる
import '../javascripts/search_calculate_cooking_time_select_box';       # ここで読み込んでいる
import '../javascripts/search_cooking_memory';           # ここで読み込んでいる
import '../javascripts/image_preview';             # ここで読み込んでいる
window.$ = $;
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

上記のマニフェストファイルを以下のようにレイアウトファイルで読み込んでいる。

[app/views/layouts/application.html.slim]

doctype html
html
  head
    title = page_full_title(yield(:title))
    = csrf_meta_tags
    = csp_meta_tag
    = stylesheet_link_tag 'application', media: 'all'        ここでCSSのマニフェストファイルを読み込んでいる
    = javascript_pack_tag 'application'       ここでJava Scriptのマニフェストファイルを読み込んでいる
  body
    - if logged_in?
      = render partial: 'shared/after_login_header'
    - else
      = render partial: 'shared/before_login_header'
    = render partial: 'shared/flash_message'
    = yield

このような過程で全てのビューファイルで全てのjsファイルが読み込まれてしまっている為、以下のように変更する。

まず以下のようにマニフェストファイルから特定のビューでしか使用しないjsファイルを削除する。

[app/javascript/packs/application.js]

// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require('jquery')
require("@rails/ujs").start()
require("@rails/activestorage").start()
require("channels")
require('bootstrap')

import 'bootstrap';
import '@fortawesome/fontawesome-free/js/all';
# ここで読み込んでいたビュー毎のjsファイルを削除

window.$ = $;
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

レイアウトファイル(app/views/layouts/application.html.slim)からは、そのままマニフェストファイルを読み込むようにする。

[app/javascript/packs]フォルダ以下に以下のように自分でマニフェストファイルを作成する。

Image from Gyazo

以下のように作成したマニフェストファイルからビュー毎に使用するjsファイルを読み込む。

[app/javascript/packs/image_preview.js]

import '../javascripts/image_preview';
[app/javascript/packs/search_calculate_cooking_time_select_box.js]

import '../javascripts/search_calculate_cooking_time_select_box';
[app/javascript/packs/search_cooking_memory.js]

import '../javascripts/search_cooking_memory';
[app/javascript/packs/search_cooking_select_box.js]

import '../javascripts/search_cooking_select_box';

※読み込むjsファイルは相対パスで記載する必要がある。

上記のようなマニフェストファイルを以下のようにjsを使用するビューファイル毎で直接読み込むようにする。

[app/views/cooking_informations/index.html.slim]

= javascript_pack_tag 'search_cooking_select_box'
= content_for(:title, (t '.title'))
.search-wrapper
  .container
    .row.justify-content-md-center
      .col-md-10
        = search_form_for @q, url: cooking_informations_path do |f|
          .mt-4
            = f.collection_select :fish_kind_eq, @fishes, :kind, :kind, { include_blank: "#{t 'defaults.search_for_fish'}" }, {class: 'search-select-form'}
            = f.collection_select :handle_pattern_eq, @handles, :pattern, :pattern, { include_blank: "#{t 'defaults.search_for_fish'}" }, {class: 'search-select-form'}
            = button_tag type: 'submit', class: 'btn btn-primary search-button' do
              i.fas.fa-search
    = render @cooking_informations
    = paginate @cooking_informations

これで使用するビューファイルだけでjsファイルを読み込むようになるため、開発者ツールでもエラーにならなくなる。

Image from Gyazo

参考記事

webpacker でページごとにスタイルを分ける - Qiita

WebpackerでJavaScriptを使ってハマった話 - sasaboの生活

Webpacker::Manifest::MissingEntryErrorの対処法 | ゆみしん夫婦のブログ

Railsで特定のページのみJavaScriptを読み込む方法を現役エンジニアが解説【初心者向け】 | TechAcademyマガジン

Rails6で、アプリの特定のビューでJavaScriptを動かす。 : リア充キラキラ系のnoteです。@kuromitsu_ka

javascript — ビューごとのJavaScriptファイルRails

http://www.code-magagine.com/?p=4609

Railsでページごとのscssを管理する方法 -- blog.10rane.com

Ruby on Rails のアセットパイプラインの挙動を環境ごとに学ぶ - 30歳からのプログラミング

RailsでcssファイルとJavascriptファイルをマニフェストファイルから読み込む | Boys Be Engineer 非エンジニアよ、エンジニアになれ

Railsのマニフェストファイルを使ったJsとStylesheetの呼び出し - Qiita