Skip to content

load functions runs on both server and client #8302

@chrisseto

Description

@chrisseto

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/A

System 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.4

Severity

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();
					}
				})

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions