From 128c9743c40bf776af428e5ed36ea1a09a0ef7b8 Mon Sep 17 00:00:00 2001 From: Matthieu Sieben Date: Tue, 4 Aug 2020 11:29:23 +0200 Subject: [PATCH] fix(vue-app): handle server-side routing errors (#7801) --- packages/vue-app/template/index.js | 8 +++++-- test/dev/basic.ssr.test.js | 21 +++++++++++++++++++ test/fixtures/basic/nuxt.config.js | 1 + .../basic/pages/router-guard-error.vue | 3 +++ test/fixtures/basic/plugins/router-guard.js | 17 +++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/basic/pages/router-guard-error.vue create mode 100644 test/fixtures/basic/plugins/router-guard.js diff --git a/packages/vue-app/template/index.js b/packages/vue-app/template/index.js index 765c543a35..409a582431 100644 --- a/packages/vue-app/template/index.js +++ b/packages/vue-app/template/index.js @@ -246,9 +246,13 @@ async function createApp(ssrContext, config = {}) { // If server-side, wait for async component to be resolved first if (process.server && ssrContext && ssrContext.url) { await new Promise((resolve, reject) => { - router.push(ssrContext.url, resolve, () => { + router.push(ssrContext.url, resolve, (err) => { + // https://github.com/vuejs/vue-router/blob/v3.3.4/src/history/errors.js + if (!err._isRouter) return reject(err) + if (err.type !== 1 /* NavigationFailureType.redirected */) return resolve() + // navigated to a different route in router guard - const unregister = router.afterEach(async (to, from, next) => { + const unregister = router.afterEach(async (to, from) => { ssrContext.url = to.fullPath app.context.route = await getRouteData(to) app.context.params = to.params || {} diff --git a/test/dev/basic.ssr.test.js b/test/dev/basic.ssr.test.js index b2a47737a2..567c1536d1 100644 --- a/test/dev/basic.ssr.test.js +++ b/test/dev/basic.ssr.test.js @@ -350,6 +350,27 @@ describe('basic ssr', () => { expect(html.includes('Router Guard')).toBe(false) }) + test('/router-guard-error', async () => { + const { html, error } = await nuxt.server.renderRoute('/router-guard-error') + + expect(error).toBe(null) + expect(html.includes('Page content')).toBe(false) + }) + + test('/router-guard-error?error=zepe', async () => { + const { html, error } = await nuxt.server.renderRoute('/router-guard-error?error=zepe') + + expect(html.includes('Page content')).toBe(false) + expect(html).toContain('zepe') + expect(error.message).toContain('zepe') + expect(error.statusCode).toBe(500) + }) + + test('/router-guard-error?throw=ezae', async () => { + await expect(nuxt.server.renderRoute('/router-guard-error?throw=ezae')) + .rejects.toMatchObject({ message: 'ezae' }) + }) + test('/jsx', async () => { const { html } = await nuxt.server.renderRoute('/jsx') expect(html).toContain('

JSX Page

') diff --git a/test/fixtures/basic/nuxt.config.js b/test/fixtures/basic/nuxt.config.js index 02e7379167..948d57c534 100644 --- a/test/fixtures/basic/nuxt.config.js +++ b/test/fixtures/basic/nuxt.config.js @@ -70,6 +70,7 @@ export default { plugins: [ '~/plugins/vuex-module', '~/plugins/dir-plugin', + '~/plugins/router-guard', '~/plugins/inject' ], serverMiddleware: [ diff --git a/test/fixtures/basic/pages/router-guard-error.vue b/test/fixtures/basic/pages/router-guard-error.vue new file mode 100644 index 0000000000..7eadbc093f --- /dev/null +++ b/test/fixtures/basic/pages/router-guard-error.vue @@ -0,0 +1,3 @@ + diff --git a/test/fixtures/basic/plugins/router-guard.js b/test/fixtures/basic/plugins/router-guard.js new file mode 100644 index 0000000000..e0faf0eba8 --- /dev/null +++ b/test/fixtures/basic/plugins/router-guard.js @@ -0,0 +1,17 @@ +export default function ({ app, error }) { + app.router.beforeEach((to, from, next) => { + if (to.path !== '/router-guard-error') { + return next() + } + + if (to.query.error) { + error(new Error(to.query.error)) + } + + if (to.query.throw) { + next(new Error(to.query.throw)) + } else { + next(false) + } + }) +}