How to fetch routes from API and add registered them on the app to be available on SSR

I'm migrating a Vue 3 SSR project to Nuxt. But I'm facing a challenge with the routes. The project has a single file page working as a "catch-all" but named ScenePage.vue The app works with routes being declared on the backend, as the same for the content of each page (on the frontend we "just" build components, that when a route is requested we will receive a JSON with the structure of the pages, including the components and the props to populate the components) The challenge on Nuxt because of the file-based route system is to replicate this correctly. Already tried a few options, but none of them match the requirements - using router.options works 50% as it's only executed once, and my app receives more routes after the user logs in - pages:extend hook on nuxt.config has a similar problem as it also is executed only once - module + plugin, it doesn't work on SSR, only on the client - server middleware + plugin + composable, I see the list of routes from the request, also see that it is passed using event.context.routes and then available on nuxtApp.payload.routes, but it appears that the routes aren't registered as I end up on the 404, but from the logs I have added I see after the [Vue Router warn]: No match found for location with path "/" Any help would be very helpful Thanks
2 Replies
kapa.ai
kapa.ai2w ago
Hi @Victor Neves. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the knowledge sources provided, I can offer some guidance on how to fetch routes from an API and register them for SSR in Nuxt 3. However, it's important to note that the exact solution for your specific use case might require some additional customization. One approach you can consider is using the prerender:routes Nuxt hook in combination with a custom router.options.ts file. This method allows you to dynamically add routes before prerendering and during runtime. 1. First, you can use the prerender:routes hook to fetch and add routes during the build process:
// nuxt.config.ts
export default defineNuxtConfig({
hooks: {
async "prerender:routes"(ctx) {
const { routes } = await fetch("<https://your-api.com/routes">).then(
(res) => res.json()
);
for (const route of routes) {
ctx.routes.add(route.path);
}
},
},
});
// nuxt.config.ts
export default defineNuxtConfig({
hooks: {
async "prerender:routes"(ctx) {
const { routes } = await fetch("<https://your-api.com/routes">).then(
(res) => res.json()
);
for (const route of routes) {
ctx.routes.add(route.path);
}
},
},
});
This hook is called before prerendering and allows you to register additional routes, as described in the Nuxt documentation on prerendering. 2. For runtime route handling, you can use a custom router.options.ts file:
// app/router.options.ts
import type { RouterConfig } from '@nuxt/schema'

export default <RouterConfig> {
routes: () => {
// Fetch routes from your API
return fetch('<https://your-api.com/routes'>)
.then(res => res.json())
.then(routes => routes.map(route => ({
name: route.name,
path: route.path,
component: () => import('~/pages/ScenePage.vue')
})))
}
}
// app/router.options.ts
import type { RouterConfig } from '@nuxt/schema'

export default <RouterConfig> {
routes: () => {
// Fetch routes from your API
return fetch('<https://your-api.com/routes'>)
.then(res => res.json())
.then(routes => routes.map(route => ({
name: route.name,
path: route.path,
component: () => import('~/pages/ScenePage.vue')
})))
}
}
This approach allows you to define a custom routes function that can be awaited, as mentioned in the Nuxt GitHub pull request #27644. 3. To handle routes that are received after user login, you might need to implement a client-side solution. One possibility is to use a plugin in combination with a composable:
// plugins/dynamic-routes.ts
export default defineNuxtPlugin(async (nuxtApp) => {
const router = useRouter()

// Function to add routes
const addRoutes = (newRoutes) => {
newRoutes.forEach(route => {
router.addRoute({
name: route.name,
path: route.path,
component: () => import('~/pages/ScenePage.vue')
})
})
}

// Make the function available in the Nuxt app
nuxtApp.provide('addRoutes', addRoutes)
})

// composables/useRoutes.ts
export const useRoutes = () => {
const nuxtApp = useNuxtApp()

const fetchAndAddRoutes = async () => {
const { routes } = await fetch('<https://your-api.com/routes'>).then(res => res.json())
nuxtApp.$addRoutes(routes)
}

return {
fetchAndAddRoutes
}
}
// plugins/dynamic-routes.ts
export default defineNuxtPlugin(async (nuxtApp) => {
const router = useRouter()

// Function to add routes
const addRoutes = (newRoutes) => {
newRoutes.forEach(route => {
router.addRoute({
name: route.name,
path: route.path,
component: () => import('~/pages/ScenePage.vue')
})
})
}

// Make the function available in the Nuxt app
nuxtApp.provide('addRoutes', addRoutes)
})

// composables/useRoutes.ts
export const useRoutes = () => {
const nuxtApp = useNuxtApp()

const fetchAndAddRoutes = async () => {
const { routes } = await fetch('<https://your-api.com/routes'>).then(res => res.json())
nuxtApp.$addRoutes(routes)
}

return {
fetchAndAddRoutes
}
}
You can then call fetchAndAddRoutes after the user logs in to add new routes dynamically. It's worth noting that this solution might not fully solve your SSR requirements, as dynamically added routes on the client side won't be available during server-side rendering. For a fully SSR-compatible solution, you might need to explore more advanced techniques or consider restructuring your application's routing approach. Remember that Nuxt 3's routing system is designed to work with file-based routing, so adapting a completely dynamic routing system might require some compromises or custom solutions not covered in the standard documentation. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2w ago
<@940674295531728938> Kapa.ai is still learning and improving, please let me know how I did by reacting below.

Did you find this page helpful?