Un approccio per standardizzare i casi d'uso di corrispondenza di pattern comuni.
Contesto
Il routing è un elemento chiave di ogni applicazione web. Essenzialmente, il routing comporta l'acquisizione di un URL, l'applicazione di una corrispondenza di pattern o di un'altra logica specifica dell'app e, di solito, la visualizzazione di contenuti web in base al risultato. Il routing può essere implementato in diversi modi: a volte a volte il codice è in esecuzione su un server che mappa un percorso ai file su disco oppure la logica in un'app a pagina singola che attende le modifiche alla posizione attuale e crea una parte corrispondente del DOM da visualizzare.
Sebbene non esista uno standard definitivo, gli sviluppatori web si sono concentrati su una sintassi comune per esprimere pattern di routing degli URL che condividono molto in comune con regular expressions
, ma con alcune aggiunte specifiche del dominio, come i token per i segmenti di percorso corrispondenti.
I framework lato server più diffusi come
Express e
Ruby on Rails utilizzano questa sintassi (o qualcosa di molto simile) e gli sviluppatori JavaScript possono usare moduli come
path-to-regexp
o
regexpparam
per aggiungere questa
logica al proprio codice.
URLPattern
è un'aggiunta alla piattaforma web che si basa sulle basi create
da questi framework. Il suo obiettivo è standardizzare la sintassi di un pattern di routing, compreso il supporto di caratteri jolly, gruppi di token denominati, gruppi di espressioni regolari e modificatori di gruppo. Le istanze URLPattern
create con questa sintassi
possono eseguire attività di routing comuni, come la ricerca di corrispondenze con URL completi o un URL
pathname
,
e la restituzione di informazioni sulle corrispondenze di token e gruppi.
Un altro vantaggio nel fornire la corrispondenza degli URL direttamente nella piattaforma web è che una sintassi comune può essere condivisa con altre API che devono anche corrispondere agli URL.
Supporto del browser e polyfill
L'app URLPattern
è attiva per impostazione predefinita in Chrome ed Edge 95 e versioni successive.
La libreria urlpattern-polyfill
offre un modo per utilizzare l'interfaccia URLPattern
in browser o ambienti come Node, che non supportano integrato. Se
utilizzi il polyfill, assicurati di utilizzare il rilevamento delle funzionalità per assicurarti di
caricarlo solo se l'ambiente attuale non supporta il supporto. In caso contrario, perderai uno dei principali vantaggi di URLPattern
: il fatto che gli ambienti di supporto non devono scaricare e analizzare codice aggiuntivo per utilizzarlo.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
Compatibilità della sintassi
Una filosofia alla base di URLPattern
è evitare di reinventarsi. Se già conosci la sintassi di routing utilizzata in Express o Ruby su Rails, non dovresti imparare niente di nuovo. Tuttavia, date le lievi differenze tra le sintassi nelle librerie di routing più diffuse, è stato necessario scegliere una sintassi di base, pertanto i designer di URLPattern
hanno deciso di utilizzare come punto di partenza la sintassi del pattern di path-to-regexp
(anche se non la sua superficie API).
Questa decisione è stata presa dopo una stretta consultazione con l'attuale gestore della rete di
path-to-regexp
.
Il modo migliore per acquisire familiarità con il nucleo della sintassi supportata è
consulta la
documentazione per
path-to-regexp
. Puoi leggere la documentazione prevista per la pubblicazione su MDN nella sua attuale home page su GitHub.
Altre funzionalità
La sintassi di URLPattern
è un soprainsieme di ciò che path-to-regexp
supporta, poiché URLPattern
supporta una funzionalità non comune tra le librerie di routing: le origini corrispondenti, inclusi i caratteri jolly nei nomi host. La maggior parte delle altre librerie di routing si occupa solo del pathname
e occasionalmente della parte
search o
hash di un
URL. Non devono mai controllare la parte di origine di un URL, poiché vengono utilizzati solo per il routing dalla stessa origine all'interno di un'app web autonoma.
Prendere in considerazione le origini apre le porte ad altri casi d'uso, come il routing delle richieste multiorigine all'interno del gestore di eventi fetch
di un service worker. Se esegui il routing solo di URL della stessa origine, puoi ignorare questa funzionalità aggiuntiva e utilizzare URLPattern
come altre librerie.
Esempi
Costruire il pattern
Per creare un oggetto URLPattern
, trasmettine il costruttore o le stringhe oppure un oggetto le cui proprietà contengono informazioni sul pattern con cui eseguire un confronto.
La trasmissione di un oggetto offre il controllo più esplicito sul pattern da utilizzare per la corrispondenza con ogni componente URL. Nella forma più dettagliata, può sembrare
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
La specifica di una stringa vuota per una proprietà corrisponderà solo se la parte corrispondente dell'URL non è impostata. Il carattere jolly *
corrisponderà a qualsiasi valore per una determinata porzione dell'URL.
Il costruttore offre diverse scorciatoie per un utilizzo più semplice. Omettere completamente search
e hash
, o qualsiasi altra proprietà, equivale a impostarli sul carattere jolly '*'
. L'esempio precedente può essere semplificato per
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
Come scorciatoia aggiuntiva, tutte le informazioni sull'origine possono
essere fornite in un'unica proprietà, baseURL
, che rimanda a
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Tutti questi esempi presuppongono che il tuo caso d'uso implichi le corrispondenze delle origini. Se
ti interessa la corrispondenza solo nelle altre parti dell'URL, escludendo
l'origine (come nel caso di molti scenari di routing "tradizionali" a origine singola),
puoi omettere completamente le informazioni sull'origine e fornire solo
una combinazione delle proprietà pathname
, search
e hash
. Come prima, le proprietà omesse verranno trattate come se fossero impostate sul pattern di caratteri jolly *
.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
In alternativa al passaggio di un oggetto al costruttore, puoi fornire
una o due stringhe. Se viene fornita una stringa, dovrebbe rappresentare un pattern URL completo, incluse le informazioni sul pattern utilizzate per la corrispondenza con l'origine. Se fornisci due stringhe, la seconda viene utilizzata come baseURL
e la prima viene considerata relativa a questa base.
Indipendentemente dal fatto che sia stata fornita una o due stringhe, il costruttore URLPattern
analizzerà
l'intero pattern URL, suddividendolo in componenti URL e mappa ogni parte
del pattern più grande al componente corrispondente. Ciò significa che in background, ogni URLPattern
creato con stringhe viene rappresentato come un URLPattern
equivalente creato con un oggetto. Il costruttore di stringhe è solo una scorciatoia per chi preferisce un'interfaccia meno dettagliata.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
Quando utilizzi le stringhe per creare un URLPattern
, devi tenere presente alcune avvertenze.
Eliminare una proprietà quando si utilizza un oggetto per creare URLPattern
equivale a fornire un carattere jolly *
per quella proprietà. Quando viene analizzato il pattern stringa dell'URL completo, se in uno dei componenti dell'URL manca un valore, viene considerato come se la proprietà del componente fosse impostata su ''
, che corrisponderà solo quando il componente è vuoto.
Quando utilizzi le stringhe, devi includere esplicitamente i caratteri jolly se vuoi
che vengano utilizzati nella build 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',
});
Tieni presente, inoltre, che l'analisi di un pattern stringa nei suoi componenti è potenzialmente ambigua. Negli URL sono presenti caratteri, come :
, che hanno un significato speciale nella sintassi di corrispondenza del pattern. Per evitare questa
ambiguità, il costruttore URLPattern
presuppone che uno qualsiasi di questi caratteri speciali
faccia parte di un pattern, non dell'URL. Se vuoi che un carattere ambiguo venga interpretato come parte dell'URL, assicurati di specificare un carattere di escape \` character. For example, the literal URL
about:blankshould be escaped as
"about\:blank"" quando viene fornito come stringa.
Utilizzo del pattern
Una volta creato URLPattern
, hai due opzioni per utilizzarlo. I metodi test()
e exec()
accettano entrambi lo stesso input e utilizzano lo stesso algoritmo per verificare una corrispondenza, differiscono solo nel valore restituito. test()
restituisce true
quando esiste una corrispondenza per l'input specificato e false
in caso contrario.
exec()
restituisce informazioni dettagliate sulla corrispondenza insieme ai gruppi di acquisizione oppure null
in assenza di corrispondenze. I seguenti esempi mostrano l'uso di
exec()
, ma puoi sostituire test()
con uno qualsiasi se vuoi solo
un semplice valore restituito booleano.
Un modo per utilizzare i metodi test()
e exec()
è trasmettere le stringhe.
Analogamente a quanto supportato dal costruttore, se viene fornita una singola stringa, questa deve essere un URL completo, inclusa l'origine. Se vengono fornite due stringhe, la seconda stringa viene trattata come un valore baseURL
e la prima viene valutata in base a questa base.
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.
In alternativa, puoi passare lo stesso tipo di oggetto supportato dal costruttore, con proprietà impostate solo sulle parti dell'URL che ti interessano per la corrispondenza.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
Quando utilizzi exec()
su un URLPattern
che contiene caratteri jolly o token, il valore restituito ti fornirà informazioni sui valori corrispondenti nell'URL di input. In questo modo, puoi evitare di dover analizzare questi valori autonomamente.
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'
Gruppi anonimi e denominati
Quando passi una stringa URL a exec()
, ricevi un valore che indica le parti corrispondenti a tutti i gruppi del pattern.
Il valore restituito ha proprietà che corrispondono ai componenti di
URLPattern
, come pathname
. Quindi, se un gruppo è stato definito come parte della porzione
pathname
di URLPattern
, le corrispondenze sono disponibili nel valore
restituito pathname.groups
. Le corrispondenze sono rappresentate in modo diverso a seconda che il pattern corrispondente fosse un gruppo anonimo o denominato.
Puoi utilizzare gli indici di array per accedere ai valori per una corrispondenza di pattern anonima.
Se sono presenti più pattern anonimi, l'indice 0
rappresenterà il valore corrispondente per quello più a sinistra, con 1
e altri indici utilizzati per i pattern successivi.
Quando utilizzi gruppi denominati in un pattern, le corrispondenze verranno mostrate come proprietà i cui nomi corrispondono al nome di ciascun gruppo.
Supporto e normalizzazione Unicode
URLPattern
supporta i caratteri Unicode in diversi modi.
I gruppi con nome, come
:café
, possono contenere caratteri Unicode. Le regole utilizzate per gli identificatori JavaScript validi vengono applicate ai gruppi denominati.Il testo all'interno di un pattern verrà codificato automaticamente in base alle stesse regole utilizzate per la codifica URL di quel particolare componente. I caratteri Unicode all'interno di
pathname
saranno codificati a percentuale, quindi un patternpathname
come/café
viene normalizzato automaticamente in/caf%C3%A9
. I caratteri Unicode inhostname
vengono codificati automaticamente utilizzando Punycode anziché la codifica percentuale.I gruppi di espressioni regolari devono contenere solo caratteri ASCII. La sintassi dell'espressione regolare rende difficile e non sicura la codifica automatica dei caratteri Unicode in questi gruppi. Se vuoi trovare la corrispondenza di un carattere Unicode in un gruppo di espressioni regolari, devi codificarlo manualmente tramite percentuale, ad esempio
(caf%C3%A9)
per trovare la corrispondenza concafé
.
Oltre a codificare i caratteri Unicode, URLPattern
esegue anche la normalizzazione degli URL. Ad esempio, /foo/./bar
nel componente pathname
viene
compresso nell'equivalente /foo/bar
.
In caso di dubbi su come un determinato pattern di input sia stato normalizzato, controlla l'istanza URLPattern
creata utilizzando DevTools del browser.
Riassumendo
La demo di Glitch incorporata di seguito illustra un caso d'uso principale di URLPattern
all'interno di un service worker
fetch event handler
,
mappando pattern specifici a funzioni asincrone che potrebbero generare una
risposta alle richieste di rete. I concetti di questo esempio possono essere applicati anche
ad altri scenari di routing, lato server o lato client.
Feedback e piani futuri
Sebbene la funzionalità di base di URLPattern
sia arrivata su Chrome ed Edge, sono previste aggiunte. Alcuni aspetti di URLPattern
sono ancora in fase di sviluppo e ci sono diverse domande aperte su comportamenti specifici che potrebbero essere ancora perfezionati. Ti invitiamo a provare URLPattern
e a fornire feedback tramite un problema di GitHub.
Supporto per i modelli
La libreria path-to-regexp
fornisce un elemento
compile() function
che inverte efficacemente il comportamento di routing. compile()
prende un pattern e dei valori per i segnaposto dei token e restituisce una stringa per un percorso dell'URL con quei valori sostituiti.
Ci auguriamo di aggiungere questo elemento a URLPattern in futuro, ma non rientra nell'ambito della release iniziale.
Attivazione delle funzionalità delle future piattaforme web
Supponendo che URLPattern
diventi una parte consolidata della piattaforma web, altre funzionalità che potrebbero trarre vantaggio dal routing o dalla corrispondenza di pattern possono basarsi su questo elemento come primitiva.
Sono in corso discussioni sull'utilizzo di URLPattern
per le funzionalità proposte, come la corrispondenza dei pattern degli ambiti dei service worker, le PWA come gestori di file e il precaricamento speculativo.
Ringraziamenti
Consulta il documento esplicativo originale per un elenco completo dei riconoscimenti.