Skip to content

repeated fetch request on hydration when Request object is used in +page.js #10474

Closed
@vedadeepta

Description

@vedadeepta

Describe the bug

When a request object is used to fetch data in +page.js instead of a URL the request is repeated on client hydration

export async function load({ fetch }) {
	// const res = await fetch('/mock');
	// const res = await fetch('http://localhost:5173/' + 'mock'); --- request not repeated on client hydration
	const res = await fetch(new Request('http://localhost:5173/' + 'mock')); --- request repeated
	const data = await res.json();
	return data;
}

Reproduction

https://github.com/vedadeepta/sveltejs-kit-template-default-bug

Minimal repro here.

check the network tab - /mock api is made on client hydration.

Then goto routes/page.js and comment out the fetch request with new Request object in it and make a simple fetch request with just the the URL. check network tab again - no repeated /mock request on client hydration

Logs

No response

System Info

System:
    OS: macOS 13.4.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 417.28 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.16.1 - /usr/local/bin/node
    Yarn: 1.22.19 - /opt/homebrew/bin/yarn
    npm: 9.6.7 - /opt/homebrew/bin/npm
    pnpm: 8.6.7 - /opt/homebrew/bin/pnpm
  Browsers:
    Chrome: 115.0.5790.114
    Safari: 16.5.2
  npmPackages:
    @sveltejs/adapter-auto: ^2.0.0 => 2.1.0
    @sveltejs/kit: ^1.20.4 => 1.22.4
    svelte: ^4.0.5 => 4.1.2
    vite: ^4.4.2 => 4.4.8

Severity

serious, but I can work around it

Possible Cause / Fix

The issue lies in the build_selector function.

When we make request like this fetch(new Request(url))

if opts?.headers is true which creates a data-hash=[...] property in the selector

but when we make a request like this fetch(url)

if opts?.headers is false and data-hash property is not there in the selector string.

So either we need to changes serialize_data.js fn or the build_selector function to account for empty headers when using the request object

we can do something like this to detect is headers are empty and generate hash accordingly

function isHeaderEmpty(headers) {
	if (headers == null) {
		return true
	}

	if (headers instanceof Headers) {
		return !headers.values().length
	}

	return false
}

/**
 * Build the cache key for a given request
 * @param {URL | RequestInfo} resource
 * @param {RequestInit} [opts]
 */
function build_selector(resource, opts) {
	const url = JSON.stringify(resource instanceof Request ? resource.url : resource);

	let selector = `script[data-sveltekit-fetched][data-url=${url}]`;

	console.log(opts);
	if (!isHeaderEmpty(opts?.headers) || opts?.body) {
		/** @type {import('types').StrictBody[]} */
		const values = [];
		console.log(opts.headers, opts.headers instanceof Headers);

		if (opts.headers) {
			values.push([...new Headers(opts.headers)].join(','));
		}

		if (opts.body && (typeof opts.body === 'string' || ArrayBuffer.isView(opts.body))) {
			values.push(opts.body);
		}

		selector += `[data-hash="${hash(...values)}"]`;
	}

	return selector;
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions