-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Description
Describe the bug
Despite the what is stated by the documentation svelte kit apps will re-fetch data via the load function unless specific methods of the response object are accessed.
Reproduction
This can be easily reproduced by implementing your own JSON unmarshaling, not that you would want to do that. I stumbled across this bug because I was using a GRPC Web Client which decodes the payload from body directly.
// Place in any +page.ts/js file
export const load = (async ({ fetch }) => {
const resp = await fetch('/some-endpoint');
// You wouldn't ever want to do this. What's important is that we're not accessing .text or .json
const chunks: Array<any> = [];
for await (let chunk of resp.body) {
chunks.push(chunk)
}
return JSON.parse(Buffer.concat(chunks).toString('utf-8'));
}) satisfies PageLoad;Logs
N/ASystem Info
System:
OS: macOS 13.0.1
CPU: (8) arm64 Apple M1
Memory: 349.42 MB / 16.00 GB
Shell: 3.5.1 - /opt/homebrew/bin/fish
Binaries:
Node: 18.11.0 - /opt/homebrew/bin/node
Yarn: 1.22.17 - /opt/homebrew/bin/yarn
npm: 8.19.2 - /opt/homebrew/bin/npm
Browsers:
Brave Browser: 107.1.45.133
Safari: 16.1
npmPackages:
@sveltejs/adapter-auto: next => 1.0.0-next.90
@sveltejs/adapter-node: ^1.0.0 => 1.0.0
@sveltejs/adapter-static: ^1.0.0-next.48 => 1.0.0-next.48
@sveltejs/kit: next => 1.0.0-next.571
svelte: ^3.53.1 => 3.53.1
vite: ^3.2.4 => 3.2.4Severity
serious, but I can work around it
Additional Information
What's been most frustrating about tracking this down is the phrasing of the documentation. It heavily implies, if not outright states, that the serialized data is what is returned from load. However, load will always be called on both the client and the server. Svelte's fetch function is what memoizes the requests but only under certain circumstances. If my understanding is correct, I'm happy to update the documentation myself.
Additionally, it would be nice to add in some detection to svelte's fetch proxy to log a warning to users if a request is made but can't be memoized so they don't have to go down this rabbit hole themselves.
I'm currently working around the issue by using a modified GrpcWebFetchTransport that accepts a fetch override and I've further customized the unary method to call .text and then feed the result as a ReadableStream to readGrpcWebResponseBody.
const text = await fetchResponse.text()
const stream = new ReadableStream({
start(ctrl) {
// Re-encode our text as Bytes as
// readGrpcWebResponseBody expects bytes.
const encoder = new TextEncoder()
ctrl.enqueue(encoder.encode(text));
ctrl.close();
}
})