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.
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);