Struggling with Javascript configuration

I’m coming back to Rails (7.1) after a long hiatus from it and I’m struggling a bit with how to configure Javascript for my purposes. I’ve tried using importmap-rails (the default) and also jsbundling-rails using Bun. Neither is working for my case.

I guess I’m trying to confirm here is:

    1. Am I doing this idiomatically?; and, if so;
    1. How am I messing up here?

I’m trying to create a set of shared partials that I can use as reusable “components” across different pages. Some of these need Javascript.

My partials are stored under views/shared and the associated js is under javascript/shared.

To use an example, say Header, I would create a view/shares/_header.html.erb and a javascript/shared/header.js file.

header.js would have a class like export default Header { ... } and I want to consume that class inside _header.html.erb.

Using the importmaps path, I’ve added import "shared" to application.js and pin_all_from "app/javascript/shared", under: "shared" to importmap.rb.

Using the jsbundling path, I add import "./shared" to application.js and I create a javascript/shared/index.js for the module that contains import Header from "./header". I’ve also tried exporting from the index.js and also application.js. I tried multiple variations of the above and other things too.

Whenever I try to instantiate Header from the partial I get the following error: Uncaught ReferenceError: Header is not defined. It feels like the class is being bundled correctly as I can see it in the outputted bundle, etc, but Rails can’t see the class.

What am I doing wrong!?

Thanks in advance.

fwiw: I have javascript/custom/main.js in javascript/ I have: import “custom/main”; in application.js and in importmap.rb I have: pin_all_from “app/javascript/custom”, under: “custom”

Can you be more explicit about what you’re doing in the partial? In general I would shy away from using JS in your HTML—it should be tucked away in a Stimulus controller.

For example, in my importmap.rb I have:

pin_all_from "app/javascript/lib", under: "lib", to: "lib"

In app/javascript/lib/debounce.js I have:

function debounce(func, timeout = 25) {
  let timer
  return (...args) => {
    clearTimeout(timer)
    timer = setTimeout(() => func(...args), timeout)
  }
}

export { debounce }

And then in a Stimulus controller I can import and use it:

import { Controller } from "@hotwired/stimulus"
import { debounce } from "lib/debounce"

export default class extends Controller {
  connect() {
    const broadcast = debounce((event) => this.element.dispatchEvent(event))
  }
  …
}
1 Like