Nuxt.js: Redirect doesn't work in SPA mode from plugin

Created on 6 Dec 2018  路  12Comments  路  Source: nuxt/nuxt.js

Version

v2.3.4

Reproduction link

https://codesandbox.io/s/5vj0ml10zk

Steps to reproduce

  1. Install starter template from https://github.com/nuxt-community/starter-template
  2. Update nuxt to 2.3.4
  3. Create page about.vue
  4. Create plugins/redirect.js with content:

export default ctx => {
console.log("redirect");
return ctx.redirect("/about");
};

5.Enable plugin in nuxt.config.js

  1. Go to main page
  2. Probably you will see 'redirect' message in console but you won't redirect to /about page.

What is expected ?

Redirect from one page to another from plugin in spa mode, becouse middleware doesn't fire on first load.

What is actually happening?

Redirect doesn't work. Redirect function only work with non-existed paths, but it doesn't want to redirect to real routes in SPA mode.

This bug report is available on Nuxt community (#c8278)
bug-report pending workaround available

Most helpful comment

I also have this problem, and I am using a middleware.

All 12 comments

Thanks for your contribution to Nuxt.js!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of nuxt-edge
  2. Comment the steps to reproduce it

Issues that are labeled as 馃晲Pending will not be automatically marked as stale.

I also have this problem, and I am using a middleware.

Thanks for your contribution to Nuxt.js!
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
If you would like this issue to remain open:

  1. Verify that you can still reproduce the issue in the latest version of nuxt-edge
  2. Comment the steps to reproduce it

Issues that are labeled as 馃晲Pending will not be automatically marked as stale.

redirect work on afterEach

  ctx.app.router.afterEach(() => {
    return ctx.redirect("/about");
  });

but it will have a blinked page change

We've got the same error. Version 2.6.1. SPA mode. Neither redirect nor error doesn't work from plugin. See the reproduction link above.

Hey guys I did a little research about this issue.
It seems if trying to call router.push to push to a path which has a async route component before the root vue component was created, the push call will be aborted.
But if you call router.push after create the root vue component, then vue router will wait the async route to be resolved and successfully navigate to that route.

And this is exactly the case that nuxt does, plugins was called before created the root app vue component, so app.redirect, which internally use router.push will be failed.

btw, if try push to an invalid route, or non-async route(manually add a non-async route), everything would be fine.

https://github.com/nuxt/nuxt.js/blob/19fbbb6ef66b835cf4014fd7174e5472f0c763f4/packages/vue-app/template/index.js#L169-L184

try open this jsfiddle and test it out: https://jsfiddle.net/qLz5ew9t/

<!-- index.html -->
<html>
  <head>
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  </head>
  <body>
    <div id="app">
      test
    </div>
    <script src="./index.js"></script>
  </body>
</html>
const resolveComponent = () => {
  return new Promise((rs) => {
    setTimeout(() => {
      rs({})
    }, 3000)
  })
}

const router = new VueRouter({
  mode: 'history',
  routes: [{
    path: "/async",
    component: resolveComponent,
  },{
    path: "/sync",
    component: {},
  }],
})


const tryPushSyncRoute = () => {
  router.push('/sync', () => {
    console.log('success')
  }, () => {
    console.trace('abort')
  })
}

const tryPushAsyncRoute = () => {
  router.push('/async', () => {
    console.log('success')
  }, () => {
    console.trace('abort')
  })
}

// push before new Vue
tryPushAsyncRoute()
// tryPushSyncRoute()

const app = new Vue({
  router,
  mounted() {
    console.log('mounted')
  },
  destoryed() {
    console.log('destoryed')
  }
})

// try comment above router push call and uncomment below
// push after new Vue

// tryPushAsyncRoute()
// tryPushSyncRoute()

app.$mount('#app')

So, possible solutions is try avoiding use redirect in plugins, instead, using redirect in router-middlewares.
It should be fixed in next nuxt patch version with [email protected]
https://github.com/vuejs/vue-router/issues/2712

After upgrading to [email protected] with [email protected], it seems ctx.redirect in plugins works in my projects, but you will get a page flashing before redirect complete. I think it's still better to do redirect after create the root vue instance(in middleware).

If we want to use redirect perfectly without page flashing, we have to call router.push after create vue instance, so we can do this by caching ctx.redirect calls before create root vue instance and call them right after create vue instance. Any thoughts about this approach?

I solved this problem using app.router.push("...") It's working for me.

export default ({ store, route, app }, inject) => {
  store.subscribe((mutation, state) => {
    console.log("app: ", app);

    if (mutation.type == "auth/login") {
      app.router.push("/user");
      console.log("auth logged In");
    }

    if (mutation.type == "auth/logout") {
      app.router.push("/login");
      console.log("auth logged Out");
    }
  });
};

experiencing the same problem as above, using app.router.push does not solve the problem.

Any update on this? I'm facing the same issue trying to redirect inside process.client.

I can confirm, that context.redirect doesn't work in plugin with SPA mode.
Currently, i'm trying [email protected] and [email protected]

Workaround with app.router.push doesn't work, it throws this is undefined

It's not possible to use context.redirect and context.error in client-side Nuxt plugin as it'd lead to hydration errors (client content would be different from what it'd expect from the server).

A valid workaround is using window.onNuxtReady(() => { window.$nuxt.$router.push('your-route') }) if you really have to.

There shouldn't be many use cases for that scenario though.

Closing here as it's not really "fixable".

Was this page helpful?
0 / 5 - 0 ratings

Related issues

vadimsg picture vadimsg  路  3Comments

gary149 picture gary149  路  3Comments

danieloprado picture danieloprado  路  3Comments

vadimsg picture vadimsg  路  3Comments

surmon-china picture surmon-china  路  3Comments