You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Roadmap: reliability and performance as first-class citizens
Problem / Goal
importmap-plus already does what importmap-rails does plus minification, esm.run bundles, version locks and provenance. Two things still make an app depend on a CDN at runtime or on a developer's vigilance:
No verification, no fallback, no tuning. jspm 404s or lags npm and pin just gives up; a remote pin ships without an integrity hash; nothing checks the app's import map before a page does; every preload: true pin is preloaded on every page (a real app had to hand-write preload: false on apexcharts/core to stop 1.1 MB per page); modulepreload links wait for the HTML.
Done looks like: bin/importmap pin always ends with a working pin — vendored with its whole file graph when it can be, remote with a recorded reason and an integrity hash when it can't, from whichever CDN can actually serve the registry's latest — bin/importmap doctor proves the app's map in CI, and the page preloads what it will use, as early as the server allows.
The pieces, in execution order
#
Issue
Layer
Depends on
1
#14 pin keeps a package remote when its file can't stand alone, and says why
CLI + Packager
— (bumps VERSION to 1.2.0)
2
#15 registry-latest resolution and jspm → esm.run → jsdelivr fallback
Each child issue is self-contained: context files, the decision with rejected alternatives, ordered TDD steps, verification gates, out-of-scope. Run them one at a time with /lfg <number>; each is one PR.
Upstream-owned files get additive edits only (packager.rb is at its 551-line limit — new behaviour goes in fork-only collaborators: module_inspector.rb, provider_chain.rb, integrity.rb, package_graph.rb, import_scanner.rb, doctor.rb, graph.rb, early_hints.rb). Upstream style in upstream files.
Pins this gem writes stay readable by importmap-rails: the new provenance details (remote: <reason>, (graph of <pkg>)) are comments; pin_all_from for graph files is upstream's own DSL.
Live tests (test/commands_test.rb) only for a new CDN contract or a new printed sentence; exact versions; one runner at a time.
Docs: the pages each child names, plus after pin vendors a package whole file graph, so chunked packages no longer need a CDN #17 a new page "Multi-file packages" under the Vendoring group (cd docs && bin/rails g docs_kit:page "Multi-file packages" --group=Vendoring) that tells the whole story: detection → reasons → graph vendoring → --vendor / --remote → doctor.
Settled in interview (do not re-litigate)
Epic + child issues, executed in order.
Reason recorded in the provenance comment: # @<ver> (remote: <reason>), detail order provider, minified, remote, locked.
Phase 2 vendors the file graph (flat entry + vendor/javascript/<pkg>/ directory + one pin_all_from line with relative imports rewritten to bare keys), not a public/ mirror.
Fallback is automatic: registry latest first, then jspm → esm.run → jsdelivr; --from disables it.
Roadmap scope: doctor, remote SRI, graph-aware preloading, Early Hints — all in.
Upstream-first notes
#19 (graph-aware preloading) and #20 (Early Hints) are not fork-specific; propose them to rails/importmap-rails after they land here so the next sync shrinks the diff. #14, #15, #16, #17, #18 lean on fork provenance or on behaviour upstream has declined.
Evidence
Live probe (2026-09-12) of jspm's generate API and downloads for 20 packages; crawl of lodash-es (464 files), date-fns (258), @popperjs/core (48) — closed sets matching jspm's staticDeps.
Propshaft::Compiler::JsAssetUrls rewrites only RAILS_ASSET_URL(); Sprockets rewrites nothing — relative imports in digested files can't work without the CLI rewriting them.
Roadmap: reliability and performance as first-class citizens
Problem / Goal
importmap-plus already does what importmap-rails does plus minification, esm.run bundles, version locks and provenance. Two things still make an app depend on a CDN at runtime or on a developer's vigilance:
import"./_/f08a6ffe.js",from"../_/f09ec963.js",import('../photoswipe.js')),pdfjs-distalso spawnsnew Worker(…),ace-buildstoo, and 2 (@mui/material,mermaid) don't resolve on jspm at all.pinvendors the entry anyway and the browser 404s on the siblings. Upstream calls this expected behaviour (Relative paths in importmaps js default to my domain rails/importmap-rails#295, Supporting package directory downloads rails/importmap-rails#302 open since 2024, Download all the files associated with a package from a CDN rails/importmap-rails#235 stalled on Propshaft not rewriting imports). An app on this gem is holding@basis-theory/web-elementsat 2.x for exactly this reason.pinjust gives up; a remote pin ships without an integrity hash; nothing checks the app's import map before a page does; everypreload: truepin is preloaded on every page (a real app had to hand-writepreload: falseonapexcharts/coreto stop 1.1 MB per page); modulepreload links wait for the HTML.Done looks like:
bin/importmap pinalways ends with a working pin — vendored with its whole file graph when it can be, remote with a recorded reason and an integrity hash when it can't, from whichever CDN can actually serve the registry's latest —bin/importmap doctorproves the app's map in CI, and the page preloads what it will use, as early as the server allows.The pieces, in execution order
VERSIONto 1.2.0)bin/importmap doctorconfig.importmap.preload_strategy = :reachable)Each child issue is self-contained: context files, the decision with rejected alternatives, ordered TDD steps, verification gates, out-of-scope. Run them one at a time with
/lfg <number>; each is one PR.Rules that apply to every child
Importmap::VERSIONmoves once: pin keeps a package remote when its file cannot stand alone, and says why #14 sets it to1.2.0and commitsGemfile.lock+docs/Gemfile.lock; no later child bumps it.UPSTREAM_VERSIONis untouched.CHANGELOG.md: every child adds under## 1.2.0→### Added(create the heading in pin keeps a package remote when its file cannot stand alone, and says why #14).packager.rbis at its 551-line limit — new behaviour goes in fork-only collaborators:module_inspector.rb,provider_chain.rb,integrity.rb,package_graph.rb,import_scanner.rb,doctor.rb,graph.rb,early_hints.rb). Upstream style in upstream files.with_retries; no network on the request path (Graph-aware preloading: preload what the entry point actually reaches #19 reads local files only, cached like the JSON; javascript_importmap_tags sends modulepreload links as 103 Early Hints #20 sends a header).remote: <reason>,(graph of <pkg>)) are comments;pin_all_fromfor graph files is upstream's own DSL.test/commands_test.rb) only for a new CDN contract or a new printed sentence; exact versions; one runner at a time.cd docs && bin/rails g docs_kit:page "Multi-file packages" --group=Vendoring) that tells the whole story: detection → reasons → graph vendoring →--vendor/--remote→doctor.Settled in interview (do not re-litigate)
# @<ver> (remote: <reason>), detail orderprovider, minified, remote, locked.vendor/javascript/<pkg>/directory + onepin_all_fromline with relative imports rewritten to bare keys), not apublic/mirror.--fromdisables it.Upstream-first notes
#19 (graph-aware preloading) and #20 (Early Hints) are not fork-specific; propose them to rails/importmap-rails after they land here so the next sync shrinks the diff. #14, #15, #16, #17, #18 lean on fork provenance or on behaviour upstream has declined.
Evidence
staticDeps.Propshaft::Compiler::JsAssetUrlsrewrites onlyRAILS_ASSET_URL(); Sprockets rewrites nothing — relative imports in digested files can't work without the CLI rewriting them.map.integritywhen asked; Remote pins get a subresource-integrity hash when they are written #16 hashes locally instead so every provider is covered.Execution
Start with
/lfg 14.