I am trying to port a nuxt 2 web app to Sveltekit (version 5 I guess) and have run into this hiccup with respect to urls and routing.
Route Structure in Nuxt 2
routes.js
I am trying to achieve the following route for a master detail view
Route | What is shown on desktop | What is shown on mobile |
---|---|---|
example.com |
list + detail | list |
example.com/news/<item-id>/<title> |
list + detail | detail |
example.com/news?filter=<some-filter>&search=<search-term> |
list + detail | list |
example.com/news/<some-tag> |
list + detail | list |
example.com/news/<some-tag>?filter=<some-filter>&search=<search-term> |
list + detail | list |
example.com/news/<some-tag>/<item-id>/<title> |
list + detail | detail |
The code for the above routing structure in nuxt 2 using @nuxtjs/router looks like this
{
path: '/news/:tag?',
alias: '/',
component: Index,
children: [
{
path: '',
name: 'NewsList',
component: NewsListWrapper,
props: true,
},
{
path: '/news/:tag?/:id([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})/:title',
name: 'NewsDetail',
component: NewsDetailWrapper,
props: true,
},
],
},
The above index component in Nuxt 2 handles everything
I am trying to translate this routing structure to SvelteKit and I am running into trouble. I'm a beginner in SvelteKit.
Route Structure in SvelteKit
src/routes/
├── +page.svelte # Handles example.com
├── news/
│ ├── +page.svelte # Handles example.com/news and query parameters
│ ├── [tag]/
│ │ ├── +page.svelte # Handles example.com/news/<some-tag> and query parameters
│ │ ├── [item-id]/
│ │ │ └── [title]/
│ │ │ └── +page.svelte # Handles example.com/news/<some-tag>/<item-id>/<title>
│ └── [item-id]/
│ └── [title]/
│ └── +page.svelte # Handles example.com/news/<item-id>/<title>
There are 4 +page.svelte
components. How to achieve the same layout as Nuxt 2 using a single +page.svelte
?
You can use the new reroute
hook in the hooks.ts
file to redirect any path that matches 'example.com/news'
to your main component in something like this:
export const reroute: Reroute = ({ url }) => {
if ( url.pathname.startsWith("/news") ) {
// maps to `src/routes/news`
return `/news`
}
}
Then use the load function of that route in the +page.js
file to pass the pathname to your +page.svelte
component like this:
//+page.js
export const load = ({ url }) => {
const { pathname } = url;
return {
pathname
};
};
Then you can match the pathname to render your component using that index object you showed, something like this:
<script>
import Index from 'path/to/Index/'
import NewsListWrapper from 'path/to/NewsListWrapper/'
import NewsDetailWrapper from 'path/to/NewsDetailWrapper/'
//get the data from the load function
let { data } = $props();
let pathname = $derived(data.pathname)
//changed to simple array that will be used in the #each block
const routes = [
{
path: '/news/:tag?',
alias: '/',
component: Index
},
{
path: '',
name: 'NewsList',
component: NewsListWrapper,
props: true,
},
{
path: '/news/:tag?/:id([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})/:title',
name: 'NewsDetail',
component: NewsDetailWrapper,
props: true,
},
]
</script>
{#each routes as route}
{#if route.path === pathname}
{@render route.component()}
{/if}
{/each}w
Obviously there will be some quirks to fix but I hope this helps!