Search code examples
ruby-on-railsasset-pipelinestimulusjsimport-maps

Rails 7 sharing stimulus controller functions


I'm trying to share stimulus controller functions with other controllers but the files are not being found because of the asset pipeline digest.

Parent (app/javascript/controllers/a_shared_controller.js)

import {Controller} from "@hotwired/stimulus"

export default class extends Controller {
  // some shared functions
}

Child

import Controller from "./a_shared_controller"

This works fine in development. What's the best way to do this?

Thanks!


Solution

  • Don't use relative imports. When you pin all controllers like this:

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

    You get these import-maps generated:

    <script type="importmap" data-turbo-track="reload">{
      "imports": {
        "controllers/application":      "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
        "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
        "controllers":                  "/assets/controllers/index-ed00704a3bfd9aebb7c818233ee5411c3ce8050f411b77ec27c4252ded99a59c.js",
      }
    <!-- ^ this is what you can import -->
    }</script>
    

    application.js would be an example of a shared file, it is imported in index.js:

    import { application } from "controllers/application"
    //                           ^
    // NOTE: the name of the generated importmap is used to import
    

    If you add another file, don't add _controller.js as it would load automatically in index.js (unless that's what you want).


    I have another answer explaining why relative paths don't work and how to maybe make them work:
    https://stackoverflow.com/a/73136675/207090