From 6aaf839d5473c54adba60dacd09cfa2361f64e35 Mon Sep 17 00:00:00 2001 From: Clark Du Date: Wed, 8 Aug 2018 11:11:08 +0100 Subject: [PATCH] feat: call global vue errorHandler in fetch and asyncData (#3652) resolve #3335 --- lib/app/client.js | 52 +++++++++++++---------- lib/app/utils.js | 8 ++++ test/fixtures/spa/nuxt.config.js | 5 ++- test/fixtures/spa/pages/error-handler.vue | 8 ++++ test/fixtures/spa/plugins/error.js | 5 +++ test/unit/spa.test.js | 6 +++ 6 files changed, 61 insertions(+), 23 deletions(-) create mode 100644 test/fixtures/spa/pages/error-handler.vue create mode 100644 test/fixtures/spa/plugins/error.js diff --git a/lib/app/client.js b/lib/app/client.js index 89ad6a1386..88242ff9ec 100644 --- a/lib/app/client.js +++ b/lib/app/client.js @@ -13,7 +13,9 @@ import { promisify, getLocation, compile, - getQueryDiff + getQueryDiff, + globalHandleError, + empty } from './utils' const noopData = () => { return {} } @@ -329,7 +331,7 @@ async function render (to, from, next) { let promises = [] const hasAsyncData = ( - Component.options.asyncData && + Component.options.asyncData && typeof Component.options.asyncData === 'function' ) const hasFetch = !!Component.options.fetch @@ -340,34 +342,38 @@ async function render (to, from, next) { // Call asyncData(context) if (hasAsyncData) { const promise = promisify(Component.options.asyncData, app.context) - .then((asyncDataResult) => { - applyAsyncData(Component, asyncDataResult) - <% if (loading) { %> - if(this.$loading.increase) { - this.$loading.increase(loadingIncrease) - } - <% } %> - }) + .then((asyncDataResult) => { + applyAsyncData(Component, asyncDataResult) + <% if (loading) { %> + if(this.$loading.increase) { + this.$loading.increase(loadingIncrease) + } + <% } %> + }) + // error will be handled in try catch + .catch(empty) promises.push(promise) } // Check disabled page loading this.$loading.manual = Component.options.loading === false - + // Call fetch(context) if (hasFetch) { - let p = Component.options.fetch(app.context) - if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) { - p = Promise.resolve(p) - } - p.then((fetchResult) => { - <% if (loading) { %> - if (this.$loading.increase) { - this.$loading.increase(loadingIncrease) + let p = Component.options.fetch(app.context) + if (!p || (!(p instanceof Promise) && (typeof p.then !== 'function'))) { + p = Promise.resolve(p) } - <% } %> - }) - promises.push(p) + p.then((fetchResult) => { + <% if (loading) { %> + if (this.$loading.increase) { + this.$loading.increase(loadingIncrease) + } + <% } %> + }) + // error will be handled in try catch + .catch(empty) + promises.push(p) } return Promise.all(promises) @@ -391,6 +397,8 @@ async function render (to, from, next) { const errorResponseStatus = (error.response && error.response.status) error.statusCode = error.statusCode || error.status || errorResponseStatus || 500 + globalHandleError(error) + // Load error layout let layout = NuxtError.layout if (typeof layout === 'function') { diff --git a/lib/app/utils.js b/lib/app/utils.js index 0005eb8ab0..49ca3577c9 100644 --- a/lib/app/utils.js +++ b/lib/app/utils.js @@ -11,6 +11,14 @@ if (process.browser) { } } +export function empty() {} + +export function globalHandleError(error) { + if (Vue.config.errorHandler) { + Vue.config.errorHandler(error) + } +} + export function applyAsyncData(Component, asyncData) { const ComponentData = Component.options.data || noopData // Prevent calling this method for each request on SSR context diff --git a/test/fixtures/spa/nuxt.config.js b/test/fixtures/spa/nuxt.config.js index 4a650f5849..d8337c48e8 100644 --- a/test/fixtures/spa/nuxt.config.js +++ b/test/fixtures/spa/nuxt.config.js @@ -5,5 +5,8 @@ export default { http2: { push: true } - } + }, + plugins: [ + '~/plugins/error.js' + ] } diff --git a/test/fixtures/spa/pages/error-handler.vue b/test/fixtures/spa/pages/error-handler.vue new file mode 100644 index 0000000000..e9ef8ad2b0 --- /dev/null +++ b/test/fixtures/spa/pages/error-handler.vue @@ -0,0 +1,8 @@ + diff --git a/test/fixtures/spa/plugins/error.js b/test/fixtures/spa/plugins/error.js new file mode 100644 index 0000000000..28875b1137 --- /dev/null +++ b/test/fixtures/spa/plugins/error.js @@ -0,0 +1,5 @@ +import Vue from 'vue' + +Vue.config.errorHandler = function () { + document.body.appendChild(document.createTextNode('error handler triggered')) +} diff --git a/test/unit/spa.test.js b/test/unit/spa.test.js index 324e053490..e07470030f 100644 --- a/test/unit/spa.test.js +++ b/test/unit/spa.test.js @@ -43,6 +43,12 @@ describe('spa', () => { expect(html).toMatch('

Test: updated

') }) + test('/error-handler', async () => { + await renderRoute('/error-handler') + const { html } = await renderRoute('/error-handler') + expect(html).toMatch('error handler triggered') + }) + test('/_nuxt/ (access publicPath in spa mode)', async () => { await expect(renderRoute('/_nuxt/')).rejects.toMatchObject({ response: {