feat: call global vue errorHandler in fetch and asyncData (#3652)

resolve #3335
This commit is contained in:
Clark Du 2018-08-08 11:11:08 +01:00 committed by GitHub
parent 823c298046
commit 6aaf839d54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 61 additions and 23 deletions

View File

@ -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') {

View File

@ -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

View File

@ -5,5 +5,8 @@ export default {
http2: {
push: true
}
}
},
plugins: [
'~/plugins/error.js'
]
}

View File

@ -0,0 +1,8 @@
<script>
export default {
fetch() {
throw Error('spa test error!')
}
}
</script>

5
test/fixtures/spa/plugins/error.js vendored Normal file
View File

@ -0,0 +1,5 @@
import Vue from 'vue'
Vue.config.errorHandler = function () {
document.body.appendChild(document.createTextNode('error handler triggered'))
}

View File

@ -43,6 +43,12 @@ describe('spa', () => {
expect(html).toMatch('<h1>Test: updated</h1>')
})
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: {