sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
18.11k stars 1.84k forks source link

`pushHistory` throws an error when used inside a `$effect` hook #12248

Open lts20050703 opened 1 month ago

lts20050703 commented 1 month ago

Describe the bug

pushHistory throws an error when used inside a $effect hook (Logs included below)

Reproduction

$effect(() => {
    pushState("", { current_page: $state.snapshot(current_page) })
})

Link to SvelteLab repo: https://www.sveltelab.dev/0w91yk8my729dku

Logs

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '$set')
    at pushState (client.js?v=0255b54e:1884:7)
    at $effect (+page.svelte:128:3)
    at execute_reaction_fn (chunk-O56VML7M.js?v=0255b54e:1560:29)
    at execute_effect (chunk-O56VML7M.js?v=0255b54e:1681:20)
    at flush_queued_effects (chunk-O56VML7M.js?v=0255b54e:1731:7)
    at flush_queued_root_effects (chunk-O56VML7M.js?v=0255b54e:1717:9)
    at flush_sync (chunk-O56VML7M.js?v=0255b54e:1832:7)
    at flush_sync (chunk-O56VML7M.js?v=0255b54e:1837:7)
    at hydrate (chunk-WZH6WDHG.js?v=0255b54e:476:12)
    at new Svelte4Component (chunk-WZH6WDHG.js?v=0255b54e:647:70)

System Info

System:
    OS: Linux 6.5 KDE neon 6.0 6.0
    CPU: (8) x64 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
    Memory: 7.84 GB / 15.40 GB
    Container: Yes
    Shell: 3.7.1 - /usr/bin/fish
  Binaries:
    Node: 22.2.0 - ~/.local/share/nvm/v22.2.0/bin/node
    Yarn: 1.22.21 - ~/.local/share/nvm/v22.2.0/bin/yarn
    npm: 10.8.0 - ~/.local/share/nvm/v22.2.0/bin/npm
    pnpm: 8.15.3 - ~/.local/share/nvm/v22.2.0/bin/pnpm
    bun: 1.1.8 - ~/.bun/bin/bun
  Browsers:
    Brave Browser: 125.1.66.110
  npmPackages:
    @sveltejs/adapter-static: ^3.0.1 => 3.0.1 
    @sveltejs/kit: ^2.5.9 => 2.5.9 
    @sveltejs/vite-plugin-svelte: ^3.1.0 => 3.1.0 
    svelte: ^5.0.0-next.136 => 5.0.0-next.136 
    vite: ^5.2.11 => 5.2.11

Severity

serious, but I can work around it

Additional Information

Workaround: put the pushState inside a setTimeout like this

$effect(() => {
    current_page
    setTimeout(() => pushState("", { current_page: $state.snapshot(current_page) }))
})

vite.config.js

import { sveltekit } from "@sveltejs/kit/vite"
import { defineConfig } from "vite"
export default defineConfig({
    plugins: [sveltekit()],
    build: { target: "es2015" },
    server: { hmr: false }
})

svelte.config.js

import adapter from "@sveltejs/adapter-static"
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte"
/** @type {import('@sveltejs/kit').Config} */
export default {
    extensions: [".svelte"],
    preprocess: [ vitePreprocess() ],
    kit: { adapter: adapter() },
    compilerOptions: { runes: true }
}
kettei-sproutty commented 2 weeks ago

I don't know if this can be useful, I wanted to give a shot to this but I don't really know where to put my hands on.

As far as i saw root is assigned in kit/src/runtime/client/client.js:434 in initialize function, but the effect is executed during the creation of root by sveltejs/svelte/blob/main/packages/svelte/src/internal/client/runtime.js:542, so everything that is called during $effect that uses root, such as pushState or replaceState, will throw an Error, as root is not yet assigned.

I hope this can be helpful, I'm not sure if this is even the right place to write this.

frederikhors commented 2 weeks ago

This is huge!