URLPattern ermöglicht Routing auf der Webplattform

Ein Ansatz zur Standardisierung von Anwendungsfällen für häufige Musterabgleichs.

Hintergrund

Routing ist ein wichtiger Bestandteil jeder Webanwendung. Im Kern beinhaltet das Routing eine URL, auf die ein Musterabgleich oder eine andere appspezifische Logik angewendet wird, um dann normalerweise Webinhalte anzuzeigen, die auf dem Ergebnis basieren. Routing kann auf verschiedene Weise implementiert werden: Manchmal wird Code auf einem Server ausgeführt, der einen Pfad zu Dateien auf dem Laufwerk zuordnet, oder Logik in einer einseitigen Anwendung, die auf Änderungen am aktuellen Speicherort wartet und ein entsprechendes DOM erstellt, das angezeigt werden soll.

Es gibt zwar keinen endgültigen Standard, aber Webentwickler rücken zu einer gemeinsamen Syntax für URL-Routingmuster vor, die ähnlich wie regular expressions sind, jedoch mit einigen domainspezifischen Zusätzen wie Tokens für übereinstimmende Pfadsegmente. Beliebte serverseitige Frameworks wie Express und Ruby on Rails verwenden diese oder etwas Ähnliches. JavaScript-Entwickler können diese Logik mit Modulen wie path-to-regexp oder regexpparam ihrem eigenen Code hinzufügen.

URLPattern ist eine Ergänzung zur Webplattform und baut auf der Grundlage dieser Frameworks auf. Ziel ist die Standardisierung einer Routingmustersyntax, einschließlich der Unterstützung von Platzhaltern, benannten Tokengruppen, Gruppen für reguläre Ausdrücke und Gruppenmodifikatoren. URLPattern-Instanzen, die mit dieser Syntax erstellt wurden, können gängige Routingaufgaben wie den Abgleich mit vollständigen URLs oder einer URL pathname ausführen und Informationen über das Token und die Gruppenübereinstimmungen zurückgeben.

Ein weiterer Vorteil des URL-Abgleichs direkt auf der Webplattform besteht darin, dass eine gemeinsame Syntax dann mit anderen APIs geteilt werden kann, die ebenfalls mit URLs abgeglichen werden müssen.

Browserunterstützung und Polyfills

URLPattern ist in Chrome und Edge ab Version 95 standardmäßig aktiviert.

Die urlpattern-polyfill-Bibliothek bietet die Möglichkeit, die URLPattern-Schnittstelle in Browsern oder Umgebungen wie Node zu verwenden, die keine integrierte Unterstützung haben. Wenn du Polyfill verwendest, solltest du die Funktionserkennung nutzen, damit sie nur dann geladen wird, wenn die aktuelle Umgebung keine Unterstützung bietet. Andernfalls verlieren Sie einen der Hauptvorteile von URLPattern: Die Tatsache, dass Supportumgebungen keinen zusätzlichen Code herunterladen und parsen müssen, um ihn verwenden zu können.

if (!(globalThis && 'URLPattern' in globalThis)) {
  // URLPattern is not available, so the polyfill is needed.
}

Syntaxkompatibilität

Eine Leitidee für URLPattern ist, Neuerungen zu vermeiden. Wenn Sie mit der in Express oder Ruby on Rails verwendeten Routingsyntax bereits vertraut sind, müssen Sie sich wahrscheinlich nichts Neues merken. Angesichts der leichten Abweichungen zwischen den Syntaxen in gängigen Routingbibliotheken musste jedoch etwas als Basissyntax ausgewählt werden. Die Designer von URLPattern beschlossen daher, die Mustersyntax aus path-to-regexp (allerdings nicht der API-Oberfläche) als Ausgangspunkt zu verwenden.

Diese Entscheidung wurde nach enger Absprache mit dem aktuellen Administrator von path-to-regexp getroffen.

Am besten machen Sie sich mit dem Kern der unterstützten Syntax vertraut, indem Sie die Dokumentation zu path-to-regexp lesen. Die Dokumentation zur Veröffentlichung auf MDN finden Sie auf der aktuellen Startseite auf GitHub.

Zusätzliche Funktionen

Die Syntax von URLPattern ist eine Obermenge dessen, was von path-to-regexp unterstützt wird, da URLPattern ein ungewöhnliches Feature unter Routingbibliotheken unterstützt: übereinstimmende Ursprünge, einschließlich Platzhaltern in Hostnamen. Die meisten anderen Routingbibliotheken verarbeiten nur den pathname und gelegentlich den search- oder Hash-Teil einer URL. Sie müssen nie den Ursprungsteil einer URL prüfen, da sie nur für das Routing nach demselben Ursprung innerhalb einer eigenständigen Webanwendung verwendet werden.

Durch die Berücksichtigung der Ursprünge ergeben sich zusätzliche Anwendungsfälle wie das Weiterleiten von ursprungsübergreifenden Anfragen innerhalb des Event-Handlers fetch eines Service Workers. Wenn du nur URLs mit demselben Ursprung leitest, kannst du diese zusätzliche Funktion ignorieren und URLPattern wie andere Bibliotheken verwenden.

Beispiele

Muster erstellen

Übergeben Sie zum Erstellen eines URLPattern-Objekts entweder Strings oder ein Objekt, dessen Eigenschaften Informationen zu dem Muster enthalten, das abgeglichen werden soll.

Die Übergabe eines Objekts bietet die genaueste Kontrolle darüber, welches Muster für den Abgleich der einzelnen URL-Komponenten verwendet werden soll. In ihrer ausführlichesten Form kann das wie folgt aussehen:

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
  search: '*',
  hash: '*',
});

Die Angabe eines leeren Strings für ein Attribut führt nur dann zu einer Übereinstimmung, wenn der entsprechende Teil der URL nicht festgelegt ist. Der Platzhalter * entspricht jedem Wert für einen bestimmten Teil der URL.

Der Konstruktor bietet mehrere Tastaturkürzel für eine einfachere Verwendung. Wenn Sie search und hash oder andere Attribute vollständig weglassen, entspricht dies der Festlegung des Platzhalters '*'. Das obige Beispiel könnte vereinfacht werden, sodass

const p = new URLPattern({
  protocol: 'https',
  username: '',
  password: '',
  hostname: 'example.com',
  port: '',
  pathname: '/foo/:image.jpg',
});

Als zusätzliche Verknüpfung können alle Informationen zum Ursprung in der einzigen Eigenschaft baseURL angegeben werden, was zu

const p = new URLPattern({
  pathname: '/foo/:image.jpg',
  baseURL: 'https://example.com',
});

In allen diesen Beispielen wird davon ausgegangen, dass Ihr Anwendungsfall den Abgleich von Ursprüngen beinhaltet. Wenn Sie nur die anderen Teile der URL abgleichen möchten, ohne den Ursprung zu berücksichtigen (wie es bei vielen „traditionellen“ Szenarien des Routings mit einem einzelnen Ursprung der Fall ist), können Sie die Ursprungsinformationen ganz weglassen und lediglich eine Kombination der Attribute pathname, search und hash angeben. Wie zuvor werden ausgelassene Attribute so behandelt, als wären sie auf das Platzhaltermuster * festgelegt.

const p = new URLPattern({pathname: '/foo/:image.jpg'});

Statt ein Objekt an den Konstruktor zu übergeben, können Sie auch einen oder zwei Strings angeben. Wenn ein String angegeben wird, sollte er ein vollständiges URL-Muster einschließlich Musterinformationen darstellen, die zum Abgleich des Ursprungs verwendet werden. Wenn Sie zwei Strings angeben, wird der zweite String als baseURL verwendet und der erste String als relativ zu dieser Basis betrachtet.

Unabhängig davon, ob ein oder zwei Strings angegeben werden, parst der URLPattern-Konstruktor das vollständige URL-Muster, teilt es in URL-Komponenten auf und ordnet jeden Teil des größeren Musters der entsprechenden Komponente zu. Das bedeutet, dass jede mit Strings erstellte URLPattern genauso dargestellt wird wie eine entsprechende URLPattern, die mit einem Objekt erstellt wurde. Der String-Konstruktor ist nur eine Abkürzung für diejenigen, die eine weniger ausführliche Benutzeroberfläche bevorzugen.

const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');

Wenn Sie Strings zum Erstellen eines URLPattern verwenden, sind einige Einschränkungen zu beachten.

Wenn Sie ein Attribut weglassen, wenn Sie URLPattern mit einem Objekt erstellen, entspricht dies der Angabe des Platzhalters * für dieses Attribut. Wenn das vollständige URL-String-Muster geparst wird und bei einer der URL-Komponenten ein Wert fehlt, wird sie so behandelt, als wäre die Eigenschaft der Komponente auf '' gesetzt, was nur übereinstimmt, wenn diese Komponente leer ist.

Wenn Sie Strings verwenden, müssen Sie die Platzhalter explizit einschließen, wenn sie in der erstellten URLPattern verwendet werden sollen.

// 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',
});

Beachten Sie auch, dass das Parsen eines Stringmusters in seine Komponenten möglicherweise mehrdeutig ist. In URLs sind Zeichen wie : enthalten, die in der Syntax des Musterabgleichs aber eine besondere Bedeutung haben. Um diese Mehrdeutigkeit zu vermeiden, geht der URLPattern-Konstruktor davon aus, dass diese Sonderzeichen Teil eines Musters und nicht Teil der URL sind. Wenn ein mehrdeutiges Zeichen als Teil der URL interpretiert werden soll, müssen Sie es mit dem Escapezeichen \` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'` als String maskieren.

Verwendung des Musters

Nachdem Sie ein URLPattern erstellt haben, haben Sie zwei Möglichkeiten, es zu verwenden. Die Methoden test() und exec() verwenden dieselbe Eingabe und denselben Algorithmus, um nach einer Übereinstimmung zu suchen. Sie unterscheiden sich nur in ihrem Rückgabewert. test() gibt true zurück, wenn eine Übereinstimmung mit der angegebenen Eingabe vorliegt, andernfalls wird false zurückgegeben. exec() gibt detaillierte Informationen zur Übereinstimmung zusammen mit Erfassungsgruppen zurück oder null, wenn es keine Übereinstimmung gibt. Die folgenden Beispiele zeigen, wie exec() verwendet wird. Wenn Sie nur einen einfachen booleschen Rückgabewert verwenden möchten, können Sie test() durch jedes Objekt ersetzen.

Eine Möglichkeit, die Methoden test() und exec() zu verwenden, ist das Übergeben von Strings. Ähnlich wie dies vom Konstruktor unterstützt wird, sollte ein einzelner String angegeben werden, um eine vollständige URL einschließlich des Ursprungs zu sein. Wenn zwei Strings angegeben werden, wird der zweite String als baseURL-Wert behandelt und der erste String als relativ zu dieser Basis ausgewertet.

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.

Alternativ können Sie dieselbe Art von Objekt übergeben, die der Konstruktor unterstützt, mit Attributen, die nur auf die Teile der URL festgelegt sind, die abgeglichen werden sollen.

const p = new URLPattern({pathname: '/foo/:image.jpg'});

const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.

Wenn Sie exec() für eine URLPattern verwenden, die Platzhalter oder Tokens enthält, liefert Ihnen der Rückgabewert Informationen zu den entsprechenden Werten in der Eingabe-URL. So müssen Sie diese Werte nicht selbst parsen.

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'

Anonyme und benannte Gruppen

Wenn Sie einen URL-String an exec() übergeben, wird ein Wert zurückgegeben, der angibt, welche Teile mit allen Gruppen des Musters übereinstimmen.

Der Rückgabewert hat Attribute, die den Komponenten von URLPattern entsprechen, z. B. pathname. Wenn also eine Gruppe als Teil des pathname-Teils von URLPattern definiert wurde, können die Übereinstimmungen im pathname.groups des Rückgabewerts gefunden werden. Die Übereinstimmungen werden unterschiedlich dargestellt, je nachdem, ob das entsprechende Muster eine anonyme oder benannte Gruppe war.

Mithilfe von Array-Indizes können Sie auf die Werte für eine anonyme Musterübereinstimmung zugreifen. Wenn es mehrere anonyme Muster gibt, stellt der Index 0 den Abgleichwert für das ganz links angezeigte Muster dar, mit 1 und weiteren Indizes, die für nachfolgende Muster verwendet werden.

Wenn Sie benannte Gruppen in einem Muster verwenden, werden die Übereinstimmungen als Attribute angezeigt, deren Namen dem jeweiligen Gruppennamen entsprechen.

Unicode-Unterstützung und -Normalisierung

URLPattern unterstützt Unicode-Zeichen auf verschiedene Arten.

  • Benannte Gruppen wie :café können Unicode-Zeichen enthalten. Die für gültige JavaScript-IDs verwendeten Regeln gelten für benannte Gruppen.

  • Text innerhalb eines Musters wird automatisch nach denselben Regeln codiert, die für die URL-Codierung der jeweiligen Komponente verwendet werden. Unicode-Zeichen in pathname werden prozentcodiert. Daher wird ein pathname-Muster wie /café automatisch auf /caf%C3%A9 normalisiert. Unicode-Zeichen in hostname werden statt einer Prozentcodierung automatisch mit Punycode codiert.

  • Gruppen mit regulären Ausdrücken dürfen nur ASCII-Zeichen enthalten. Die Syntax für reguläre Ausdrücke erschwert und erschwert die automatische Codierung von Unicode-Zeichen in diesen Gruppen. Wenn Sie ein Unicode-Zeichen in einer Gruppe von regulären Ausdrücken abgleichen möchten, müssen Sie es manuell Prozentual codieren, z. B. (caf%C3%A9), damit es café entspricht.

Neben der Codierung von Unicode-Zeichen führt URLPattern auch eine URL-Normalisierung durch. Beispielsweise wird /foo/./bar in der Komponente pathname auf die entsprechende /foo/bar minimiert.

Wenn Sie unsicher sind, wie ein bestimmtes Eingabemuster normalisiert wurde, prüfen Sie die erstellte URLPattern-Instanz mithilfe der DevTools Ihres Browsers.

Zusammenfassung

Die unten eingebettete Glitch-Demo veranschaulicht einen zentralen Anwendungsfall von URLPattern in der fetch event handler eines Service Workers, bei dem bestimmte Muster asynchronen Funktionen zugeordnet werden, die eine Antwort auf Netzwerkanfragen generieren könnten. Die Konzepte in diesem Beispiel können auch auf andere Routingszenarien angewendet werden, entweder server- oder clientseitige.

Feedback und zukünftige Pläne

Die Grundfunktionen von URLPattern sind jetzt auch in Chrome und Edge enthalten. Es sind aber weitere Ergänzungen geplant. Einige Aspekte von URLPattern befinden sich noch in der Entwicklungsphase und es gibt eine Reihe von offenen Fragen zu bestimmten Verhaltensweisen, die noch optimiert werden können. Wir empfehlen Ihnen, URLPattern auszuprobieren und Feedback über ein GitHub-Problem zu geben.

Unterstützung von Vorlagen

Die path-to-regexp-Bibliothek bietet eine compile() function, die das Routingverhalten effektiv umkehrt. compile() verwendet ein Muster und Werte für die Tokenplatzhalter und gibt einen String für einen URL-Pfad mit diesen Werten zurück.

Wir hoffen, dies in Zukunft zu URLPattern hinzufügen zu können, aber dies ist in der ersten Version noch nicht möglich.

Zukünftige Webplattformfunktionen ermöglichen

Vorausgesetzt, URLPattern wird ein fester Bestandteil der Webplattform, können andere Features, die vom Routing oder Musterabgleich profitieren könnten, als Primitiv darauf aufbauen.

Es wird derzeit darüber diskutiert, wie Sie URLPattern für vorgeschlagene Funktionen wie den Musterabgleich für Service Worker-Bereiche, PWAs als Datei-Handler und spekulativen Prefetch verwenden.

Danksagungen

Eine vollständige Liste der Danksagungen finden Sie im ursprünglichen Erklärungsdokument.