Rails 7 using custom js in specific pages

Viewed 264

Having adapted the hotwire mechanism for rails 7, problems arise for custom JS that are dependency-less. in this case, a JS that is not mapped to a given source.

Added to importmap.rb:

pin_all_from "app/javascript/plugin", under: "plugin"

which does render

    <script type="importmap" data-turbo-track="reload">{
  "imports": {
    "application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
    "@hotwired/turbo-rails": "/assets/turbo.min-e5023178542f05fc063cd1dc5865457259cc01f3fba76a28454060d33de6f429.js",
    "@hotwired/stimulus": "/assets/stimulus.min-900648768bd96f3faeba359cf33c1bd01ca424ca4d2d05f36a5d8345112ae93c.js",
    "@hotwired/stimulus-loading": "/assets/stimulus-loading-1fc59770fb1654500044afd3f5f6d7d00800e5be36746d55b94a2963a7a228aa.js",
    "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
    "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
    "controllers": "/assets/controllers/index-2db729dddcc5b979110e98de4b6720f83f91a123172e87281d5a58410fc43806.js",
    "plugin/auto-complete": "/assets/plugin/auto-complete-813c8033519c4886434d3f867f4159971e0d46aca097d6706580f5042f78d4ec.js"
  }

Also note that I made the mistake of running ./bin/rails javascript:install:esbuild which leads to unnecessary pollution of the header and do not know how to un-do this (indictions not provided with the gem)

<script type="esms-options">{"nonce":null}</script>
<script src="/assets/es-module-shims.min-b8099fffdbd758070d4801321d43b389c5b6174a50782f9f4cb57061533b7ac2.js" async="async" data-turbo-track="reload"></script>

could this be a factor in impeding the eventual loading of the script?

Apparently, a declaration is required to have it load: <%= javascript_import_module_tag "plugin" %>. While the preference is to load it on the action that requires it, this was added to the application.html.erb file.

To no avail.
The script runs only if the raw script is included in the action's view.

Is there a more succinct manner to load such a script as necessary?

Update

The suggestion provided by @alex appears in the right direction, however, a greater issue exists for the browser, with a fresh application creation, pushing the situation into a different question.
FF version required an ImportMap enabling under about:config which then rendered the same situation as Chrome: FF console

module spec The same error arises when substituting the pin_all_from command with
pin("plugin/auto-complete")

Chrome: chrome console

Thus the building tool is working in an unexpected manner under pin_all_from and pin with

<% content_for :head do %>
  <%= javascript_import_module_tag "plugin/autocomplete" %>
<% end %>
1 Answers

You can only import the pins that you have:

<%= javascript_import_module_tag "plugin/auto-complete" %>

To import modules only on specific pages:

# app/views/layouts/application.html.erb

<%= javascript_importmap_tags %>

# NOTE: Add this below importmaps
<%= yield(:head) %>
# app/views/users/index.html.erb

# NOTE: now you can add things to layout from specific templates

<% content_for :head do %>
  <%= javascript_import_module_tag "plugin/auto-complete" %>
<% end %>

To undo esbuild install, you can undo these steps manually, unless you're actually using jsbundling-rails for something else (like tailwind or cssbundling):

create  app/assets/builds
append  app/assets/config/manifest.js
# //= link_tree ../builds
append  .gitignore
# /app/assets/builds/*
# !/app/assets/builds/.keep
#
# /node_modules
insert  app/views/layouts/application.html.erb
# <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %>
create  package.json
create  Procfile.dev
   run  gem install foreman
create  bin/dev

Update Let's try again.

$ rails -v                                                                                                                                                                   
Rails 7.0.3.1
$ rails new my_app
$ cd my_app
$ bin/rails g scaffold Test
$ bin/rails db:migrate
# app/layouts/application.rb
# add below javascript_importmap_tags
<%= yield :head %>

# app/views/tests/index.html.erb
<% content_for :head do %>
  <%= javascript_import_module_tag "plugin/autocomplete" %>
<% end %>
<script type="text/javascript">console.log("loaded first")</script>

# app/javascript/plugin/autocomplete.js
console.log("autocomplete loaded");

# config/importmap.rb
pin_all_from "app/javascript/plugin", under: "plugin"
$ bin/rails s

Go to http://localhost:3000/tests. Open up the console:

autocomplete loaded                  autocomplete-d4e6a...8d3b403ce5.js:1 

Should be easy as that.


https://github.com/rails/importmap-rails#selectively-importing-modules

My little explanation of pin_all_from and pin How to add custom JS file to new rails 7 project

Related