Search code examples
sveltesveltekit

How to achieve the nuxt 2 routing structure below in Sveltekit using a single +page.svelte?


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?


Solution

  • 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!