一般的なパターン マッチングのユースケースを標準化するアプローチ。
背景
ルーティングは、すべてのウェブ アプリケーションの重要な要素です。基本的にルーティングでは、URL を取得してパターン マッチングやその他のアプリ固有のロジックを適用し、通常はその結果に基づいてウェブ コンテンツを表示します。ルーティングはさまざまな方法で実装できます。たとえば、ディスク上のファイルにパスをマッピングするサーバーで実行されるコードや、現在の位置の変更を待機して、表示する DOM の対応する部分を作成するシングルページ アプリのロジックなどです。
明確な標準はありませんが、ウェブ デベロッパーは、URL ルーティング パターンを表現するための共通の構文を重視しています。regular expressions
と多くの共通点がありますが、一致するパスセグメント用のトークンなど、ドメイン固有の要素もいくつかあります。Express や Ruby on Rails などの一般的なサーバーサイド フレームワークでは、この構文(またはそれに非常に近い構文)が使用されます。JavaScript デベロッパーは、path-to-regexp
や regexpparam
などのモジュールを使用して、そのロジックを独自のコードに追加できます。
URLPattern
は、これらのフレームワークによって作成された基盤の上に構築されたウェブ プラットフォームの追加機能です。ワイルドカード、名前付きトークン グループ、正規表現グループ、グループ修飾子のサポートなど、ルーティング パターンの構文を標準化することを目的としています。この構文で作成された URLPattern
インスタンスは、完全な URL または URL pathname
との照合や、トークンとグループの一致に関する情報の返却など、一般的なルーティング タスクを実行できます。
ウェブ プラットフォームで直接 URL マッチングを提供するもう 1 つの利点は、共通の構文を、URL との照合が必要な他の API と共有できることです。
ブラウザのサポートとポリフィル
URLPattern
は、Chrome と Edge のバージョン 95 以降ではデフォルトで有効になっています。
urlpattern-polyfill
ライブラリを使用すると、組み込みのサポートがないブラウザや Node などの環境で URLPattern
インターフェースを使用できます。ポリフィルを使用する場合は、機能検出を使用して、現在の環境でサポートされていない場合にのみ読み込むようにしてください。そうしないと、URLPattern
の重要な利点の 1 つである、サポート環境で使用するために追加のコードをダウンロードして解析する必要がないことが失われます。
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
構文の互換性
URLPattern
の指針となるのは、作り直しを避けることです。Express または Ruby on Rails で使用されるルーティング構文にすでに精通している場合は、新たに学習する必要はありません。ただし、一般的なルーティング ライブラリの構文には若干の差異があるため、ベース構文として何かを選択する必要がありました。URLPattern
の設計者は、path-to-regexp
のパターン構文(API サーフェスではない)を起点として使用することにしました。
この決定は、path-to-regexp
の現在のメンテナーと緊密に協議したうえで行われました。
サポートされている構文の中核的な内容を理解するには、path-to-regexp
のドキュメントをご覧ください。MDN に公開される予定のドキュメントは、GitHub の現在のホームで確認できます。
その他の機能
URLPattern
の構文は path-to-regexp
がサポートするもののスーパーセットです。URLPattern
は、ホスト名のワイルドカードなど、ルーティング ライブラリでは珍しい機能であるオリジンの照合をサポートしています。他のほとんどのルーティング ライブラリは、pathnameのみを処理し、場合によっては URL の検索またはハッシュ部分も処理します。自己完結型のウェブアプリ内での同一オリジンのルーティングにのみ使用されるため、URL のオリジンを確認する必要はありません。
オリジンを考慮すると、サービス ワーカーの fetch
イベント ハンドラ内でクロスオリジン リクエストを転送するなど、追加のユースケースが開かれます。同じオリジンの URL のみを転送する場合は、この追加機能を無視して、他のライブラリと同様に URLPattern
を使用できます。
例
パターンを作成する
URLPattern
を作成するには、コンストラクタに文字列またはオブジェクトを渡します。このオブジェクトのプロパティには、照合するパターンに関する情報が含まれています。
オブジェクトを渡すことで、各 URL コンポーネントの照合に使用するパターンを明示的に制御できます。最も冗長な場合、次のようなコードになります。
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
プロパティに空の文字列を指定した場合、一致するのは URL の対応する部分が設定されていない場合のみです。ワイルドカード *
は、URL の特定の部分に対応する任意の値に一致します。
コンストラクタには、より簡単に使用するためのショートカットがいくつか用意されています。search
と hash
、またはその他のプロパティを完全に省略することは、ワイルドカード '*'
に設定するのと同じことです。上記の例は次のように簡素化できます。
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
追加のショートカットとして、送信元に関するすべての情報を 1 つのプロパティ baseURL
で指定できます。
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
これらすべての例は、一致するオリジンがユースケースに含まれていることを前提としています。オリジンを除く URL の他の部分との照合のみを目的としている場合(多くの「従来型」の単一オリジン ルーティング シナリオの場合と同様に)、オリジン情報は完全に省略し、pathname
、search
、hash
プロパティの組み合わせを指定します。省略されたプロパティは、以前と同様に、*
ワイルドカード パターンに設定されているものとして扱われます。
const p = new URLPattern({pathname: '/foo/:image.jpg'});
コンストラクタにオブジェクトを渡す代わりに、1 つまたは 2 つの文字列を指定できます。1 つの文字列を指定する場合は、オリジンとの照合に使用されるパターン情報を含む完全な URL パターンを表す必要があります。2 つの文字列を指定すると、2 つ目の文字列が baseURL
として使用され、1 つ目の文字列はそのベースに対して相対的と見なされます。
文字列が 1 つでも 2 つでも、URLPattern
コンストラクタは URL パターン全体を解析し、URL コンポーネントに分割して、大きなパターンの各部分を対応するコンポーネントにマッピングします。つまり、内部的には、文字列で作成された各 URLPattern
は、オブジェクトで作成された同等の URLPattern
と同じように表されます。文字列のコンストラクタは、冗長なインターフェースを好むユーザー向けのショートカットです。
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
文字列を使用して URLPattern
を作成する場合は、いくつかの注意事項があります。
オブジェクトを使用して URLPattern
を作成する場合、プロパティを省略することは、そのプロパティに *
ワイルドカードを指定することと同様です。完全な URL 文字列パターンが解析されたときに、URL コンポーネントのいずれかに値がない場合、そのコンポーネントのプロパティが ''
に設定されているかのように扱われます。この場合、そのコンポーネントが空の場合にのみ一致します。
文字列を使用する場合は、作成された URLPattern
でワイルドカードを使用する場合は、ワイルドカードを明示的に含める必要があります。
// p1 and p2 are equivalent.
const p1 = new URLPattern('/foo', location.origin);
const p2 = new URLPattern({
protocol: location.protocol,
hostname: location.hostname,
pathname: '/foo',
search: '',
hash: '',
});
// p3 and p4 are equivalent.
const p3 = new URLPattern('/foo?*#*', location.origin);
const p4 = new URLPattern({
protocol: location.protocol,
hostname: location.hostname,
pathname: '/foo',
});
また、文字列パターンをそのコンポーネントに解析すると、あいまいになる可能性があることにも注意する必要があります。:
のような文字は URL に含まれていますが、パターン マッチング構文で特別な意味を持つものがあります。このあいまいさを回避するため、URLPattern
コンストラクタでは、これらの特殊文字は URL ではなくパターンの一部であると想定されます。曖昧な文字を URL の一部として解釈する場合は、文字列として指定するときに \` character. For example, the literal URL
about:blankshould be escaped as
'about\:blank'` でエスケープしてください。
パターンの使用
URLPattern
を作成した後、それを使用するには 2 つの方法があります。test()
メソッドと exec()
メソッドはどちらも同じ入力を受け取り、同じアルゴリズムを使用して一致を確認します。異なるのは戻り値のみです。test()
は、指定された入力と一致する場合は true
を返し、一致しない場合 false
を返します。exec()
は、キャプチャ グループとともに一致に関する詳細情報を返します。一致がない場合、null
を返します。次の例では exec()
を使用していますが、単純なブール値の戻り値のみが必要な場合は、test()
をこれらに切り替えることができます。
test()
メソッドと exec()
メソッドを使用する方法の一つは、文字列を渡すことです。コンストラクタがサポートするものと同様に、1 つの文字列を指定する場合は、オリジンを含む完全な URL にする必要があります。2 つの文字列が指定されている場合、2 番目の文字列は baseURL
値として扱われ、最初の文字列はそのベースに対して相対的に評価されます。
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
const result = p.exec('https://example.com/foo/cat.jpg');
// result will contain info about the successful match.
// const result = p.exec('/foo/cat.jpg', 'https://example.com')
// is equivalent, using the baseURL syntax.
const noMatchResult = p.exec('https://example.com/bar');
// noMatchResult will be null.
または、コンストラクタがサポートするオブジェクトと同じ種類のオブジェクトを渡し、プロパティを一致させる URL の部分のみに設定することもできます。
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
ワイルドカードまたはトークンを含む URLPattern
で exec()
を使用すると、戻り値に入力 URL 内の対応する値に関する情報が返されます。これにより、それらの値を自分で解析する手間を省くことができます。
const p = new URLPattern({
hostname: ':subdomain.example.com',
pathname: '/*/:image.jpg'
});
const result = p.exec('https://imagecdn1.example.com/foo/cat.jpg');
// result.hostname.groups.subdomain will be 'imagecdn1'
// result.pathname.groups[0] will be 'foo', corresponding to *
// result.pathname.groups.image will be 'cat'
匿名グループと名前付きグループ
URL 文字列を exec()
に渡すと、パターンのすべてのグループに一致した部分を示す値が返されます。
戻り値には、URLPattern
のコンポーネントに対応するプロパティ(pathname
など)があります。したがって、グループが URLPattern
の pathname
部分の一部として定義されている場合、戻り値の pathname.groups
で一致を見つけることができます。一致は、対応するパターンが匿名グループか名前付きグループかによって異なる方法で表されます。
配列インデックスを使用して、匿名パターン マッチの値にアクセスできます。複数の匿名パターンがある場合、インデックス 0
は左端のパターンと一致する値を表し、1
と後続のパターンにさらにインデックスが使用されます。
パターンで名前付きグループを使用する場合、名前が各グループ名に対応するプロパティとして一致が公開されます。
Unicode のサポートと正規化
URLPattern
は、いくつかの方法で Unicode 文字をサポートしています。
名前付きグループ(
:café
など)には Unicode 文字を含めることができます。有効な JavaScript 識別子に使用されるルールは、名前付きグループに適用されます。パターン内のテキストは、その特定のコンポーネントの URL エンコードに使用されるのと同じルールに従って自動的にエンコードされます。
pathname
内の Unicode 文字はパーセント エンコードされるため、/café
などのpathname
パターンは自動的に/caf%C3%A9
に正規化されます。hostname
内の Unicode 文字は、パーセント エンコードではなく Punycode を使用して自動的にエンコードされます。正規表現のグループには ASCII 文字のみを含める必要があります。正規表現の構文では、これらのグループの Unicode 文字を自動的にエンコードすることは困難で安全ではありません。正規表現グループ内で Unicode 文字を照合する場合は、
café
と一致するように(caf%C3%A9)
など、手動でパーセント エンコードする必要があります。
URLPattern
は、Unicode 文字のエンコードに加えて、URL の正規化も行います。たとえば、pathname
コンポーネントの /foo/./bar
は、同等の /foo/bar
に圧縮されます。
特定の入力パターンの正規化方法が不明な場合は、ブラウザの DevTools を使用して、作成された URLPattern
インスタンスを調べます。
すべてを組み合わせる
以下に埋め込まれた Glitch デモは、サービス ワーカーの fetch event handler
内の URLPattern
のコア ユースケースを示しています。特定のパターンを、ネットワーク リクエストにレスポンスを生成できる非同期関数にマッピングします。この例のコンセプトは、サーバーサイドまたはクライアントサイドの他のルーティング シナリオにも適用できます。
フィードバックと今後の計画
URLPattern
の基本機能は Chrome と Edge に実装されていますが、追加機能の追加が予定されています。URLPattern
の一部はまだ開発中であり、特定の動作について未解決の質問がいくつかありますが、まだ改善の余地があります。URLPattern
をお試しいただき、GitHub の問題を通じてフィードバックをお寄せください。
テンプレートのサポート
path-to-regexp
ライブラリには、ルーティング動作を効果的に逆転する compile() function
が用意されています。compile()
は、トークン プレースホルダのパターンと値を受け取り、それらの値を置き換えた URL パスの文字列を返します。
今後、URLPattern に追加する予定ですが、最初のリリースの範囲外です。
今後のウェブ プラットフォーム機能を有効にする
URLPattern
がウェブ プラットフォームの確立された部分になると仮定すると、ルーティングやパターン マッチングから利益を得られる他の機能は、プリミティブとしてその上に構築できます。
サービス ワーカー スコープ パターン マッチング、ファイル ハンドラとしての PWA、推測プリフェッチなどの提案されている機能に URLPattern
を使用するかどうかについて、現在も議論が続いています。
謝辞
謝辞の一覧については、元の説明ドキュメントをご覧ください。