Un approccio per standardizzare i casi d'uso comuni di corrispondenza dei pattern.
Sfondo
Il routing è un elemento chiave di ogni applicazione web. In sostanza, il routing consiste nel prendere un URL, applicare una corrispondenza di pattern o un'altra logica specifica per l'app e poi, in genere, visualizzare i contenuti web in base al risultato. Il routing può essere implementato in diversi modi: a volte è codice in esecuzione su un server che mappa un percorso ai file su disco oppure logica in un'app a pagina singola che attende modifiche alla posizione corrente e crea un pezzo corrispondente di DOM da visualizzare.
Sebbene non esista uno standard definitivo, gli sviluppatori web si sono orientati verso una sintassi comune per esprimere pattern di routing degli URL che hanno molto in comune con regular expressions
, ma con alcune aggiunte specifiche del dominio come i token per la corrispondenza dei segmenti di percorso.
Framework lato server popolari come
Express e
Ruby on Rails utilizzano questa sintassi (o
qualcosa di molto simile) e gli sviluppatori JavaScript possono utilizzare moduli come
path-to-regexp
o
regexpparam
per aggiungere questa
logica al proprio codice.
URLPattern
è un'aggiunta alla piattaforma web che si basa sulle fondamenta create
da questi framework. Il suo obiettivo è standardizzare la sintassi dei pattern di routing, incluso 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 corrispondenza con URL completi o un URL
pathname
,
e restituire informazioni sulle corrispondenze di token e gruppi.
Un altro vantaggio della corrispondenza degli URL direttamente nella piattaforma web è che una sintassi comune può essere condivisa con altre API che devono anche corrispondere agli URL.
Supporto dei browser e polyfill
URLPattern
è attivato per impostazione predefinita in Chrome e Edge versione 95 e successive.
La libreria
urlpattern-polyfill
fornisce un modo per utilizzare l'interfaccia URLPattern
nei browser
o in ambienti come Node che non dispongono del supporto integrato. Se utilizzi il polyfill, assicurati di utilizzare il rilevamento delle funzionalità per caricarlo solo se l'ambiente corrente non lo supporta. In caso contrario, perderai uno dei vantaggi principali di URLPattern
: il fatto che gli ambienti di supporto non debbano 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 guida per URLPattern
è evitare di reinventare. Se hai già familiarità con la sintassi di routing utilizzata in Express o Ruby on Rails, non dovresti dover imparare nulla di nuovo. Tuttavia, a causa delle lievi divergenze tra le sintassi delle librerie di routing più diffuse, è stato necessario scegliere una sintassi di base e i progettisti di URLPattern
hanno deciso di utilizzare la sintassi dei pattern di path-to-regexp
(anche se non la sua API) come punto di partenza.
Questa decisione è stata presa dopo un'attenta consultazione con l'attuale maintainer di
path-to-regexp
.
Il modo migliore per acquisire familiarità con la parte principale della sintassi supportata è consultare la documentazione di path-to-regexp
. Puoi
leggere la documentazione destinada alla pubblicazione su MDN nella sua casa attuale su GitHub.
Altre funzionalità
La sintassi di URLPattern
è un superset di ciò che supporta path-to-regexp
, poiché URLPattern
supporta una funzionalità insolita tra le librerie di routing: la corrispondenza delle origini, inclusi i caratteri jolly negli hostname. La maggior parte delle altre librerie di routing si occupa solo del pathname e, occasionalmente, della parte di ricerca o hash di un URL. Non devono mai controllare la parte di origine di un URL, in quanto vengono utilizzati solo per il routing con la stessa origine all'interno di un'app web autonoma.
Tenere conto delle origini apre la strada a casi d'uso aggiuntivi, come il routing delle richieste cross-origin all'interno del gestore eventi fetch
di un service worker. Se indirizzi solo URL con la stessa origine, puoi ignorarla tranquillamente e utilizzare URLPattern
come faresti con altre librerie.
Esempi
Costruzione del pattern
Per creare un URLPattern
, passa al suo costruttore stringhe o un oggetto le cui proprietà contengono informazioni sul pattern da confrontare.
Il passaggio di un oggetto offre il controllo più esplicito sul pattern da utilizzare per la corrispondenza di ciascun componente dell'URL. In caso di massima verbosità, può avere il seguente aspetto
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
Se fornisci una stringa vuota per una proprietà, la corrispondenza verrà trovata solo se la parte corrispondente dell'URL non è impostata. Il carattere jolly *
corrisponde a qualsiasi valore per una determinata
parte dell'URL.
Il costruttore offre diverse scorciatoie per un utilizzo più semplice. Omettere completamente search
e hash
o qualsiasi altra proprietà equivale a impostarle sul carattere jolly '*'
. L'esempio riportato sopra potrebbe essere semplificato in
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 una singola proprietà, baseURL
, che genera
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Tutti questi esempi presuppongono che il tuo caso d'uso preveda l'associazione di origini. Se
ti interessa solo la corrispondenza per le altre parti dell'URL, escludendo
l'origine (come accade per molti scenari di routing "tradizionali" con un'unica origine), puoi omettere completamente le informazioni sull'origine e fornire solo
qualche combinazione delle proprietà pathname
, search
e hash
. Come in precedenza,
le proprietà omesse verranno trattate come se fossero impostate sul pattern
*
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, deve rappresentare un pattern URL completo, incluse le informazioni sul pattern utilizzate per trovare una corrispondenza con l'origine. Se fornisci due stringhe, la seconda viene utilizzata come baseURL
e la prima è considerata relativa a questa base.
Indipendentemente dal fatto che vengano fornite una o due stringhe, il costruttore URLPattern
analizzerà il pattern URL completo, suddividendolo in componenti URL e mappando ogni parte del pattern più grande al componente corrispondente. Ciò significa che, in un certo senso, 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 verbosa.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
Quando utilizzi le stringhe per creare un URLPattern
, devi tenere presente alcune avvertenze.
Omettere una proprietà quando si utilizza un oggetto per costruire URLPattern
è equivalente a fornire un'espressione generica *
per quella proprietà. Quando viene analizzato il pattern di stringa dell'URL completo, se a uno dei componenti dell'URL manca un valore, viene trattato come se la proprietà del componente fosse impostata su ''
, che corrisponde solo quando il componente è vuoto.
Quando utilizzi le stringhe, devi includere esplicitamente i caratteri jolly se vuoi che vengano utilizzati nel URLPattern
creato.
// 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 inoltre presente che l'analisi di un pattern di stringa nei relativi componenti è potenzialmente ambigua. Esistono caratteri, come :
, che si trovano negli URL, ma hanno anche un significato speciale nella sintassi di corrispondenza dei pattern. Per evitare questa ambiguità, il costruttore URLPattern
presuppone che uno 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 eseguirne la fuga con 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
Dopo aver creato un URLPattern
, hai due opzioni per utilizzarlo. I metodi test()
e exec()
accettano entrambi lo stesso input e utilizzano lo stesso algoritmo per verificare la corrispondenza e 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 cattura
o null
se non esiste alcuna corrispondenza. Gli esempi riportati di seguito mostrano l'utilizzo di exec()
, ma puoi sostituire test()
con qualsiasi altro se vuoi solo un semplice valore restituito booleano.
Un modo per utilizzare i metodi test()
e exec()
è passare stringhe.
Analogamente a quanto supportato dal costruttore, se viene fornita una singola stringa, deve essere un URL completo, inclusa l'origine. Se vengono fornite due stringhe, la seconda 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.
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()
in un URLPattern
contenente caratteri jolly o token, il valore restituito ti fornirà informazioni sui valori corrispondenti nell'URL di input. In questo modo, non dovrai analizzare autonomamente questi valori.
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 con nome
Quando passi una stringa URL a exec()
, ricevi un valore che ti indica quali parti corrispondono a tutti i gruppi del pattern.
Il valore restituito ha proprietà che corrispondono ai componenti di URLPattern
, come pathname
. Pertanto, se un gruppo è stato definito come parte della
parte pathname
di URLPattern
, le corrispondenze possono essere trovate in pathname.groups
del valore di ritorno. Le corrispondenze sono rappresentate in modo diverso
a seconda che il pattern corrispondente fosse un gruppo anonimo o denominato.
Puoi utilizzare gli indici dell'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 con nome in un pattern, le corrispondenze verranno esposte come proprietà cuyos nomi corrispondono a ciascun nome di gruppo.
Supporto e normalizzazione di 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 si applicano ai gruppi denominati.Il testo all'interno di un pattern verrà codificato automaticamente in base alle stesse regole utilizzate per la codifica dell'URL di quel determinato componente. I caratteri Unicode all'interno di
pathname
verranno codificati in 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 delle espressioni regolari rende difficile e non sicuro codificare automaticamente i caratteri Unicode in questi gruppi. Se vuoi trovare una corrispondenza con un carattere Unicode in un gruppo di espressioni regolari, devi codificarlo in percentuale manualmente, ad esempio
(caf%C3%A9)
per trovare una corrispondenza concafé
.
Oltre a codificare i caratteri Unicode, URLPattern
esegue anche la normalizzazione dell'URL. Ad esempio, /foo/./bar
nel componente pathname
viene collapse all'equivalente /foo/bar
.
In caso di dubbi su come è stato normalizzato un determinato pattern di input, controlla l'istanza URLPattern
costruita utilizzando DevTools del browser.
Riassumendo
La demo di Glitch incorporata di seguito illustra un caso d'uso principale di URLPattern
all'interno di fetch event handler
di un worker di servizio, 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, sia lato server che lato client.
Feedback e piani futuri
Sebbene la funzionalità di base di URLPattern
sia stata implementata in Chrome ed Edge, sono previste altre aggiunte. Alcuni aspetti di URLPattern
sono ancora in fase di sviluppo e esistono diverse domande aperte su comportamenti specifici che potrebbero essere ancora perfezionati. Ti invitiamo a provareURLPattern
e a inviare eventuali feedback tramite una
segnalazione su GitHub.
Supporto per i modelli
La libreria path-to-regexp
fornisce un
compile() function
che inverte efficacemente il comportamento di routing. compile()
prende un
pattern e i valori per i segnaposto dei token e restituisce una stringa per un percorso
URL con i valori sostituiti.
Ci auguriamo di poterlo aggiungere a URLPattern in futuro, ma non rientra nell'ambito della release iniziale.
Attivazione di future funzionalità della piattaforma web
Supponendo che URLPattern
diventi una parte consolidata della piattaforma web, altre funzionalità che potrebbero trarre vantaggio dal routing o dalla corrispondenza dei pattern possono essere basate su di essa come elemento primitivo.
Sono in corso discussioni sull'utilizzo di URLPattern
per le funzionalità proposte come la corrispondenza di pattern dell'ambito del servizio worker, i PWA come gestori di file e il prefetching speculativo.
Ringraziamenti
Per un elenco completo dei riconoscimenti, consulta il documento esplicativo originale.