概要
Deno では npm: 形式の URL により npm モジュールを読み込むことができます。このモジュールの指定は import maps でも用いることができる一方、接頭辞マッピング (package/... を npm:package/... にマッピングする) を行うためには URL の形式に注意が必要です。
結論
理由は後述しますが、npm:/ に続く形 (例: npm:react ではなく npm:/react) でモジュールを指定することで接頭辞マッピングを行うことができます。
{
"imports": {
"module/": "npm:/module/",
"another-module/": "npm:/@someone/another-module@1.0.0/"
}
}
Deno での npm パッケージの読み込み
Deno は npm パッケージの読み込みに対応しており、パッケージを npm: URL で指定します。例えば
import { React } from 'npm:react@18.3.1';
とすれば React を読み込めます。
import maps の接頭辞マッピング
MDN のページ より具体例を引用しますが、import maps は key と value の両方を / で終えることで接頭辞マッピングが可能です。
{
"imports": {
"square": "./module/shapes/square.js",
"circle": "https://example.com/shapes/circle.js",
"shapes/": "./module/shapes/",
"othershapes/": "https://example.com/modules/shapes/"
}
}
import 'square';
import 'cicle';
import 'shapes/foo.js';
import 'othershapes/bar.js';
Deno の import maps での接頭辞マッピング
この接頭辞マッピングは Deno の import maps でも利用可能です。ただし、npm: URL に関しては以下のような接頭辞マッピングを行うとエラーが発生します。
{
"imports": {
"module/": "npm:module/"
}
}
error: Failed to resolve the specifier ""module/foo.js"" as its after-prefix
portion ""foo.js"" could not be URL-parsed relative to the URL prefix
"npm:module/" mapped to by the prefix "module/"
at ...
これは次のように npm:/ に続く形にすることで修正可能です。
{
"imports": {
"module/": "npm:/module/"
}
}
なお、通常のインポートで npm:module/foo.js は許可されます。
理由
これは npm スキームの URL のパース方法がインポートの解決時と import maps の解決時で異なるためです (何で?)。前述の公式ドキュメント には npm URL の文法が定義されています。
npm:<package-name>[@<version-requirement>][/<binary-name>]
一方 URL の仕様である RFC 1630 の定義では <scheme>:<path> のように定められており、<path> の部分は <scheme> によって変わります (/ がセパレータであることだけが定められています)。
ソースを見ていないので推測ですが、Deno が import maps を解決する際には <path> の部分をいわゆる path.resolve のように解決しているため / で始まらないときに有効なパスと認識されていないと考えられます。