Publicado em: 22 de julho de 2021
O roteamento é uma parte fundamental de todos os aplicativos da Web. Basicamente, o roteamento usa um URL, aplica uma correspondência de padrões ou outra lógica específica do app e, geralmente, mostra conteúdo da Web com base no resultado. O roteamento pode ser implementado de várias maneiras:
- Código do servidor que mapeia caminhos para arquivos em um disco
- Lógica em um app de página única que espera mudanças no local atual e cria e mostra uma parte correspondente do DOM.
Embora não haja um padrão definitivo, os desenvolvedores da Web têm se inclinado para uma sintaxe comum para expressar padrões de rotas de URL que compartilham muito em comum com regular expressions, mas com algumas adições específicas do domínio, como tokens para correspondência de segmentos de caminho.
Frameworks populares do lado do servidor, como
Express e
Ruby on Rails, usam essa sintaxe (ou
algo muito parecido), e os desenvolvedores de JavaScript podem usar módulos como
path-to-regexp ou
regexpparam para adicionar essa
lógica ao próprio código.
URLPattern
é uma adição à plataforma da Web que se baseia na fundação criada
por essas estruturas. O objetivo é padronizar uma sintaxe de padrão de roteamento, incluindo suporte para caracteres curinga, grupos de tokens nomeados, grupos de expressões regulares e modificadores de grupo. As instâncias URLPattern criadas com essa sintaxe
podem realizar tarefas de roteamento comuns, como correspondência com URLs completos ou um URL
pathname,
e retornar informações sobre o token e as correspondências de grupo.
Outro benefício de fornecer a correspondência de URL diretamente na plataforma da Web é que uma sintaxe comum pode ser compartilhada com outras APIs que também precisam corresponder a URLs.
Suporte a navegadores e polyfills
O URLPattern é ativado por padrão no Chrome e no Edge 95 e versões mais recentes.
A biblioteca
urlpattern-polyfill
oferece uma maneira de usar a interface URLPattern em navegadores
ou ambientes como o Node, que não têm suporte integrado. Se você usar o polyfill, faça a detecção de recursos para garantir que ele só seja carregado se o ambiente atual não tiver suporte. Caso contrário, você vai perder um dos principais benefícios do URLPattern: o fato de que os ambientes de suporte não precisam baixar e analisar código adicional para usá-lo.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
Compatibilidade de sintaxe
Uma filosofia orientadora para URLPattern é evitar a reinvenção. Se você já conhece a sintaxe de roteamento usada no Express ou no Ruby on Rails, não precisa aprender nada novo. No entanto, devido às pequenas divergências entre as sintaxes das bibliotecas de rotas mais usadas, algo precisava ser escolhido como sintaxe básica. Os designers do URLPattern decidiram usar a sintaxe de padrão do path-to-regexp (embora não a superfície da API) como ponto de partida.
Essa decisão foi tomada após uma consulta detalhada com o mantenedor atual de
path-to-regexp.
A melhor maneira de se familiarizar com o núcleo da sintaxe compatível é consultar a documentação de path-to-regexp. É possível ler a documentação (em inglês) destinada à publicação na MDN (em inglês) no local atual dela no GitHub.
Recursos adicionais
A sintaxe de URLPattern é um superconjunto do que path-to-regexp oferece suporte, já que URLPattern é compatível com um recurso incomum entre as bibliotecas de roteamento: correspondência de origens, incluindo caracteres curinga em nomes de host. A maioria das outras bibliotecas de roteamento lida apenas com o pathname e, ocasionalmente, com a parte search ou hash de um URL. Eles nunca precisam verificar a parte de origem de um URL, já que são usados apenas
para roteamento de mesma origem em um web app independente.
Considerar as origens abre a porta para outros casos de uso, como
o roteamento de solicitações entre origens dentro de um
service worker
fetch event handler. Se você estiver roteando apenas URLs de mesma origem, ignore esse recurso adicional e use URLPattern como outras bibliotecas.
Exemplos
Como construir o padrão
Para criar um URLPattern, transmita ao construtor dele strings ou um objeto cujas
propriedades contenham informações sobre o padrão a ser correspondido.
Transmitir um objeto oferece o controle mais explícito sobre qual padrão usar para corresponder a cada componente de URL. Na forma mais detalhada, isso pode ser assim:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
Fornecer uma string vazia para uma propriedade só vai corresponder se a parte correspondente do URL não estiver definida. O caractere curinga * corresponde a qualquer valor de uma determinada parte do URL.
O construtor oferece vários atalhos para facilitar o uso. Omitir completamente search e hash, ou qualquer outra propriedade, é equivalente a definir o caractere curinga '*'. O exemplo pode ser simplificado para:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
Como um atalho adicional, todas as informações sobre a origem podem ser fornecidas em uma única propriedade, baseURL, resultando em
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
Todos esses exemplos pressupõem que seu caso de uso envolve origens correspondentes. Se você só quiser fazer a correspondência com as outras partes do URL, excluindo a origem (como é o caso de muitos cenários de roteamento de origem única), omita as informações de origem e forneça uma combinação das propriedades pathname, search e hash. Como antes, as propriedades omitidas serão tratadas como se estivessem definidas para o padrão curinga *.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
Como alternativa à transmissão de um objeto para o construtor, é possível fornecer uma ou duas strings. Se uma string for fornecida, ela vai representar um padrão de URL completo, incluindo informações de padrão usadas para corresponder à origem. Se você
fornecer duas strings, a segunda será usada como um baseURL, e a primeira
será considerada relativa a essa base.
Seja uma ou duas strings fornecidas, o construtor URLPattern vai analisar
o padrão de URL completo, dividindo-o em componentes de URL e mapeando cada parte
do padrão maior para o componente correspondente. Isso significa que, por baixo dos panos, cada URLPattern criado com strings acaba sendo representado da mesma forma que um URLPattern equivalente criado com um objeto. O construtor
strings é apenas um atalho para quem prefere uma interface
menos detalhada.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
Ao usar strings para criar um URLPattern, é importante lembrar de algumas observações.
Omitir uma propriedade ao usar um objeto para construir URLPattern é equivalente a fornecer um caractere curinga * para essa propriedade. Quando o padrão de string de URL completo é analisado, se um dos componentes do URL não tiver um valor, ele será tratado como se a propriedade do componente estivesse definida como '', o que só vai corresponder quando esse componente estiver vazio.
Ao usar strings, é necessário incluir explicitamente os caracteres curinga se você quiser que eles sejam usados no URLPattern construído.
// 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',
});
Além disso, é importante saber que analisar um padrão de string em seus componentes pode ser ambíguo. Há caracteres, como :, que são encontrados em URLs, mas também têm um significado especial na sintaxe de correspondência de padrões. Para evitar essa ambiguidade, o construtor URLPattern pressupõe que qualquer um desses caracteres especiais faz parte de um padrão, não do URL. Se você quiser que um caractere ambíguo
seja interpretado como parte do URL, faça o escape dele com um
\` character. For example, the literal URLabout:blankshould be escaped as'about\:blank'` quando fornecido como uma string.
Usar o padrão
Depois de criar um URLPattern, você tem duas opções para usá-lo. Os métodos test() e exec() usam a mesma entrada e o mesmo algoritmo para verificar uma correspondência, diferindo apenas no valor de retorno. test()
retorna true quando há uma correspondência para a entrada especificada e false caso contrário.
exec() retorna informações detalhadas sobre a correspondência com grupos de captura ou null se não houver correspondência. Os exemplos a seguir demonstram o uso de
exec(), mas você pode substituir test() em qualquer um deles se quiser apenas um
valor booleano de retorno.
Uma maneira de usar os métodos test() e exec() é transmitindo strings.
Assim como o construtor, se uma única string for fornecida, ela precisará ser um URL completo, incluindo a origem. Se duas strings forem fornecidas, a segunda será tratada como um valor baseURL, e a primeira será avaliada em relação a essa 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.
Como alternativa, você pode transmitir o mesmo tipo de objeto que o construtor aceita, com propriedades definidas apenas para as partes do URL que você quer que correspondam.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
Ao usar exec() em um URLPattern que contém caracteres curinga ou tokens, o valor de retorno fornece informações sobre quais eram os valores correspondentes no URL de entrada. Isso evita que você precise analisar esses valores por conta própria.
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'
Grupos anônimos e nomeados
Quando você transmite uma string de URL para exec(), recebe um valor que informa quais partes corresponderam a todos os grupos do padrão.
O valor de retorno tem propriedades que correspondem aos componentes do
URLPattern, como pathname. Assim, se um grupo foi definido como parte da
porção pathname do URLPattern, as correspondências poderão ser encontradas no
pathname.groups do valor de retorno. As correspondências são representadas de maneira diferente, dependendo se o padrão correspondente era um grupo anônimo ou nomeado.
É possível usar índices de matriz para acessar os valores de uma correspondência de padrão anônima.
Se houver vários padrões anônimos, o índice 0 representará o valor correspondente do padrão mais à esquerda, com 1 e outros índices usados para padrões subsequentes.
Ao usar grupos nomeados em um padrão, as correspondências são expostas como propriedades cujos nomes correspondem a cada nome de grupo.
Suporte e normalização do Unicode
O URLPattern oferece suporte a caracteres Unicode de algumas maneiras diferentes.
Grupos nomeados, como
:café, podem conter caracteres Unicode. As regras usadas para identificadores JavaScript válidos se aplicam a grupos nomeados.O texto em um padrão será codificado automaticamente de acordo com as mesmas regras usadas para a codificação de URL desse componente específico. Os caracteres Unicode em
pathnameserão codificados por porcentagem, portanto, um padrãopathnamecomo/caféserá normalizado para/caf%C3%A9automaticamente. Os caracteres Unicode nohostnamesão codificados automaticamente usando Punycode, em vez de codificação por porcentagem.Os grupos de expressões regulares só podem conter caracteres ASCII. A sintaxe de expressão regular dificulta e torna inseguro codificar automaticamente caracteres Unicode nesses grupos. Se você quiser corresponder a um caractere Unicode em um grupo de expressão regular, faça a codificação por porcentagem manualmente, como
(caf%C3%A9)para corresponder acafé.
Além de codificar caracteres Unicode, URLPattern também realiza a normalização de URL. Por exemplo, /foo/./bar no componente pathname é recolhido ao /foo/bar equivalente.
Em caso de dúvida sobre como um determinado padrão de entrada foi normalizado, inspecione a instância URLPattern construída usando as DevTools do navegador.
Reunir todos os elementos
A demonstração do Glitch ilustra um caso de uso principal do URLPattern
em um
fetch event handler
de service worker,
mapeando padrões específicos para funções assíncronas que podem gerar uma
resposta a solicitações de rede. Os conceitos neste exemplo também podem ser aplicados a
outros cenários de roteamento, seja no lado do servidor ou do cliente.
Feedback e planos futuros
Embora a funcionalidade básica do URLPattern tenha chegado ao Chrome e ao Edge,
há adições planejadas. Alguns aspectos do URLPattern ainda estão em desenvolvimento, e há várias questões em aberto sobre comportamentos específicos que ainda podem ser refinados. Recomendamos que você teste o
URLPattern e envie feedback por um
problema do GitHub.
Suporte para modelos
A biblioteca path-to-regexp fornece um
compile() function
que inverte o comportamento de roteamento. compile() usa um padrão e valores para os marcadores de posição de token e retorna uma string para um caminho de URL com esses valores substituídos.
Esperamos adicionar isso ao URLPattern no futuro, mas não está no escopo da versão inicial.
Ativar recursos futuros da plataforma da Web
Supondo que URLPattern se torne uma parte estabelecida da plataforma da Web, outros
recursos que podem se beneficiar do roteamento ou da correspondência de padrões podem ser criados com base
nela como uma primitiva.
Há discussões em andamento sobre o uso de URLPattern para recursos propostos, como correspondência de padrões de escopo do service worker, PWAs como manipuladores de arquivos e pré-busca especulativa.
Consulte o documento explicativo original para ver uma lista completa de agradecimentos.