URLPattern ermöglicht Routing auf der Webplattform

Ein Ansatz zur Standardisierung häufiger Anwendungsfälle für Musterabgleiche.

Hintergrund

Das Routing ist ein wichtiger Bestandteil jeder Webanwendung. Beim Routing wird eine URL verwendet, auf die ein Musterabgleich oder eine andere appspezifische Logik angewendet wird. Anschließend werden in der Regel Webinhalte basierend auf dem Ergebnis angezeigt. Das Routing kann auf unterschiedliche Weise implementiert werden: Manchmal ist es Code, der auf einem Server ausgeführt wird und einen Pfad zu Dateien auf dem Laufwerk zuordnet, oder Logik in einer Single-Page-App, die auf Änderungen am aktuellen Standort wartet und ein entsprechendes DOM-Element zum Anzeigen erstellt.

Es gibt zwar keinen eindeutigen Standard, aber Webentwickler haben sich für eine gemeinsame Syntax zum Ausdruck von URL-Routing-Mustern entschieden, die viel mit regular expressions gemeinsam haben, aber einige domainspezifische Ergänzungen wie Tokens zum Abgleichen von Pfadsegmenten enthalten. Gängige serverseitige Frameworks wie Express und Ruby on Rails verwenden diese Syntax (oder eine sehr ähnliche) und JavaScript-Entwickler können Module wie path-to-regexp oder regexpparam verwenden, um diese Logik in ihren eigenen Code einzufügen.

URLPattern ist eine Ergänzung der Webplattform, die auf der Grundlage dieser Frameworks aufbaut. Ziel ist es, eine Routing-Mustersyntax zu standardisieren, einschließlich Unterstützung für Platzhalter, benannte Tokengruppen, reguläre Ausdrucksgruppen und Gruppenmodifikatoren. Mit dieser Syntax erstellte URLPattern-Instanzen können gängige Routingaufgaben ausführen, z. B. den Abgleich mit vollständigen URLs oder einer URL vom Typ pathname und das Zurückgeben von Informationen zu den Token- und Gruppenübereinstimmungen.

Ein weiterer Vorteil der URL-Übereinstimmung direkt auf der Webplattform besteht darin, dass eine gemeinsame Syntax dann für andere APIs verwendet 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 Bibliothek urlpattern-polyfill bietet eine Möglichkeit, die URLPattern-Oberfläche in Browsern oder Umgebungen wie Node zu verwenden, die keine integrierte Unterstützung bieten. Wenn Sie die Polyfill verwenden, sollten Sie die Feature-Erkennung verwenden, damit sie nur geladen wird, wenn die aktuelle Umgebung nicht unterstützt wird. Andernfalls verlieren Sie einen der Hauptvorteile von URLPattern: In Supportumgebungen muss kein zusätzlicher Code heruntergeladen und geparst werden, um ihn zu verwenden.

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

Syntaxkompatibilität

Eine Leitphilosophie für URLPattern ist es, Neuentwicklungen zu vermeiden. Wenn Sie bereits mit der Routing-Syntax von Express oder Ruby on Rails vertraut sind, müssen Sie nichts Neues lernen. Aufgrund der leichten Abweichungen zwischen den Syntaxen in gängigen Routingbibliotheken musste jedoch eine Basissyntax ausgewählt werden. Die Designer von URLPattern entschieden sich, die Mustersyntax von path-to-regexp (nicht jedoch die API-Oberfläche) als Ausgangspunkt zu verwenden.

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

Die Dokumentation zu path-to-regexp ist die beste Informationsquelle für die unterstützte Syntax. Die Dokumentation, die auf der MDN veröffentlicht werden soll, finden Sie in ihrer aktuellen Version auf GitHub.

Zusätzliche Funktionen

Die Syntax von URLPattern ist eine Übermenge dessen, was path-to-regexp unterstützt, da URLPattern eine unter Routingbibliotheken eher seltene Funktion unterstützt: das Abgleichen von Ursprüngen, einschließlich Platzhaltern in Hostnamen. Die meisten anderen Routingbibliotheken befassen sich nur mit dem pathname und gelegentlich mit dem Such- oder Hash-Teil einer URL. Sie müssen nie den Ursprungsteil einer URL prüfen, da sie nur für das Routing innerhalb einer eigenständigen Webanwendung verwendet werden.

Wenn Sie Ursprünge berücksichtigen, eröffnen sich zusätzliche Anwendungsfälle, z. B. das Weiterleiten von Anfragen zwischen verschiedenen Ursprüngen innerhalb des fetch-Ereignishandlers eines Dienstarbeiters. Wenn Sie nur URLs mit demselben Ursprung weiterleiten, können Sie diese zusätzliche Funktion ignorieren und URLPattern wie andere Bibliotheken verwenden.

Beispiele

Muster erstellen

Wenn Sie ein URLPattern erstellen möchten, übergeben Sie dem Konstruktor entweder Strings oder ein Objekt, dessen Eigenschaften Informationen zum zu vergleichenden Muster enthalten.

Wenn Sie ein Objekt übergeben, können Sie am besten festlegen, welches Muster für die Übereinstimmung der einzelnen URL-Komponenten verwendet werden soll. Im schlimmsten Fall könnte das so aussehen:

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

Wenn Sie für eine Property einen leeren String angeben, wird nur dann eine Übereinstimmung gefunden, 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 Tastenkürzel für eine einfachere Verwendung. Wenn Sie search und hash oder andere Properties vollständig weglassen, entspricht das dem Festlegen der Platzhalter '*'. Das obige Beispiel könnte so vereinfacht werden:

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

Als zusätzliche Vereinfachung können alle Informationen zur Quelle in einer einzigen Property (baseURL) angegeben werden.

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

Bei allen diesen Beispielen wird davon ausgegangen, dass Ihr Anwendungsfall Übereinstimmungen von Ursprüngen umfasst. Wenn Sie nur die Übereinstimmung mit den anderen Teilen der URL, ohne den Ursprung, anstreben (wie bei vielen „traditionellen“ Routingszenarien mit nur einem Ursprung), können Sie die Ursprungsinformationen vollständig weglassen und nur eine Kombination der Eigenschaften pathname, search und hash angeben. Wie bisher werden ausgelassene Properties so behandelt, als wären sie auf das Platzhaltermuster * festgelegt.

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

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

Unabhängig davon, ob ein oder zwei Strings angegeben werden, wird das vollständige URL-Muster vom Konstruktor von URLPattern analysiert, in URL-Komponenten zerlegt und jeder Teil des größeren Musters der entsprechenden Komponente zugeordnet. Das bedeutet, dass jede mit Strings erstellte URLPattern im Grunde genauso dargestellt wird wie eine entsprechende URLPattern, die mit einem Objekt erstellt wurde. Der Konstruktor für Strings ist nur eine Verknüpfung für diejenigen, die eine weniger ausladende Benutzeroberfläche bevorzugen.

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

Wenn Sie Strings zum Erstellen einer URLPattern verwenden, müssen Sie einige Einschränkungen beachten.

Wenn Sie eine Property weglassen, wenn Sie URLPattern mit einem Objekt erstellen, entspricht das dem Angeben eines *-Platzhalters für diese Property. Wenn beim Parsen des vollständigen URL-Strings einer der URL-Komponenten ein Wert fehlt, wird davon ausgegangen, dass die Eigenschaft der Komponente auf '' festgelegt ist. Das ist nur dann der Fall, wenn die Komponente leer ist.

Wenn Sie Strings verwenden, müssen Sie die Platzhalter explizit angeben, damit sie in der erstellten URLPattern verwendet werden.

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

Außerdem ist zu beachten, dass das Parsen eines Stringmusters in seine Komponenten potenziell mehrdeutig ist. Es gibt Zeichen wie :, die in URLs vorkommen, aber auch eine besondere Bedeutung in der Syntax für die Musterabgleich haben. Um diese Mehrdeutigkeit zu vermeiden, geht der Konstruktor von URLPattern davon aus, dass alle diese Sonderzeichen Teil eines Musters und nicht Teil der URL sind. Wenn ein mehrdeutiges Zeichen als Teil der URL interpretiert werden soll, muss es mit einem Escapezeichen \` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'` versehen werden, wenn es als String angegeben wird.

Muster verwenden

Nachdem Sie einen URLPattern erstellt haben, haben Sie zwei Möglichkeiten, ihn zu verwenden. Die Methoden test() und exec() nehmen dieselbe Eingabe an und verwenden denselben Algorithmus, um nach einer Übereinstimmung zu suchen. Sie unterscheiden sich nur durch den Rückgabewert. test() gibt true zurück, wenn eine Übereinstimmung mit der angegebenen Eingabe gefunden wird, andernfalls false. exec() gibt detaillierte Informationen zur Übereinstimmung zusammen mit Erfassungsgruppen zurück oder null, wenn keine Übereinstimmung gefunden wurde. In den folgenden Beispielen wird exec() verwendet. Sie können aber auch test() verwenden, wenn Sie nur einen einfachen booleschen Rückgabewert benötigen.

Eine Möglichkeit, die Methoden test() und exec() zu verwenden, besteht darin, Strings zu übergeben. Ähnlich wie beim Konstruktor sollte es sich bei einem einzelnen String, der angegeben wird, um eine vollständige URL handeln, einschließlich des Ursprungs. Wenn zwei Strings angegeben werden, wird der zweite String als baseURL-Wert behandelt und der erste String wird 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 vom Konstruktor unterstützt wird, mit Properties, 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() auf eine URLPattern anwenden, die Wildcards oder Tokens enthält, enthält der Rückgabewert Informationen zu den entsprechenden Werten in der Eingabe-URL. So müssen Sie diese Werte nicht selbst herausfinden.

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'

Anonymes und benannte Gruppen

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

Der Rückgabewert hat Eigenschaften, die den Komponenten der URLPattern entsprechen, z. B. pathname. Wenn eine Gruppe als Teil des pathname-Teils von URLPattern definiert wurde, finden Sie die Übereinstimmungen in pathname.groups des Rückgabewerts. Die Übereinstimmungen werden unterschiedlich dargestellt, je nachdem, ob das entsprechende Muster eine anonyme oder benannte Gruppe war.

Sie können Arrayindizes verwenden, um auf die Werte für eine anonyme Musterübereinstimmung zuzugreifen. Wenn mehrere anonyme Muster vorhanden sind, steht Index 0 für den übereinstimmenden Wert des Musters links, während 1 und weitere Indexe für nachfolgende Muster verwendet werden.

Wenn Sie benannte Gruppen in einem Muster verwenden, werden die Übereinstimmungen als Properties angezeigt, deren Namen den 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 Regeln für gültige JavaScript-IDs gelten auch für benannte Gruppen.

  • Text in einem Muster wird automatisch gemäß denselben Regeln codiert, die für die URL-Codierung der jeweiligen Komponente verwendet werden. Unicode-Zeichen in pathname werden prozentcodiert. Ein pathname-Muster wie /café wird also automatisch in /caf%C3%A9 normalisiert. Unicode-Zeichen in der hostname werden automatisch mit Punycode und nicht mit Prozentcodierung codiert.

  • Reguläre Ausdrucksgruppen dürfen nur ASCII-Zeichen enthalten. Die Syntax von regulären Ausdrücken macht es schwierig und unsicher, Unicode-Zeichen in diesen Gruppen automatisch zu codieren. Wenn Sie ein Unicode-Zeichen in einer regulären Ausdrucksgruppe abgleichen möchten, müssen Sie es manuell mit dem Prozentzeichen codieren, z. B. (caf%C3%A9) für café.

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

Wenn Sie sich nicht sicher sind, wie ein bestimmtes Eingabemuster normalisiert wurde, können Sie die erstellte URLPattern-Instanz mit den DevTools Ihres Browsers prüfen.

Zusammenfassung

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

Feedback und zukünftige Pläne

Die grundlegenden Funktionen für URLPattern sind bereits in Chrome und Edge verfügbar. 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 dir, URLPattern auszuprobieren und uns Feedback über ein GitHub-Problem zu geben.

Unterstützung für Vorlagen

Die path-to-regexp-Bibliothek bietet eine compile() function, mit der das Routingverhalten effektiv umgekehrt wird. compile() nimmt ein Muster und Werte für die Token-Platzhalter an und gibt einen String für einen URL-Pfad zurück, in dem diese Werte eingefügt sind.

Wir hoffen, diese Funktion in Zukunft URLPattern hinzuzufügen, sie ist aber nicht Teil der ersten Version.

Zukünftige Webplattformfunktionen aktivieren

Angenommen, URLPattern wird ein etablierter Teil der Webplattform, können andere Funktionen, die von Routing oder Musterabgleich profitieren könnten, darauf aufbauen.

Es gibt laufende Diskussionen über die Verwendung von URLPattern für vorgeschlagene Funktionen wie Musterabgleich im Service Worker-Umfang, PWAs als Dateihandler und vorsorgliches Vorabladen.

Danksagungen

Eine vollständige Liste der Mitwirkenden finden Sie im ursprünglichen Erklärdokument.