Skip to content

fix: fix popState race-condition when not using SSR #12925

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

Merged

Conversation

aloisklink
Copy link
Contributor

When loading a non-SSR page and pressing the browser's back button while the page is still loading, it's possible for current.url to still be the default value of null, which then causes the popState function to throw the following uncaught error:

Uncaught (in promise) TypeError: Cannot destructure property 'href' of 'object null' as it is null.
    at strip_hash (url.js?v=3a24e001:84:30)
    at client.js?v=3a24e001:2227:52

This is from

const is_hash_change = strip_hash(location) === strip_hash(current.url);

See #12924 for a reproduction/example videos.


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

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:.

Edits

  • Please ensure that 'Allow edits from maintainers' is checked. PRs without this option may be closed.

When loading a non-SSR page and pressing the browser's back button while
the page is still loading, it's possible for `current.url` to still be
the default value of `null`, which then causes the `popState` function
to throw the following uncaught error:

```
Uncaught (in promise) TypeError: Cannot destructure property 'href' of 'object null' as it is null.
    at strip_hash (url.js?v=3a24e001:84:30)
    at client.js?v=3a24e001:2227:52
```

This is from
https://github.com/sveltejs/kit/blob/e41a8e24b71cb9e9ee249ddfe732a3d0721d40bf/packages/kit/src/runtime/client/client.js#L2234
Copy link

changeset-bot bot commented Oct 31, 2024

🦋 Changeset detected

Latest commit: 758a804

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

@benmccann
Copy link
Member

I don't understand the comment where current.url is initialized:

// @ts-ignore - we need the initial value to be null

I wonder if that's really true or why we need that to be true. Perhaps we need a separate variable to track whether the current page is initialized?

I feel like this code has gotten quite complicated and there needs to be some higher-level documentation around what states are expected at what times for what reasons, etc. I'm uncomfortable with making a change that might just be papering over an issue without really understanding what the correct fix is one way or the other. Simon or Rich might have a better understanding of this code and be able to weigh in here

@aloisklink
Copy link
Contributor Author

I don't understand the comment where current.url is initialized:

Neither do I, to be honest! There are other places where we (I say we, but it's mainly @dummdidumm!) are checking for current.url being null.

const url_changed = current.url ? id !== current.url.pathname + current.url.search : false;


Perhaps we need a separate variable to track whether the current page is initialized?

I think we could just get away with making the type in

URL | null. The problem is that there are many places we'd then need to add checks to see if the current page is initialized (and I think in most places, these functions are only called if the page is already initialized).


I'm uncomfortable with making a change that might just be papering over an issue without really understanding what the correct fix is one way or the other. Simon or Rich might have a better understanding of this code and be able to weigh in here

👍 One thing I've also noticed is that this goto is an async function, but it's missing an await (I've got no idea if this is intentional or not by @dummdidumm). I'm pretty sure adding an await here would also fix this issue, but since I'm not sure what the implications are, just "papering over" this fix seems safer.

goto(location.href, { replaceState: true });

@eltigerchino eltigerchino added the needs-decision Not sure if we want to do this yet, also design work needed label Nov 13, 2024
Copy link
Member

@dummdidumm dummdidumm left a comment

Choose a reason for hiding this comment

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

thank you!

@dummdidumm dummdidumm merged commit 1bedcc1 into sveltejs:main Jan 13, 2025
10 checks passed
@github-actions github-actions bot mentioned this pull request Jan 13, 2025
@aloisklink aloisklink deleted the fix/fix-a-popState-race-condition branch January 14, 2025 04:56
@MathiasWP
Copy link
Contributor

Maybe this closes #13145?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
needs-decision Not sure if we want to do this yet, also design work needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Race-condition when pressing **Back** while the page is still loading when not using SSR
5 participants