현재에 와서 URL을 우아하게 다루는 방법은 웹 브라우저에서 네이티브로 지원해주는 URL
클래스를 사용하는 것이다. 생성자를 사용해 URL을 만들어주면 프로토콜과 호스트 이름, 파일 경로, 쿼리 문자열까지 아주 잘 뽑아내준다.
const url = new URL('https://taegon.kim/?s=url');
console.log(url.protocol, url.hostname, url.pathname, url.search);
게다가 URL 인스턴스에는 searchParams
라는 URLSearchParams 인스턴스도 있는데 기본적으로 맵과 유사한 인터페이스를 가지고 있어서 각 쿼리의 키와 값을 설정하기가 좋다.
const url = new URL('https://taegon.kim/?s=url');
console.log(url.searchParams.get('s')); // 'url'
url.searchParams.set('num', '1234');
console.log(url.searchParams.toString()); // 's=url&num=1234'
URL과 URLSearchParams 모두 Node.js에도 네이티브로 존재하므로(아주 예전 버전엔 없을 수 있다) 클라이언트든 서버든 JS에서 URL을 우아하게 다루기는 쉬워졌...어야 했지만, 아직도 IE 11을 지원해야 하는 입장에서 저 두 개의 아름다운 지원은 그림의 떡일 뿐이다.
문서를 살펴보면 IE 10부터는 URL을 지원한다고 하는데 잘 읽어보면 URL
클래스가 아니라 URL object
를 지원한다. IE에서 지원하는 이 URL object
는 거의 Object
나 마찬가지인데 createObjectURL
과 revokeObjectURL
이라는 두 개의 정적 메소드를 포함하고 있다. 이들을 사용하는 방법은 [JS] Blob와 Blob URL을 참조하자. 어쨌든 중요한 것은 URL의 각 파트를 다루는 데는 도움이 안된다는 점이다.
그럼 URL 클래스가 있기 전에는 어떻게 URL의 각 파트를 구분했을까? 정규표현식을 사용하거나 이 글에서 설명할 방법을 사용했다. 코드부터 보자.
const url = document.createElement('a');
url.href = 'https://taegon.kim/?s=url';
console.log(url.protocol, url.hostname, url.pathname, url.search);
DOM 엘리먼트를 사용하고 있으므로 당연히 웹 브라우저 환경 또는 DOM 환경이 제공되는 Node에서만 사용할 수 있는 방법이다. 또한 아쉽게도 searchParams
는 제공해주지 않아서 쿼리 문자열을 간편하게 다루기는 어렵다. 그 외에도 항상 기준이 현재 문서의 URL이 되어서 잘못된 형식의 URL을 전달하는 경우에는 기대한 대로 동작하지 않을 수 있다는 문제가 있다.
본격적으로 구현 된 URL의 폴리필은 이미 core-js에서 잘 다루고 있으니 여기서는 (언제나 그렇듯) 아주 간단한 버전으로 만들어 보려고 한다.
/**
* URL 문자열을 해석하여 (유사) URL 객체를 반환한다.
* @param {string} url URL 문자열
* @return {URL} URL 객체. IE11에서는 유사 URL 객체를 반환한다.
*/
function parseURL(url) {
if (typeof URL === 'function') {
return new URL(url);
}
var a = document.createElement('a');
a.href = url;
return {
protocol: a.protocol,
host: a.host,
hostname: a.hostname,
pathname: a.pathname,
hash: a.hash,
href: a.href,
search: a.search,
};
}
아쉬운 부분이 꽤 있다. 이왕이면 searchParams도 지원하면 좋겠고 읽기 전용 객체가 아니라 각 파트를 설정하면 href
에 반영되었으면 좋을 것이다. 하지만, 2023년에 굳이 URL 객체가 없는 브라우저를 지원해야 할까. 아마 나도 회사 업무가 아니었다면 아마 작성하지 않았을 것 같다. 그래서 이 작업은 여기서 멈추기로 했다. 혹시 더 많은 기능이 필요한 사람이 있다고 하면 그때 추가하면 되지 않을까.
오랜만에 포스팅 감사합니다.
회사업무 드리븐 강력하네요 ㅋㅋ
내용 잘 봤습니다. polyfill이야 임포트해 사용하면 되지만, 이렇게 설명을 해 주시니 IE11과 최신 브라우저들의 차이를 알 수 있어서 좋네요.
저희 회사 업무는 용량에 민감한데 폴리필이 의외로 용량이 커서 쓰기가 부담스럽더라고요(그게 다 돈이라...). 그래서 이렇게 기능은 좀 모자라도 가벼운 폴리필을 직접 만들어서 쓰고 있기도 합니다. 하지만 실제 속마음은 얼른 IE를 버리고 싶습니다 ㅠㅠ