Fecha de publicación: 22 de julio de 2021
El enrutamiento es una parte fundamental de todas las aplicaciones web. En esencia, el enrutamiento toma una URL, le aplica una coincidencia de patrones o alguna otra lógica específica de la app y, luego, por lo general, muestra contenido web según el resultado. El enrutamiento se puede implementar de varias maneras:
- Código del servidor que asigna rutas de acceso a archivos en un disco
- Lógica en una app de una sola página que espera cambios en la ubicación actual y, luego, crea y muestra una parte correspondiente del DOM.
Si bien no existe un estándar definitivo, los desarrolladores web se han inclinado por una sintaxis común para expresar patrones de enrutamiento de URLs que comparten mucho en común con regular expressions, pero con algunas adiciones específicas del dominio, como tokens para hacer coincidir segmentos de ruta.
Los frameworks populares del servidor, como Express y Ruby on Rails, usan esta sintaxis (o algo muy similar), y los desarrolladores de JavaScript pueden usar módulos como path-to-regexp o regexpparam para agregar esa lógica a su propio código.
URLPattern
es una incorporación a la plataforma web que se basa en la base creada
por estos frameworks. Su objetivo es estandarizar una sintaxis de patrones de enrutamiento, lo que incluye la compatibilidad con comodines, grupos de tokens con nombre, grupos de expresiones regulares y modificadores de grupos. Las instancias de URLPattern creadas con esta sintaxis pueden realizar tareas de enrutamiento comunes, como la coincidencia con URLs completas o un pathname de URL, y devolver información sobre las coincidencias de tokens y grupos.
Otro beneficio de proporcionar la coincidencia de URLs directamente en la plataforma web es que se puede compartir una sintaxis común con otras APIs que también necesitan hacer coincidir URLs.
Compatibilidad con navegadores y polyfills
URLPattern está habilitado de forma predeterminada en Chrome y Edge 95 y versiones posteriores.
La biblioteca urlpattern-polyfill proporciona una forma de usar la interfaz URLPattern en navegadores o entornos como Node que no tienen compatibilidad integrada. Si usas el polyfill, asegúrate de usar la detección de funciones para garantizar que solo lo cargues si el entorno actual no es compatible. De lo contrario, perderás uno de los beneficios clave de URLPattern: el hecho de que los entornos de asistencia no tienen que descargar ni analizar código adicional para usarlo.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
Compatibilidad de la sintaxis
Una filosofía que guía a URLPattern es evitar la reinvención. Si ya conoces la sintaxis de enrutamiento que se usa en Express o Ruby on Rails, no deberías tener que aprender nada nuevo. Sin embargo, dadas las ligeras divergencias entre las sintaxis de las bibliotecas de enrutamiento populares, se debía elegir algo como sintaxis base, y los diseñadores de URLPattern decidieron usar la sintaxis de patrones de path-to-regexp (aunque no su superficie de API) como punto de partida.
Esta decisión se tomó después de una consulta exhaustiva con el mantenedor actual de path-to-regexp.
La mejor manera de familiarizarte con el núcleo de la sintaxis admitida es consultar la documentación de path-to-regexp. Puedes leer la documentación destinada a publicarse en MDN en su ubicación actual en GitHub.
Funciones adicionales
La sintaxis de URLPattern es un superconjunto de lo que admite path-to-regexp, ya que URLPattern admite una función poco común entre las bibliotecas de enrutamiento: la coincidencia de orígenes, incluidos los comodines en los nombres de host. La mayoría de las otras bibliotecas de enrutamiento solo se ocupan de la pathname y, en ocasiones, de la parte de búsqueda o hash de una URL. Nunca tienen que verificar la parte del origen de una URL, ya que solo se usan para el enrutamiento del mismo origen dentro de una app web autónoma.
Tener en cuenta los orígenes abre la puerta a casos de uso adicionales, como el enrutamiento de solicitudes de origen cruzado dentro del controlador de eventos fetch de un service worker. Si solo enrutas URLs del mismo origen, puedes ignorar esta función adicional y usar URLPattern como otras bibliotecas.
Ejemplos
Cómo construir el patrón
Para crear un URLPattern, pasa a su constructor cadenas o un objeto cuyas propiedades contengan información sobre el patrón con el que se debe hacer la coincidencia.
Pasar un objeto ofrece el control más explícito sobre qué patrón usar para hacer coincidir cada componente de la URL. En su versión más detallada, puede verse así:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
Si se proporciona una cadena vacía para una propiedad, solo habrá coincidencias si no se establece la parte correspondiente de la URL. El comodín * coincidirá con cualquier valor para una parte determinada de la URL.
El constructor ofrece varios atajos para un uso más sencillo. Omitir por completo search y hash, o cualquier otra propiedad, equivale a establecerlas en el comodín '*'. El ejemplo se podría simplificar de la siguiente manera:
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
Como acceso directo adicional, toda la información sobre el origen se puede proporcionar en una sola propiedad, baseURL, lo que lleva a
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
En todos estos ejemplos, se supone que tu caso de uso implica orígenes coincidentes. Si solo te interesa hacer coincidir las otras partes de la URL, sin incluir el origen (como sucede en muchos casos de situaciones de enrutamiento de un solo origen), puedes omitir por completo la información del origen y proporcionar solo alguna combinación de las propiedades pathname, search y hash. Al igual que antes, las propiedades omitidas se tratarán como si se hubieran establecido en el patrón de comodín *.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
Como alternativa a pasar un objeto al constructor, puedes proporcionar una o dos cadenas. Si se proporciona una cadena, debe representar un patrón de URL completo, incluida la información del patrón que se usa para hacer coincidir el origen. Si proporcionas dos cadenas, la segunda se usa como baseURL y la primera se considera relativa a esa base.
Ya sea que se proporcione una o dos cadenas, el constructor URLPattern analizará el patrón de URL completo, lo dividirá en componentes de URL y asignará cada parte del patrón más grande al componente correspondiente. Esto significa que, internamente, cada URLPattern creado con cadenas termina representándose de la misma manera que un URLPattern equivalente creado con un objeto. El constructor de cadenas es solo un atajo para quienes prefieren una interfaz menos detallada.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
Cuando usas cadenas para crear un objeto URLPattern, debes tener en cuenta algunas advertencias.
Omitir una propiedad cuando se usa un objeto para construir URLPattern equivale a proporcionar un comodín * para esa propiedad. Cuando se analiza el patrón de cadena de URL completa, si a uno de los componentes de la URL le falta un valor, se considera como si la propiedad del componente se hubiera establecido en '', que solo coincidirá cuando ese componente esté vacío.
Cuando usas cadenas, debes incluir explícitamente los comodines si quieres que se usen en el URLPattern construido.
// 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',
});
También debes tener en cuenta que analizar un patrón de cadena en sus componentes puede ser ambiguo. Hay caracteres, como :, que se encuentran en las URLs, pero también tienen un significado especial en la sintaxis de coincidencia de patrones. Para evitar esta ambigüedad, el constructor URLPattern supone que cualquiera de esos caracteres especiales forma parte de un patrón, no de la URL. Si deseas que un carácter ambiguo se interprete como parte de la URL, asegúrate de escaparlo con un \` character. For example, the literal URLabout:blankshould be escaped as"about\:blank"` cuando se proporcione como una cadena.
Cómo usar el patrón
Después de construir un URLPattern, tienes dos opciones para usarlo. Los métodos test() y exec() toman la misma entrada y usan el mismo algoritmo para verificar si hay una coincidencia, y solo difieren en su valor de retorno. test() devuelve true cuando hay una coincidencia para la entrada proporcionada y false en caso contrario.
exec() devuelve información detallada sobre la coincidencia junto con los grupos de captura, o null si no hay coincidencia. En los siguientes ejemplos, se muestra el uso de exec(), pero puedes reemplazarlo por test() en cualquiera de ellos si solo deseas un valor de devolución booleano.
Una forma de usar los métodos test() y exec() es pasar cadenas.
Al igual que lo que admite el constructor, si se proporciona una sola cadena, debe ser una URL completa, incluido el origen. Si se proporcionan dos cadenas, la segunda se trata como un valor de baseURL y la primera se evalúa en relación con esa 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, puedes pasar el mismo tipo de objeto que admite el constructor, con propiedades que se establecen solo en las partes de la URL que te interesan que coincidan.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
Cuando se usa exec() en un URLPattern que contiene comodines o tokens, el valor de devolución te brindará información sobre cuáles eran los valores correspondientes en la URL de entrada. Esto puede ahorrarte la molestia de tener que analizar esos valores por tu cuenta.
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 y con nombre
Cuando pasas una cadena de URL a exec(), obtienes un valor que te indica qué partes coincidieron con todos los grupos del patrón.
El valor de retorno tiene propiedades que corresponden a los componentes de URLPattern, como pathname. Por lo tanto, si se definió un grupo como parte de la porción pathname de URLPattern, las coincidencias se pueden encontrar en el pathname.groups del valor de devolución. Las coincidencias se representan de manera diferente según si el patrón correspondiente fue un grupo anónimo o con nombre.
Puedes usar índices de array para acceder a los valores de una coincidencia de patrón anónima.
Si hay varios patrones anónimos, el índice 0 representa el valor coincidente del patrón más a la izquierda, y 1 y los índices posteriores se usan para los patrones siguientes.
Cuando se usan grupos con nombre en un patrón, las coincidencias se exponen como propiedades cuyos nombres corresponden a cada nombre de grupo.
Compatibilidad y normalización de Unicode
URLPattern admite caracteres Unicode de varias maneras diferentes.
Los grupos con nombre, como
:café, pueden contener caracteres Unicode. Las reglas que se usan para los identificadores de JavaScript válidos se aplican a los grupos con nombre.El texto dentro de un patrón se codificará automáticamente según las mismas reglas que se usan para la codificación de URL de ese componente en particular. Los caracteres Unicode dentro de
pathnamese codificarán en porcentajes, por lo que un patrónpathnamecomo/cafése normalizará automáticamente en/caf%C3%A9. Los caracteres Unicode enhostnamese codifican automáticamente con Punycode, en lugar de con codificación de porcentaje.Los grupos de expresiones regulares solo deben contener caracteres ASCII. La sintaxis de las expresiones regulares dificulta y hace que sea inseguro codificar automáticamente caracteres Unicode en estos grupos. Si deseas que coincida un carácter Unicode en un grupo de expresiones regulares, debes codificarlo como porcentaje de forma manual, como
(caf%C3%A9)para que coincida concafé.
Además de codificar caracteres Unicode, URLPattern también realiza la normalización de URLs. Por ejemplo, /foo/./bar en el componente pathname se contrae al /foo/bar equivalente.
Si tienes dudas sobre cómo se normalizó un patrón de entrada determinado, inspecciona la instancia de URLPattern construida con las DevTools de tu navegador.
Combina todas las opciones
La demostración de Glitch ilustra un caso de uso principal de URLPattern dentro de un fetch event handler de Service Worker, en el que se asignan patrones específicos a funciones asíncronas que podrían generar una respuesta a las solicitudes de red. Los conceptos de este ejemplo también se podrían aplicar a otros casos de uso de enrutamiento, ya sea del servidor o del cliente.
Comentarios y planes futuros
Si bien la funcionalidad básica de URLPattern ya está disponible en Chrome y Edge, se planean más incorporaciones. Algunos aspectos de URLPattern aún se están desarrollando, y hay varias preguntas abiertas sobre comportamientos específicos que aún se pueden definir mejor. Te recomendamos que pruebes URLPattern y envíes tus comentarios a través de un problema de GitHub.
Compatibilidad con plantillas
La biblioteca path-to-regexp proporciona un compile() function que invierte de manera eficaz el comportamiento de enrutamiento. compile() toma un patrón y valores para los marcadores de posición de tokens, y devuelve una cadena para una ruta de URL con esos valores sustituidos.
Esperamos agregar esto a URLPattern en el futuro, pero no está dentro del alcance de la versión inicial.
Habilita funciones futuras de la plataforma web
Si se supone que URLPattern se convierte en una parte establecida de la plataforma web, otras funciones que podrían beneficiarse del enrutamiento o la coincidencia de patrones pueden basarse en ella como un elemento primitivo.
Se están llevando a cabo debates sobre el uso de URLPattern para las funciones propuestas, como la coincidencia de patrones de alcance de Service Worker, las APW como controladores de archivos y la obtención previa especulativa.
Consulta el documento explicativo original para ver la lista completa de agradecimientos.