user14131782
user14131782

Reputation: 1068

Vue Router - catch all wildcard not working

I'm using Vue Router with Vue 3 and am trying to add a catch-all route to redirect the user if they try and access an invalid URL. When I try and use the wildcard (*), i get the following error logged to the console:

Uncaught Error: A non-empty path must start with "/"
    at tokenizePath (vue-router.esm.js?8c4f:975)
    at createRouteRecordMatcher (vue-router.esm.js?8c4f:1106)
    at addRoute (vue-router.esm.js?8c4f:1190)
    at eval (vue-router.esm.js?8c4f:1335)
    at Array.forEach (<anonymous>)
    at createRouterMatcher (vue-router.esm.js?8c4f:1335)
    at createRouter (vue-router.esm.js?8c4f:2064)
    at eval (index.js?a18c:26)
    at Module../src/router/index.js (app.js:1402)
    at __webpack_require__ (app.js:854)

I'm assuming this is because I don't prepend the path containing the asterisk with a '/', but if I do this then the catch all doesn't work. Here are my routes:

imports...

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/user',
    name: 'User',
    // route level code-splitting
    // this generates a separate chunk (user.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "user" */ '../views/user/User.vue'),
    children: [{path: '', component: UserStart}, {path: ':id', component: UserDetail}, {path: ':id/edit', component: UserEdit, name: 'userEdit'}]
  },
  {path: '/redirect-me', redirect: '/user'},
  {path: '*', redirect: '/'}
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router

The wildcard route is the last object in the routes array. Does anyone know what I'm doing wrong?

Upvotes: 38

Views: 45982

Answers (2)

Roland
Roland

Reputation: 27819

Personally, for Vue 2's * (star or catch all) routes in Vue 3 I use:

{
  path: '/:pathMatch(.*)*', <== THIS
  name: 'not-found',
  component: NotFound
}

Catch all routes (*, /*) must now be defined using a parameter with a custom regex:

The parameter name can be whatever you want like catchAll, pathMatch, noPage etc

{
  path: '/:pathMatch(.*)*', //will match everything and put it under `$route.params.pathMatch`
  name: 'not-found',
  component: NotFound
}
{ 
  path: '/user-:afterUser(.*)',// will match anything starting with `/user-` and put it under `$route.params.afterUser`
  component: UserGeneric
}


/:pathMatch(.*)*

  • The last * it is necessary if you plan on directly navigating to the not-found route using its name.

  • If you omit it the / character in params, it will be encoded when resolving or pushing.

For example if you use path: /:pathMatch(.*) (note: without the last asterisk) and you go to /user/not-found (a page that doesn't exists) the this.$route.params.pathMatch will be a string => 'user/not-found'

// bad example if using named routes:
router.resolve({
  name: 'bad-not-found',
  params: { pathMatch: 'not/found' },
}).href // '/not%2Ffound'

Instead, if you use path: /:pathMatch(.*)* (note: with asterisk) this.$route.params.pathMatch will be an array ['user', 'not-found']

// good example:
router.resolve({
  name: 'not-found',
  params: { pathMatch: ['not', 'found'] },
}).href // '/not/found'

Please read docs: From migration from vue 2 to vue 3 and Catch all / 404 Not found Route

Upvotes: 22

Raj
Raj

Reputation: 1665

Catch all routes (/*) must now be defined using a parameter with a custom regex: /:catchAll(.*)

For example:

    {
      // path: "*",
      path: "/:catchAll(.*)",
      name: "NotFound",
      component: PageNotFound,
      meta: {
        requiresAuth: false
      }
    }

Upvotes: 81

Related Questions