Description
Stumbled into a bit of a rabbit hole while adding prerendering to adapter-node — because this.fetch
is expected to work exactly the same as fetch
, we have to account for the possibility that someone will this.fetch('/some-static-file.json
), which means that the prerenderer needs to know where the static files could live, which muddies the API somewhat.
It's also just a bit of an awkward API:
- Sapper doesn't currently handle URLs relative to the requested page (though this could easily change, and has in fact changed in the current app-utils)
- The whole
res = await this.fetch(...); data = await res.json()
dance is a bit of a pain, honestly - It's easy to forget that you need
credentials: 'include'
if you're usingsession
fetch
supports non-GET methods, which don't make sense in the context ofpreload
(or load, as the case may be)
I'd like to replace it with this.get
:
<script context="module">
export async function load({ params }) {
return await this.get(`./${params.slug}.json`);
}
</script>
- Only works with server routes, not static files or external resources. Simpler
- Accepts a URL (easiest way to identify server routes, which will of course continue to work with plain
fetch
), which can be relative to the requested page - Always includes credentials
- Returns a promise for the body of the response. If the
Content-Type
isapplication/json
, isJSON.parse
d. If it'stext/*
, is returned as text. Otherwise is returned as an array buffer - Non-200 responses throw an error (augmented with
status
code), which is equivalent to callingthis.error(status, error)
, except that you can catch and handle if necessary. For common cases, this eliminates the need to add error handling around the response returned fromthis.fetch
We could also expose get
alongside the other app functions (goto
et al) for use outside preload
/load
functions. (It would probably just throw in Node.) That's not necessary for this.get
to have value though.
Of course there are still times when it's useful to be able to use fetch
in preload
/load
— hn.svelte.dev fetches data from https://api.hnpwa.com, for example, and it's good to be able to do this isomorphically (rather than forcing the app to always connect to the app's own server, like ahem some frameworks). But if it's only to be used for external URLs, then there's no need to use this.fetch
, we can just use regular fetch
. We can polyfill it in Node with @rollup/plugin-inject and node-fetch (which already powers this.fetch
). With this approach, many apps wouldn't need node-fetch at all, whereas currently it has to be included because of this.fetch
.
This seems like all upside to me, except for the breakingness of the change. But if there was ever a time for breaking changes this is it. Thoughts?