Redirects for Nuxt Dynamic Nested Routes
Unknown dynamic nested routes in NuxtJS allow you to serve the same page for URLs of varying depths that aren't statically known in advance. They can be based on data in an external data source such as a hierarchy of folders or categories, for example.
In such a scenario, you'll need to decide how to handle URLs that don't match the data in the data source. Redirecting to another valid URL can often be a good strategy.
The Vue way
In Vue.js, redirecting can be implemented in navigation guards. The beforeRouteEnter
navigation guard is called before the page loads after navigating to a route. It allows you to redirect to a different URL:
@Component({
async beforeRouteEnter(
to: Route,
_from: Route,
next: NavigationGuardNext<Vue>
) {
next(await getUrlForRedirect(to.path));
},
})
export default class RedirectPage extends Vue {}
However, it doesn't get invoked when navigating between different URLs that match the same route. To handle those as well, the beforeRouteUpdate
navigation guard must also be implemented:
@Component({
// unchanged beforeRouteEnter skipped
async beforeRouteUpdate(
to: Route,
_from: Route,
next: NavigationGuardNext<Vue>
) {
next(await getUrlForRedirect(to.path));
},
})
export default class RedirectPage extends Vue {}
In NuxtJS, these navigation guards also work in SSR (server-side rendering) mode. However, the final URL change happens on the client even if the redirect target page is rendered on the server. The HTTP status code for the original URL is still 200 OK. Since semantically a redirect happened, this might not be best for search engine optimization.
The Nuxt way
In NuxtJS, the redirection can alternatively be implemented as a named middleware which causes a real HTTP redirect. Optionally, a custom HTTP status code can be specified for it:
export default async function (context: Context) {
const redirectUrl = await getUrlForRedirect(context.route.path);
if (redirectUrl) {
context.redirect(301, redirectUrl);
}
}
The middleware must be associated with a page using its name (matching its filename in the middleware
folder):
@Component({
middleware: "redirect",
})
export default class RedirectPage extends Vue {}
The middleware approach works in NuxtJS even in full SPA (single-page application) mode which makes it the preferred way of doing redirects in similar scenarios.
I created a repository in GitHub with different approaches described here as separate commits so that they can all be easily tested.
If you need to do a redirect before a page loads, Vue.js allows you to do that in the navigation guards. With server-side rendering, this has the disadvantage of not being able to change the HTTP status code to match the redirect behavior. In NuxtJS, named middleware can be used to do a real redirect instead and optionally specify the HTTP status code of the response.