Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(nuxt): stop loading indicator on vue errors #20738

Merged
merged 2 commits into from May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/nuxt/src/app/components/nuxt-error-boundary.ts
Expand Up @@ -11,9 +11,10 @@ export default defineComponent({
const error = ref<Error | null>(null)
const nuxtApp = useNuxtApp()

onErrorCaptured((err) => {
onErrorCaptured((err, target, info) => {
if (process.client && !nuxtApp.isHydrating) {
emit('error', err)
nuxtApp.hooks.callHook('vue:error', err, target, info)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main question about calling it here is that we explicitly say this will only be called when errors propagate up:

In addition, Nuxt provides a `vue:error` hook that will be called if any errors propagate up to the top level.

I think the concept here is that the error boundary establishes a different kind of error handling. But I'm open to discussion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it makes sense.

The problem is that when error occurs inside an error boundary neither page:finish nor vue:error are called, so not only loading indicator remains active, but view transitions are not finished or aborted either.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

What about something like this? It works but I'm not sure. Feels wrong calling page:finish in case of an error.

Maybe we do need something like page:error hook, as it was suggested in the original issue?

Or am I going in the wrong direction?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we could use page:finish there πŸ‘

The page: hooks are really about suspense rather than changing route. (They won't run if a page does not have an async setup or async dependencies, for example.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure they're called even with a sync setup, because every page is wrapped with a Suspense.

And in that case page:finish gets called twice with my solution 😒

image
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, to recap

// /nuxt/src/pages/runtime/page.ts

setup (props, { attrs }) {
  const nuxtApp = useNuxtApp()

  const done = nuxtApp.deferHydration()

  onErrorCaptured(() => {
    nuxtApp.callHook('page:finish').finally(done)
  })

It works, but for sync components page:finish gets called twice, because onResolve from Suspense also gets called

error.value = err
return false
}
Expand Down
1 change: 1 addition & 0 deletions packages/nuxt/src/app/components/nuxt-loading-indicator.ts
Expand Up @@ -32,6 +32,7 @@ export default defineComponent({
const nuxtApp = useNuxtApp()
nuxtApp.hook('page:start', indicator.start)
nuxtApp.hook('page:finish', indicator.finish)
nuxtApp.hook('vue:error', indicator.finish)
onBeforeUnmount(indicator.clear)

return () => h('div', {
Expand Down