[importmap-rails] ネストされたパッケージパスの正確な識別処理を実装
背景
importmap-railsでは、JavaScriptパッケージのバージョン管理を行う際、パッケージ名をURLから抽出する処理が実装されています。しかし、photoswipe/lightbox や @github/webauthn-json/browser-ponyfill のようなネストされたパスを持つパッケージに対して、パッケージ名の識別が正しく機能していませんでした。
この問題により、outdated版のチェック時に誤ったパッケージ名で検索が行われ、バージョン比較が正常に動作しないという課題が発生していました(#321)。
技術的な変更内容
パッケージ名抽出ロジックの追加
lib/importmap/npm.rb に新しいプライベートメソッド extract_base_package_name が追加されました。このメソッドは、ネストされたパスを持つパッケージから、ベースとなるパッケージ名を正確に抽出します。
def extract_base_package_name(package)
if package.start_with?("@")
# Scoped packages can have nested paths, e.g. @scope/package/subpath
parts = package.split("/", 3)
parts.size > 2 ? parts.first(2).join("/") : package
else
# Non-scoped packages - just take the first part
package.split("/").first
end
end
このロジックは以下の2つのケースを処理します:
-
スコープ付きパッケージ(
@で始まる):最初の2つのパートを結合してパッケージ名とする-
@github/webauthn-json/browser-ponyfill→@github/webauthn-json -
@github/webauthn-json→@github/webauthn-json(変更なし)
-
-
通常のパッケージ:最初のパートのみを取得
-
photoswipe/lightbox→photoswipe -
photoswipe→photoswipe(変更なし)
-
packages_with_versionsメソッドの改良
抽出されたパッケージ名とバージョンのペアに対して、新しいロジックを適用し、重複を排除する処理が追加されました。
with_versions.map! do |package, version|
[extract_base_package_name(package), version]
end.uniq!
この変更により、同一パッケージの異なるサブパスが複数存在する場合でも、ベースパッケージ名として1つにまとめられます。
実際の動作例
ネストされたパスを持つパッケージの場合
Importmap定義:
pin "photoswipe/lightbox", to: "https://ga.jspm.io/npm:photoswipe@5.4.4/dist/photoswipe-lightbox.esm.js"
pin "photoswipe", to: "https://ga.jspm.io/npm:photoswipe@5.4.4/dist/photoswipe.esm.js"
変更前: photoswipe/lightbox と photoswipe が別々のパッケージとして認識される
変更後: 両方とも photoswipe@5.4.4 として正しく認識され、outdatedチェックが正常に機能する
スコープ付きパッケージのネストされたパスの場合
pin "@github/webauthn-json/browser-ponyfill", to: "https://ga.jspm.io/npm:@github/webauthn-json@2.1.1/dist/esm/webauthn-json.browser-ponyfill.js" # @2.1.1
変更後: @github/webauthn-json@2.1.1 として正しく識別され、npmレジストリへの問い合わせが正常に行われる
テストカバレッジ
今回の変更では、以下のケースに対する包括的なテストが追加されています:
- ネストされたパッケージパスの抽出
- バージョンコメント付きネストパッケージの処理
- スコープ付きパッケージのネストパス処理
- 通常のスコープ付きパッケージの処理
- outdatedチェックの正常動作
これにより、様々なパッケージ構造に対する堅牢性が確保されました。