Setup:
# config/importmap.rb
pin "application"
pin "plugin"
// app/javascript/application.js
import "./plugin";
See generated importmap:
$ bin/importmap json
{
"imports": {
"application": "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js",
"plugin": "/assets/plugin-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
}# ^ ^
} # imports urls
# for you for browser
It's pretty simple:
import "plugin";
// will match "plugin" from import-maps
"plugin": "/assets/plugin-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
// and turn it into
import "/assets/plugin-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js";
// browser sends request to this url ^
But:
import "./plugin";
// is relative to `application.js`, because that's where the import is.
// application.js is imported correctly with `import "application"` in the layout
"application": "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js"
// ^^^^^^^^^^^
// so "./plugin" is relative to this, which resolves to "/assets/plugin"
// which doesn't match the import-map
import "/assets/plugin";
// ^
// browser sends request in development and production
Started GET "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js" for 127.0.0.1 at 2023-04-27 00:28:21 -0400
Started GET "/assets/es-module-shims.js-32db422c5db541b7129a2ce936aed905edc2cd481748f8d67ffe84e28313158a.map" for 127.0.0.1 at 2023-04-27 00:28:21 -0400
Started GET "/assets/plugin" for 127.0.0.1 at 2023-04-27 00:28:21 -0400
# ^
# NOTE: see how this one didn't get mapped to anything, it is just a plain url.
In development /assets is routed to sprockets that can handle digested and undigested assets and it works fine.
In production, web server does the work instead and it only has precompiled assets, /assets/plugin gets a 404.
Fix #1
Stop using relative imports.
Fix #2
Make an import-map that would match the relative import:
# config/importmap.rb
pin "application"
pin "/assets/plugin", to: "plugin"
# ^ look familiar?
import "./plugin"; // this will be
import "/assets/plugin" // resolved to this
// and will match the import-map
Started GET "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js" for 127.0.0.1 at 2023-04-27 03:52:47 -0400
Started GET "/assets/plugin-c8122d51d5713808bd0206fb036b098e74b576f45c42480e977eb11b9040f1f4.js" for 127.0.0.1 at 2023-04-27 03:52:47 -0400
Started GET "/assets/es-module-shims.js-32db422c5db541b7129a2ce936aed905edc2cd481748f8d67ffe84e28313158a.map" for 127.0.0.1 at 2023-04-27 03:52:47 -0400
If you want to go this route, I'll borrow @cesoid's helper method, it'll get you started:
# config/importmap.rb
def pin_all_relative(dir_name)
pin_all_from "app/javascript/#{dir_name}",
under: "#{Rails.application.config.assets.prefix}/#{dir_name}",
to: dir_name
end
pin_all_relative "controllers"
# etc