일반적인 패턴 매칭 사용 사례를 표준화하는 접근 방식
배경
라우팅은 모든 웹 애플리케이션의 핵심 요소입니다. 라우팅의 핵심은 URL을 취하고 패턴 일치 또는 기타 앱별 로직을 적용한 다음 일반적으로 결과에 따라 웹 콘텐츠를 표시하는 것입니다. 라우팅은 다양한 방식으로 구현될 수 있습니다. 디스크의 파일 경로를 매핑하는 서버에서 실행되는 코드 또는 현재 위치의 변경사항을 대기하고 표시할 해당 DOM 부분을 만드는 단일 페이지 앱의 로직일 때도 있습니다.
확실한 표준은 없지만 웹 개발자는 regular expressions
와 많은 공통점을 공유하지만 경로 세그먼트 일치용 토큰과 같은 일부 도메인별 추가 항목이 있는 URL 라우팅 패턴을 표현하기 위한 공통 문법을 선호했습니다.
Express 및 Ruby on Rails와 같은 인기 있는 서버 측 프레임워크는 이 문법 (또는 이와 매우 유사한 문법)을 사용하며 JavaScript 개발자는 path-to-regexp
또는 regexpparam
와 같은 모듈을 사용하여 자체 코드에 로직을 추가할 수 있습니다.
URLPattern
는 이러한 프레임워크로 만든 기반을 기반으로 하는 웹 플랫폼에 추가된 버전입니다. 와일드 카드, 이름이 지정된 토큰 그룹, 정규 표현식 그룹, 그룹 수정자를 지원하는 등 라우팅 패턴 문법을 표준화하는 것이 목표입니다. 이 문법으로 만든 URLPattern
인스턴스는 전체 URL 또는 URL pathname
과 일치시키고 토큰 및 그룹 일치에 관한 정보를 반환하는 것과 같은 일반적인 라우팅 작업을 실행할 수 있습니다.
웹 플랫폼에서 URL 매칭을 직접 제공할 때의 또 다른 이점은 공통 구문을 URL과 일치시켜야 하는 다른 API와도 공유할 수 있다는 것입니다.
브라우저 지원 및 폴리필
URLPattern
는 Chrome 및 Edge 버전 95 이상에서 기본적으로 사용 설정됩니다.
urlpattern-polyfill
라이브러리는 기본 제공 지원이 없는 브라우저 또는 Node와 같은 환경에서 URLPattern
인터페이스를 사용하는 방법을 제공합니다. 폴리필을 사용하는 경우 기능 감지를 사용하여 현재 환경에서 지원되지 않는 경우에만 폴리필을 로드해야 합니다. 그러지 않으면 URLPattern
의 주요 이점 중 하나인 지원 환경에서 이를 사용하기 위해 추가 코드를 다운로드하고 파싱할 필요가 없다는 이점을 놓치게 됩니다.
if (!(globalThis && 'URLPattern' in globalThis)) {
// URLPattern is not available, so the polyfill is needed.
}
구문 호환성
URLPattern
의 지침 철학은 재발명을 피하는 것입니다. Express 또는 Ruby on Redis에서 사용되는 라우팅 구문에 이미 익숙하다면 새로운 것을 배우지 않아도 됩니다. 하지만 많이 사용되는 라우팅 라이브러리의 구문 간에 약간의 차이가 있기 때문에 기본 문법으로 무언가를 선택해야 했으며 URLPattern
의 디자이너는 API 노출 영역이 아닌 path-to-regexp
의 패턴 문법을 시작점으로 사용하기로 결정했습니다.
이 결정은 path-to-regexp
의 현재 유지관리자와 긴밀히 협의한 후 내려졌습니다.
지원되는 문법의 핵심을 숙지하는 가장 좋은 방법은 path-to-regexp
의 문서를 참고하는 것입니다. MDN에 게시할 문서를 읽을 수 있습니다. 현재 GitHub의 홈에서 확인할 수 있습니다.
추가 기능
URLPattern
는 라우팅 라이브러리 중에서 일반적으로 사용되지 않는 기능(호스트 이름에 와일드 카드를 포함하여 출처 일치)을 지원하기 때문에 URLPattern
구문은 path-to-regexp
에서 지원하는 구문의 상위 집합입니다. 다른 대부분의 라우팅 라이브러리는 pathname만 처리하고 경우에 따라 URL의 검색 또는 해시 부분을 처리합니다. URL의 출처 부분은 확인할 필요가 없습니다. 독립된 웹 앱 내에서 동일한 출처 라우팅에만 사용되기 때문입니다.
출처를 고려하면 서비스 워커의 fetch
이벤트 핸들러 내에서 교차 출처 요청을 라우팅하는 것과 같은 추가 사용 사례를 사용할 수 있습니다. 동일 출처 URL만 라우팅하는 경우 이 추가 기능을 무시하고 다른 라이브러리처럼 URLPattern
를 사용할 수 있습니다.
예
패턴 구성
URLPattern
를 만들려면 생성자에 문자열 또는 일치시킬 패턴에 관한 정보가 속성에 포함된 객체를 전달합니다.
객체를 전달하면 각 URL 구성요소를 일치시키는 데 사용할 패턴을 가장 명시적으로 제어할 수 있습니다. 최대한 자세한 내용은 다음과 같습니다.
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
search: '*',
hash: '*',
});
속성에 빈 문자열을 제공하면 URL의 해당 부분이 설정되지 않은 경우에만 일치합니다. 와일드 카드 *
는 URL의 지정된 부분에 있는 모든 값과 일치합니다.
생성자는 더 쉽게 사용할 수 있도록 여러 바로가기를 제공합니다. search
및 hash
또는 기타 속성을 완전히 생략하면 '*'
와일드 카드로 설정하는 것과 같습니다. 위의 예는 다음과 같이 간소화할 수 있습니다.
const p = new URLPattern({
protocol: 'https',
username: '',
password: '',
hostname: 'example.com',
port: '',
pathname: '/foo/:image.jpg',
});
추가 단축키로 출처에 관한 모든 정보를 단일 속성 baseURL
에 제공할 수 있습니다.
const p = new URLPattern({
pathname: '/foo/:image.jpg',
baseURL: 'https://example.com',
});
이러한 예시에서는 모두 사용 사례에 출처 일치가 포함된다고 가정합니다. 출처를 제외한 URL의 다른 부분에만 일치시키는 데 관심이 있는 경우 (많은 '기존' 단일 출처 라우팅 시나리오의 경우와 같이) 출처 정보를 완전히 생략하고 pathname
, search
, hash
속성의 조합만 제공하면 됩니다. 이전과 마찬가지로 생략된 속성은 *
와일드 카드 패턴으로 설정된 것처럼 처리됩니다.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
생성자에 객체를 전달하는 대신 문자열 1개 또는 2개를 제공할 수 있습니다. 문자열이 1개 제공되는 경우 출처를 일치시키는 데 사용된 패턴 정보를 포함하여 전체 URL 패턴을 나타내야 합니다. 문자열을 두 개 제공하면 두 번째 문자열이 baseURL
로 사용되고 첫 번째 문자열은 이 베이스를 기준으로 간주됩니다.
문자열이 하나이든 두 개이든 URLPattern
생성자는 전체 URL 패턴을 파싱하여 URL 구성요소로 분할하고 더 큰 패턴의 각 부분을 해당 구성요소에 매핑합니다. 즉, 문자열로 만든 각 URLPattern
는 객체로 만든 상응하는 URLPattern
와 동일하게 표현됩니다. 문자열 생성자는 덜 상세한 인터페이스를 선호하는 사용자를 위한 단축키에 불과합니다.
const p = new URLPattern('https://example.com/foo/:image.jpg?*#*');
문자열을 사용하여 URLPattern
를 만들 때는 몇 가지 주의해야 할 사항이 있습니다.
객체를 사용하여 URLPattern
를 구성할 때 속성을 생략하면 해당 속성에 *
와일드 카드를 제공하는 것과 같습니다. 전체 URL 문자열 패턴이 파싱될 때 URL 구성요소 중 하나에 값이 누락된 경우 구성요소의 속성이 ''
로 설정된 것처럼 처리되며, 이는 구성요소가 비어 있을 때만 일치합니다.
문자열을 사용할 때 와일드 카드를 생성된 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',
});
또한 문자열 패턴을 구성요소로 파싱하는 것은 모호할 수 있다는 점에 유의해야 합니다. :
와 같이 URL에 있지만 패턴 일치 문법에서도 특별한 의미를 갖는 문자가 있습니다. 이러한 모호성을 피하기 위해 URLPattern
생성자는 특수 문자가 URL의 일부가 아니라 패턴의 일부라고 가정합니다. 모호한 문자를 URL의 일부로 해석하려면 문자열로 제공된 경우 \` character. For example, the literal URL
about:blankshould be escaped as
'about\:blank'`로 이스케이프 처리해야 합니다.
패턴 사용
URLPattern
를 구성한 후에는 두 가지 옵션을 사용할 수 있습니다. test()
및 exec()
메서드는 모두 동일한 입력을 사용하고 동일한 알고리즘을 사용하여 일치를 확인하며 반환 값만 다릅니다. test()
는 지정된 입력과 일치하는 경우 true
를 반환하고 일치하지 않는 경우에는 false
를 반환합니다.
exec()
는 캡처 그룹과 함께 일치하는 항목에 관한 자세한 정보를 반환하거나 일치하는 항목이 없는 경우 null
를 반환합니다. 다음 예에서는 exec()
를 사용하는 방법을 보여줍니다. 단순한 불리언 반환 값만 원하는 경우 test()
로 바꿀 수 있습니다.
test()
및 exec()
메서드를 사용하는 한 가지 방법은 문자열을 전달하는 것입니다.
생성자가 지원하는 것과 마찬가지로 단일 문자열이 제공되는 경우 원본을 포함한 전체 URL이어야 합니다. 두 문자열이 제공되면 두 번째 문자열은 baseURL
값으로 취급되고 첫 번째 문자열은 이 기준을 기준으로 평가됩니다.
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.
또는 일치시키는 데 중요한 URL 부분으로만 설정된 속성을 사용하여 생성자가 지원하는 것과 동일한 종류의 객체를 전달할 수 있습니다.
const p = new URLPattern({pathname: '/foo/:image.jpg'});
const result = p.exec({pathname: '/foo/:image.jpg'});
// result will contain info about the successful match.
와일드 카드나 토큰이 포함된 URLPattern
에서 exec()
를 사용하면 반환 값을 통해 입력 URL의 해당 값에 대한 정보가 제공됩니다. 이렇게 하면 이러한 값을 직접 파싱해야 하는 수고를 덜 수 있습니다.
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'
익명 그룹 및 이름이 지정된 그룹
URL 문자열을 exec()
에 전달하면 패턴의 모든 그룹과 일치하는 부분을 나타내는 값이 반환됩니다.
반환 값에는 pathname
와 같이 URLPattern
의 구성요소에 해당하는 속성이 있습니다. 따라서 그룹이 URLPattern
의 pathname
부분의 일부로 정의된 경우 반환 값의 pathname.groups
에서 일치 항목을 찾을 수 있습니다. 일치는 해당 패턴이 익명 그룹인지 이름이 지정된 그룹인지에 따라 다르게 표시됩니다.
배열 색인을 사용하여 익명의 패턴 일치 값에 액세스할 수 있습니다.
익명 패턴이 여러 개 있는 경우 색인 0
는 가장 왼쪽에 있는 패턴의 일치 값을 나타내며 1
와 이후 패턴에 사용되는 추가 색인이 있습니다.
이름이 지정된 그룹을 패턴으로 사용하면 일치 항목이 각 그룹 이름과 일치하는 이름으로 표시되는 속성으로 노출됩니다.
유니코드 지원 및 정규화
URLPattern
는 여러 가지 방법으로 유니코드 문자를 지원합니다.
:café
와 같이 이름이 지정된 그룹에는 유니코드 문자가 포함될 수 있습니다. 유효한 JavaScript 식별자에 사용되는 규칙은 이름이 지정된 그룹에 적용됩니다.패턴 내의 텍스트는 특정 구성요소의 URL 인코딩에 사용되는 동일한 규칙에 따라 자동으로 인코딩됩니다.
pathname
내의 유니코드 문자는 퍼센트 인코딩되므로/café
과 같은pathname
패턴은 자동으로/caf%C3%A9
로 정규화됩니다.hostname
의 유니코드 문자는 퍼센트 인코딩이 아닌 Punycode를 사용하여 자동으로 인코딩됩니다.정규 표현식 그룹에는 ASCII 문자만 포함해야 합니다. 정규 표현식 구문으로 인해 이러한 그룹에서 유니코드 문자를 자동으로 인코딩하기가 어렵고 안전하지 않습니다. 정규 표현식 그룹에서 유니코드 문자를 일치시키려면
café
와 일치시키기 위해(caf%C3%A9)
와 같이 수동으로 퍼센트 인코딩해야 합니다.
유니코드 문자 인코딩 외에도 URLPattern
는 URL 정규화도 수행합니다. 예를 들어 pathname
구성요소의 /foo/./bar
는 상응하는 /foo/bar
로 축소됩니다.
지정된 입력 패턴이 어떻게 정규화되었는지 확실하지 않은 경우 브라우저의 DevTools를 사용하여 구성된 URLPattern
인스턴스를 검사합니다.
요약 정리
아래에 삽입된 Glitch 데모는 서비스 워커의 fetch event handler
내부에서 URLPattern
의 핵심 사용 사례를 보여줍니다. 이 데모에서는 특정 패턴을 네트워크 요청에 대한 응답을 생성할 수 있는 비동기 함수에 매핑합니다. 이 예시의 개념은 서버 측 또는 클라이언트 측의 다른 라우팅 시나리오에도 적용할 수 있습니다.
의견 및 향후 계획
URLPattern
의 기본 기능은 Chrome 및 Edge에 도입되었지만 계속 추가될 예정입니다. URLPattern
의 일부 측면은 아직 개발 중이며, 아직 세부적으로 조정될 수 있는 특정 동작에 관한 미해결 질문이 여러 개 있습니다. URLPattern
를 사용해 보고 GitHub 문제를 통해 의견을 보내주세요.
템플릿 지원
path-to-regexp
라이브러리는 라우팅 동작을 효과적으로 역전시키는 compile() function
를 제공합니다. compile()
는 토큰 자리표시자의 패턴과 값을 사용하고 이러한 값이 대체된 URL 경로의 문자열을 반환합니다.
향후 URLPattern에 추가할 예정이지만 초기 출시의 범위에는 해당하지 않습니다.
향후 웹 플랫폼 기능 사용 설정
URLPattern
가 웹 플랫폼의 확립된 부분이 되면 라우팅 또는 패턴 매칭의 이점을 누릴 수 있는 다른 기능이 이를 기반으로 빌드될 수 있습니다.
서비스 워커 범위 패턴 일치, 파일 핸들러로서의 PWA, 예상 프리캐시와 같은 제안된 기능에 URLPattern
를 사용하는 것에 관한 논의가 진행 중입니다.
감사의 말씀
전체 감사의 말씀은 원본 설명 문서를 참고하세요.