Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: adjust fetch error message on the server #8551

Merged
merged 7 commits into from
Feb 9, 2023
Merged

Conversation

dummdidumm
Copy link
Member

probably closes #8536, but let's wait a little for the OP to answer my question first.

Please don't delete this checklist! Before submitting the PR, please make sure you do the following:

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.

Tests

  • Run the tests with pnpm test and lint the project with pnpm lint and pnpm check

Changesets

  • If your PR makes a change that should be noted in one or more packages' changelogs, generate a changeset by running pnpm changeset and following the prompts. Changesets that add features should be minor and those that fix bugs should be patch. Please prefix changeset messages with feat:, fix:, or chore:.

@changeset-bot
Copy link

changeset-bot bot commented Jan 16, 2023

🦋 Changeset detected

Latest commit: b18c839

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

if (typeof info === 'string' && !/^\w+:\/\//.test(info)) {
await Promise.resolve(); // allows people to use malformed fetch urls in `{#await ..}` (native fetch error is swallowed by those)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This came out of #8536 (comment) , doing {#await fetch('/foo')}.. worked previously, because the error was swallowed.

Either we treat this as a potential breaking change because this worked previously; also it may be deliberate to rely on this behavior on the server to save some code ("yeah this will fail but I don't care, it will work on the client then"). Or we treat it as a bug that this ever worked and revert the 2nd commit of this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favour of reverting — this behaviour seems much too magical to me

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's magical about it for you? That this relies on specific behavior of #await? I'm not sure if that's the case but maybe this also works if we omit that line if the function is marked as async? Would that be too magical, too?
Do you think it's edge case enough that we can mark this as "this merely uncovered a bug in your code and is not a breaking change"?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rule 1: don't swallow errors.

If my intent is to have an await that only works in the browser, then that's the code I should write. It's far more likely that someone simply didn't understand the mechanics of await and fetch, and this kind of benevolent interference prevents them from developing that understanding (while causing confusion to someone who understands why it shouldn't work).

This definitely qualifies as 'we found a bug in your code', yeah

throw new Error(
`Cannot use relative URL (${info}) with global fetch use \`event.fetch\` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis`
`Cannot use relative URL (${info}) with global fetch on the server. If this is called inside a \`load\` function, use \`event.fetch\` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use event.fetch inside hooks and request handlers as well. But I'm not sure that changing the text to 'If this is called inside a load function, a request handler or a hook,' makes sense because apart from init code, all server-only code runs in the context of responding to an event.

Not 100% sure what the solution is but I think we need to keep brainstorming

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The primary goal is to give people an error message that unblocks them/gives them pointers what to do instead.
What about

Suggested change
`Cannot use relative URL (${info}) with global fetch on the server. If this is called inside a \`load\` function, use \`event.fetch\` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis`
`Cannot use relative URL (${info}) with global fetch on the server. If this coming from a fetch call inside a component, ensure that it is not run eagerly on the server, for example by wrapping the call inside \`onMount\`. Else, use \`event.fetch\` instead: https://kit.svelte.dev/docs/web-standards#fetch-apis`

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can intercept eager fetch calls during component rendering. What about doing this, and keeping the existing error message for other cases?

+// src/runtime/server/page/render.js
+const { fetch } = globalThis;
+globalThis.fetch = () => {
+	throw new Error(
+		'Cannot call `fetch` eagerly during SSR — put your `fetch` calls inside `onMount` or `load` instead'
+	);
+};

rendered = options.root.render(props);

+globalThis.fetch = fetch;

Copy link
Member Author

@dummdidumm dummdidumm Jan 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oooh yeah that's nice, will adjust (though not to what you have there, that's just too breaking for people who still eagerly have it inside #await)!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it though? People who are doing that shouldn't be, and it's really a bug that it's allowed. If I was making server-side requests that had no effect but were costing me actual dollars, I wouldn't consider it a breaking change if my framework stopped me from doing that

Copy link
Member Author

@dummdidumm dummdidumm Jan 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The related issue has three thumbs up and one more person saying they had to adjust all their #await imports, I'm not sure if this kind of rigourus throwing of an error still not counts as "not a breaking change", so I'm against that. I'm all for emitting a warning though, and make it an error in 2.0.
(Or maybe we have some kind of async server components then and it is allowed 😅 )

@dummdidumm
Copy link
Member Author

@Rich-Harris is this good to merge for you? If so, could you approve it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot use relative URL with global fetch in .svelte file
2 participants