Option 1
Using a CDN url would be the simplest option, because there are a lot of relative imports that would be resolved automatically relative to CDN:
pin "formatDistanceToNow", to: "https://ga.jspm.io/npm:date-fns@4.1.0/formatDistanceToNow.js"

Option 2
If you're feeling iffy about all those requests, use jsdelivr, it seems to do a different kind of bundle for ESM by inlining all the imports:
https://cdn.jsdelivr.net/npm/date-fns@4.1.0/formatDistanceToNow.js/+esm
compared to
https://ga.jspm.io/npm:date-fns@4.1.0/formatDistanceToNow.js
(jspm does flatten all the dependent imports into this one file, so you don't end up with a lot of sequential requests)
# NOTE: /+esm at the end of the url
pin "formatDistanceToNow", to: "https://cdn.jsdelivr.net/npm/date-fns@4.1.0/formatDistanceToNow.js/+esm"

This could get rather bloated if you want to import several functions.
Option 3
Small files and many requests is not a bad thing, it's good for caching and parallel downloads.
Currently, there is no easy way to use importmap-rails
for downloaded modules if they have other imports, as jspm api doesn't provide any information on dependencies (at least, not always). If we're to stick to a true importmap aproach, some manual work is required to resolve dependencies:
# pin.rb
require_relative "./config/application"
require "importmap/packager"
def download url, path
file_path = Pathname.new("vendor/javascript/#{path}") # => "vendor/javascript/date-fns/constructNow.js"
file_path.parent.mkpath # ensure intermediate directories exist
file_path.write(Net::HTTP.get_response(URI(url)).body)
end
package = ARGV.first
packager = Importmap::Packager.new
json = packager.import(package) # => {"date-fns/formatDistanceToNow" => "https://ga.jspm.io/npm:date-fns@4.1.0/formatDistanceToNow.js"}
json.each do |name, url|
# download the main file
download(url, "#{name}.js")
puts %(pin "#{name}", to: "#{name}.js")
base_url = url.match(/.+\//).to_s.chomp("/") # => "https://ga.jspm.io/npm:date-fns@4.1.0"
content = Net::HTTP.get_response(URI(url)).body # => "import{constructNow as o}from\"./constructNow.js\";import{formatDistance as t}from\"./formatDistance.js\"; ...
imports = content.scan(/import.*?"(.+?)"/).flatten # => ["./constructNow.js", "./formatDistance.js", "./constructFrom.js", "./constants.js", "./_/D4S1TYKo.js", ...
imports.each do |import|
url = "#{base_url}/#{import.remove(/^\.\/)}" # => "https://ga.jspm.io/npm:date-fns@4.1.0/constructNow.js"
module_name = name.split("/").first # => "date-fns"
path = import.sub(/^\./, module_name) # => "date-fns/constructNow.js"
# download dependencies
download(url, path)
puts %(pin "/assets/#{path}", to: "#{path}")
end
end
$ ruby ./pin.rb date-fns/formatDistanceToNow
# copy paste these into importmap.rb
pin "date-fns/formatDistanceToNow", to: "date-fns/formatDistanceToNow.js"
pin "/assets/date-fns/constructNow.js", to: "date-fns/constructNow.js"
pin "/assets/date-fns/formatDistance.js", to: "date-fns/formatDistance.js"
pin "/assets/date-fns/constructFrom.js", to: "date-fns/constructFrom.js"
pin "/assets/date-fns/constants.js", to: "date-fns/constants.js"
pin "/assets/date-fns/_/D4S1TYKo.js", to: "date-fns/_/D4S1TYKo.js"
pin "/assets/date-fns/locale/en-US.js", to: "date-fns/locale/en-US.js"
pin "/assets/date-fns/_/BHOttRZ-.js", to: "date-fns/_/BHOttRZ-.js"
pin "/assets/date-fns/_/BkvIkgYg.js", to: "date-fns/_/BkvIkgYg.js"
pin "/assets/date-fns/_/BnFQDOKz.js", to: "date-fns/_/BnFQDOKz.js"
pin "/assets/date-fns/_/xou8AGNM.js", to: "date-fns/_/xou8AGNM.js"
pin "/assets/date-fns/_/DCvnqCw9.js", to: "date-fns/_/DCvnqCw9.js"
pin "/assets/date-fns/toDate.js", to: "date-fns/toDate.js"
pin "/assets/date-fns/_/Dntog4x-.js", to: "date-fns/_/Dntog4x-.js"
pin "/assets/date-fns/compareAsc.js", to: "date-fns/compareAsc.js"
pin "/assets/date-fns/differenceInMonths.js", to: "date-fns/differenceInMonths.js"
pin "/assets/date-fns/differenceInCalendarMonths.js", to: "date-fns/differenceInCalendarMonths.js"
pin "/assets/date-fns/isLastDayOfMonth.js", to: "date-fns/isLastDayOfMonth.js"
pin "/assets/date-fns/endOfDay.js", to: "date-fns/endOfDay.js"
pin "/assets/date-fns/endOfMonth.js", to: "date-fns/endOfMonth.js"
pin "/assets/date-fns/differenceInSeconds.js", to: "date-fns/differenceInSeconds.js"
pin "/assets/date-fns/_/D-sZk5CW.js", to: "date-fns/_/D-sZk5CW.js"
pin "/assets/date-fns/differenceInMilliseconds.js", to: "date-fns/differenceInMilliseconds.js"
pin "/assets/...
allows for relative imports, these have to match an importmap otherwise imports will break in production when using sprockets and won't work at all with propshaft.

This looks worse, because local server is running http/1.1 and, well, ruby. However, we're preloading all those files without waiting for formatDistanceToNow.js
to download, unlike option 1.
Subsequent requests look identical and very cached:
