Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/forty-lions-give.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sveltejs/kit': patch
---

[breaking] resolve relative urls from the target page when using load's fetch
41 changes: 37 additions & 4 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,11 +578,44 @@ export function create_client({ target, session, base, trailing_slash }) {
node.uses.stuff = true;
return { ...stuff };
},
fetch(resource, info) {
const requested = typeof resource === 'string' ? resource : resource.url;
add_dependency(requested);
async fetch(resource, init) {
let requested;

if (typeof resource === 'string') {
requested = resource;
} else {
requested = resource.url;

// we're not allowed to modify the received `Request` object, so in order
// to fixup relative urls we create a new equivalent `init` object instead
init = {
// the request body must be consumed in memory until browsers
// implement streaming request bodies and/or the body getter
body:
resource.method === 'GET' || resource.method === 'HEAD'
? undefined
: await resource.blob(),
cache: resource.cache,
credentials: resource.credentials,
headers: resource.headers,
integrity: resource.integrity,
keepalive: resource.keepalive,
method: resource.method,
mode: resource.mode,
redirect: resource.redirect,
referrer: resource.referrer,
referrerPolicy: resource.referrerPolicy,
signal: resource.signal,
...init
};
}

// we must fixup relative urls so they are resolved from the target page
const normalized = new URL(requested, url).href;
add_dependency(normalized);

return started ? fetch(resource, info) : initial_fetch(resource, info);
// prerendered pages may be served from any origin, so `initial_fetch` urls shouldn't be normalized
return started ? fetch(normalized, init) : initial_fetch(requested, init);
},
status: status ?? null,
error: error ?? null
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export function get() {
return {
body: {
answer: 42
}
};
}

/** @type {import('@sveltejs/kit').RequestHandler} */
export async function post({ request }) {
return {
body: {
question: await request.text()
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script context="module">
/** @type {import('@sveltejs/kit').Load} */
export async function load({ fetch }) {
const get = await fetch('fetch-relative.json');
const post = await fetch('fetch-relative.json', { method: 'post', body: '?' });

return {
props: { ...(await get.json()), ...(await post.json()) }
};
}
</script>

<script>
export let answer;
export let question;
</script>

<h1>the answer is {answer}</h1>
<h2>the question was {question}</h2>
1 change: 1 addition & 0 deletions packages/kit/test/apps/basics/src/routes/load/index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<h1>bar == {foo}?</h1>

<a href="/load/fetch-request">fetch request</a>
<a href="/load/fetch-relative">fetch relative</a>
<a href="/load/fetch-credentialed">fetch credentialed</a>
<a href="/load/fetch-headers">fetch headers</a>
<a href="/load/large-response">large response</a>
Expand Down
7 changes: 7 additions & 0 deletions packages/kit/test/apps/basics/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,13 @@ test.describe.parallel('Load', () => {
expect(await page.textContent('h1')).toBe('the answer is 42');
});

test('fetch resolves urls relatively to the target page', async ({ page, clicknav }) => {
await page.goto('/load');
await clicknav('[href="/load/fetch-relative"]');
expect(await page.textContent('h1')).toBe('the answer is 42');
expect(await page.textContent('h2')).toBe('the question was ?');
});

test('handles large responses', async ({ page }) => {
await page.goto('/load');

Expand Down