Stimulus Libraries not loading in production mode

I’ve been setting up a new app, without webpack and using the asset pipeline. Turbo + stimulus.

I have a folder for a library that I created for some common page functions, CSS functions, etc. Took me a while, but I successfully got it working and everything importing in dev. It’s structured like so:

  • app / assets / javascripts
    • controllers - normal controllers here
    • libraries
      • sm - my library folder
        • sm.js - entry point that exports my functions.

In my controller, I reference my sm.js exports with a normal import:

import {Animation, CSS} from 'sm'

Works great in dev. Once I deploy to production (Heroku) or run it locally with RAILS_ENV=production, the autoloader cannot find my sm library at all. In the console it generates the usual errors when it can’t find a library. BUT:

  1. public/assets/libraries has the files I expect generated from the precompile
  2. public/assets/importmap.json has all the files I would expect listed, and the paths with the randomly generated strings all exist.

So basically, there is something not joining up somewhere but I’m not sure why and not sure what to look at next.

Update
One thing I didn’t explain above is that my sm.js file also includes two files animation.js and css.js that are in the same folder. Just now looking at the browser console it appears that Importmap IS loading the sm.js file fine, but when that file tries to import its dependencies, it using the base filename and NOT including the asset precompiled file name with the unique code.

I’m guessing that I need to convert sm.js into sm.js.erb, and use <% asset_path %> to reference those included files?

Leaving this question up and giving an answer for future searchers.

If you have a case where you are importing libraries and those libraries are importing your own files within the libraries folder, then you have to provide the asset path on those imports, not just the base path like you would expect. It’ll work fine in dev, but not production. Example:

In my sm.js file I had code like so:

import Animation from './animation'
import CSS from './css'
export { Animation, CSS }

I had to make sm.js into sm.js.erb, and change the import paths to look like this:

import Animation from '<%=asset_path "libraries/sm/animation.js" %>'
import CSS from '<%=asset_path "libraries/sm/css.js" %>'
export { Animation, CSS }

Then if you look at your precompiled assets you’ll notice that rails has replaced those paths with the full generated path to the file in your public/assets folder.

1 Like

I just solved this problem in my code for heroku deployment.

The key is, don’t use relative links in your imports!

You have your ESM js file at
/assets/javascripts/libraries/sm/sm.js
so you must import like:
import {Animation, CSS} from 'sm/sm'

Likewise, you must change your statements like:
import Animation from './animation'
to
import Animation from 'sm/animation'

My commit that fixed my issues by letting hotwire/stimulus create the import map and point to the appropriate files.