Skip to content

feat: use devalue for pushState/replaceState #14129

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

GauBen
Copy link
Contributor

@GauBen GauBen commented Aug 6, 2025

Hi!

Closes #14128: pushState/replaceState now use devalue+transport to serialize custom objects

I kept it simple, not sure if the idea will be accepted


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

Edits

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

Copy link

changeset-bot bot commented Aug 6, 2025

🦋 Changeset detected

Latest commit: df5d01b

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 Minor

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

@svelte-docs-bot
Copy link

@GauBen GauBen force-pushed the feat/pushstate-devalue branch from e47baa8 to ac02814 Compare August 6, 2025 21:04
@Rich-Harris
Copy link
Member

Rich-Harris commented Aug 7, 2025

I don't think we can do this. Today, if you try and do something like this...

<script>
  import { page } from '$app/state';
  import { pushState } from '$app/navigation';
</script>

<section>
  <button
    onclick={() => {
      let object = $state({ count: 0 });
      pushState('/', { object });
    }}
  >
    push state
  </button>

  {#if page.state?.object}
    <p>{page.state.object.count}</p>

    <button onclick={() => (page.state.object.count += 1)}>
      increment page.state.object.count
    </button>
  {/if}
</section>

...SvelteKit will yell at you, because you can't serialize a proxy. With this PR, if you click the first button, page.state.object becomes a reactive proxy. You can increment page.state.object.count by clicking the button. But if you navigate back, and then forward, object.count will be a non-reactive deserialized object. And so on. It's basically making a promise it can't keep. I think the current approach is probably better, even if (or maybe because) it's more restrictive

@GauBen
Copy link
Contributor Author

GauBen commented Aug 7, 2025

(Technically it's the browser that yells at me if I give it a proxy, devalue will happily serialize it)

Would it be acceptable to $state.snapshot the value given to pushState? For your specific example, the behavior would then be consistent before and after a history state pop (I guess)

In dev we can also add a warning that reactivity will be lost for history states if that makes the behavior less surprising

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.

Use transport for pushState/replaceState serialization
2 participants