sveltesvelte-5page.js

Svelte 5 and page.js routing problem with external state


I tried to use page.js for client side routing within a Svelte 5 application, but encountered a strange phenomenon: When I put the routing logic within the App.svelte component everything works fine:

<!-- App.svelte -->
<script lang="ts">
    import router from "page"
    import Index from "./pages/index.svelte"
    import About from "./pages/about.svelte"
    import NotFound from "./pages/404.svelte"

    let Page = $state(Index)

    router("/", () => Page = Index)
    router("/about", () => Page = About)
    router("*", () => Page = NotFound)

    router.start()
</script>

<Page/>

However, as soon as I try to extract this logic into an external module the routing fails and the links to other pages do nothing:

// router.svelte.ts
import router from "page"
import Index from "../pages/index.svelte"
import About from "../pages/about.svelte"
import NotFound from "../pages/404.svelte"

let page = $state(Index);

export const createRouter = () => {

    const registerRoutes = () => {
        router("/", () => page = Index)
        router("/about", () => page = About)
        router("*", () => page = NotFound)

        router.start()
    }

    return {
        get page() {
            return page
        },
        registerRoutes,
    }
}

Now when I call this router from my App.svelte file the page loads correctly initially, but the links between pages do not work anymore:

<!-- App.svelte -->
<script lang="ts">
    import {createRouter} from "./router.svelte";
    const router = createRouter()
    router.registerRoutes()
    let Page = router.page
</script>

<Page/>

I assume there's simply a misunderstanding on my part about the reactivity involved, but maybe someone could point me in the right direction.


Solution

  • The problem is:

    let Page = router.page
    

    This is a one-time assignment, so subsequent changes to the page do not update the variable. You would need a $derived here:

    let Page = $derived(router.page);