Skip to content

Respect remote URL pins and preserve pin options in bin/importmap - #327

Open
mhenrixon wants to merge 1 commit into
rails:mainfrom
zoolutions:feat/respect-remote-url-pins
Open

Respect remote URL pins and preserve pin options in bin/importmap#327
mhenrixon wants to merge 1 commit into
rails:mainfrom
zoolutions:feat/respect-remote-url-pins

Conversation

@mhenrixon

Copy link
Copy Markdown

Problem

Running bin/importmap pin pkg@x.y.z (or update) rewrites every pin in the jspm response — including transitive dependencies — from scratch:

  1. preload: false is wiped on every bump. The new pin line is built solely from the CLI's --preload flag, so options on existing pins (and on every dependency that happens to be in the response) are lost. update preserved preload for directly-requested packages, but pin never did, and dependencies were always clobbered.
  2. Hand-written remote URL pins are replaced with downloads. A pin like pin "pkg", to: "https://ga.jspm.io/npm:pkg@1.0.0/index.js" is silently converted to a vendored download the next time the package is pinned, updated, or pulled in as a dependency.

Changes

pin_package now looks at the existing pin before writing:

  • Options are preserved on rewrite. The existing pin's preload value survives pin/update unless --preload is passed explicitly. This applies to dependencies re-pinned along the way, not just requested packages.
  • Remote URL pins stay remote. If the existing pin's to: is an https:// URL:
    • Known CDN hosts (ga.jspm.io, unpkg.com, cdn.jsdelivr.net, cdn.skypack.dev, esm.sh) are re-resolved from the same provider at the new version — a jsdelivr pin updates to a new jsdelivr URL even though resolution goes through jspm.
    • Unknown/custom hosts are left completely untouched, with a Skipping "pkg" pinned to custom URL ... notice.
    • If the provider can't resolve the package (e.g. Skypack is no longer resolvable through the jspm generator), the existing pin is kept with a notice instead of being clobbered.
  • New --remote flag on pin creates URL pins without downloading (pin "react", to: "https://ga.jspm.io/npm:react@19.1.0/index.js"), and removes the previously vendored file when converting an existing vendored pin.
  • pristine skips remote pins — there is nothing to redownload.
  • Supporting fixes: the npm version scan now recognizes esm.sh URLs (including its * external-deps prefix), and version extraction keeps prerelease suffixes (@2.0.0-beta.19 no longer truncates to @2.0.0).

An explicit integrity: value is still dropped when a pin's URL changes (unchanged policy — the stale hash would break the page).

Notes

  • The test asserting that update strips to: from URL pins encoded exactly the behavior this fixes, so it is inverted; the Skypack test fixtures were moved to jsdelivr since Skypack no longer resolves through the generator.
  • Gemfile.lock is synced with the 2.2.3 version bump from Prepare for 2.2.3 (the lock still said 2.2.2) and picks up the arm64-darwin-24 platform.
  • README documents the new behavior under "Pinning to remote CDN URLs".

Testing

Full suite passes: 112 runs, 0 failures. The commands tests run bin/importmap as a subprocess against the live jspm API and assert on the resulting config/importmap.rb, covering: remote pins surviving pin/update, dependency options surviving a bump, --remote creation and vendored→remote conversion, custom-host pins left byte-identical, and pristine skipping remote pins.

Pinning or updating a package rewrote every pin in the jspm response
(including transitive dependencies) with default options, wiping
preload: false and replacing hand-written remote URL pins with
vendored downloads.

- pin_package now extracts the existing pin's options first: preload
  survives any rewrite unless --preload is passed explicitly
- pins with to: "https://..." stay remote: the URL is re-resolved from
  the same CDN provider (ga.jspm.io, unpkg.com, cdn.jsdelivr.net,
  cdn.skypack.dev, esm.sh); unknown hosts are left untouched with a
  notice; failed provider resolution keeps the existing pin
- new --remote flag on pin creates URL pins without downloading and
  removes a previously vendored file when converting
- pristine skips remote pins (nothing to redownload)
- npm version scan recognizes esm.sh URLs (incl. the * prefix) and
  version extraction keeps prerelease suffixes (@2.0.0-beta.19)
- Gemfile.lock synced with the 2.2.3 version bump
@elalemanyo

Copy link
Copy Markdown

We’re running into this issue in practice while using thoughtbot/importmap-update for automated dependency updates.

Some existing pin attributes (for example preload: false) can disappear when dependencies are updated, which can result in unintended changes to the importmap configuration.

Would be great to get this merged, as it would make automated dependency updates much safer and more reliable for us.

Thanks @mhenrixon for putting together the fix! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants