Re: [whatwg/url] Support relative URLs (#531)

> could you perhaps go into some more detail as to why you want to avoid window.location and where these relative URLs are common?

Sure. The reason we want to avoid using `window.location` is because it doesn't exist in Web Workers, among other environments. Web Workers do have `self` instead of `window`, though. Node.js doesn't have `window` or `self`. There are even environments where a `window` _does_ exist but _without_ a `window.location`, such as [Deno](https://deno.land/). Newer environments have `globalThis` but older environments don't. There are so many special cases, it's a mess and difficult to maintain.

Relative URLs are common mainly in apps that target browsers. It's not uncommon to see something like `fetch('/foo.jpg')` or `fetch('../constants.json')`. We aim to make this work, while keeping the implementation of the Ky library as environment agnostic as possible.

Early versions of Ky were designed to pass URLs directly to `fetch()` without modifying them and without referencing `window` or `document`. That worked well because `fetch()` correctly handles relative URLs as input, and it resolves them against either `document.baseURI` (e.g. from the `<base>` HTML element), or `window.location`, depending on what is available. `fetch()` works as expected and we want Ky to work that way, too.

Then people [requested a new feature](https://github.com/sindresorhus/ky/issues/54) where you can pass a `searchParams` object to Ky, and Ky will add those those params to the input URL before calling `fetch()`. This is useful, for example, if you are creating a custom API client with `ky.extend()` and you always want to include a `?limit=100` param to limit the page size to 100 items in the response to _every_ request that is sent with that client. When that feature [was implemented](https://github.com/sindresorhus/ky/pull/57), we had to decide how to apply the `searchParams` to the input URL, and for that we began using `new URL()` and its property setters, since it's easy to do `myUrl.search = mySearchParams`. That solution seemed good at the time, but later we realized that [it broke relative URL support](https://github.com/sindresorhus/ky/issues/58) because `new URL()` lacks support for relative URLs. I tried to [fix the regression](https://github.com/sindresorhus/ky/pull/59/files#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346) by resolving the input URL against the document base, with `new URL(input, document.baseURI)`. But that then [caused problems](https://github.com/sindresorhus/ky/issues/64) for people using Ky in Web Workers, React Native on mobile devices, and Node.js. I then fixed that by [guarding the document reference](https://github.com/sindresorhus/ky/pull/74), although in hindsight that also needs a fallback to `window.location`, which itself needs to be guarded. You'd think that would be enough, but we had further complaints that our approach of referencing globals was [too difficult to mock](https://github.com/sindresorhus/ky/issues/151). The [attempted fix](https://github.com/sindresorhus/ky/pull/153) for that then [broke more stuff](https://github.com/sindresorhus/ky/issues/202)...

The point is, writing environment agnostic code that depends on `window` or `document` is pretty tricky in practice. And in the end, we were only doing that as a workaround for `new URL()`'s lack of support for relative URLs. So we dropped `new URL()` and resorted to regex-based string replacement of the search params instead, for now.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/url/issues/531#issuecomment-835521213

Received on Saturday, 8 May 2021 21:25:46 UTC