mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-25 15:15:19 +00:00
fix(nuxt): prioritise vue app context when available (#20910)
This commit is contained in:
parent
f39eb6e981
commit
d2e14b678b
@ -1,5 +1,5 @@
|
||||
/* eslint-disable no-use-before-define */
|
||||
import { getCurrentInstance, reactive } from 'vue'
|
||||
import { getCurrentInstance, hasInjectionContext, reactive } from 'vue'
|
||||
import type { App, Ref, VNode, onErrorCaptured } from 'vue'
|
||||
import type { RouteLocationNormalizedLoaded } from '#vue-router'
|
||||
import type { HookCallback, Hookable } from 'hookable'
|
||||
@ -435,19 +435,20 @@ export function callWithNuxt<T extends (...args: any[]) => any> (nuxt: NuxtApp |
|
||||
/**
|
||||
* Returns the current Nuxt instance.
|
||||
*/
|
||||
export function useNuxtApp () {
|
||||
const nuxtAppInstance = nuxtAppCtx.tryUse()
|
||||
export function useNuxtApp (): NuxtApp {
|
||||
let nuxtAppInstance
|
||||
if (hasInjectionContext()) {
|
||||
nuxtAppInstance = getCurrentInstance()?.appContext.app.$nuxt
|
||||
}
|
||||
|
||||
nuxtAppInstance = nuxtAppInstance || nuxtAppCtx.tryUse()
|
||||
|
||||
if (!nuxtAppInstance) {
|
||||
const vm = getCurrentInstance()
|
||||
if (!vm) {
|
||||
if (process.dev) {
|
||||
throw new Error('[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at `https://nuxt.com/docs/guide/concepts/auto-imports#using-vue-and-nuxt-composables`.')
|
||||
} else {
|
||||
throw new Error('[nuxt] instance unavailable')
|
||||
}
|
||||
if (process.dev) {
|
||||
throw new Error('[nuxt] A composable that requires access to the Nuxt instance was called outside of a plugin, Nuxt hook, Nuxt middleware, or Vue setup function. This is probably not a Nuxt bug. Find out more at `https://nuxt.com/docs/guide/concepts/auto-imports#using-vue-and-nuxt-composables`.')
|
||||
} else {
|
||||
throw new Error('[nuxt] instance unavailable')
|
||||
}
|
||||
return vm.appContext.app.$nuxt as NuxtApp
|
||||
}
|
||||
|
||||
return nuxtAppInstance
|
||||
|
@ -596,6 +596,22 @@ describe('navigate', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('preserves current instance', () => {
|
||||
// TODO: reenable when https://github.com/vuejs/core/issues/7733 is resolved
|
||||
it('should not return getCurrentInstance when there\'s an error in data', async () => {
|
||||
await fetch('/instance/error')
|
||||
const html = await $fetch('/instance/next-request')
|
||||
expect(html).toContain('This should be false: false')
|
||||
})
|
||||
// TODO: re-enable when https://github.com/nuxt/nuxt/issues/15164 is resolved
|
||||
it.skipIf(isWindows)('should not lose current nuxt app after await in vue component', async () => {
|
||||
const requests = await Promise.all(Array.from({ length: 100 }).map(() => $fetch('/instance/next-request')))
|
||||
for (const html of requests) {
|
||||
expect(html).toContain('This should be true: true')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
describe('errors', () => {
|
||||
it('should render a JSON error page', async () => {
|
||||
const res = await fetch('/error', {
|
||||
|
13
test/fixtures/basic/pages/instance/error.vue
vendored
Normal file
13
test/fixtures/basic/pages/instance/error.vue
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
<script lang="ts">
|
||||
export default defineComponent({
|
||||
data () {
|
||||
throw new Error('💀')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
This should not display.
|
||||
</div>
|
||||
</template>
|
14
test/fixtures/basic/pages/instance/next-request.vue
vendored
Normal file
14
test/fixtures/basic/pages/instance/next-request.vue
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
<script setup>
|
||||
const nuxtApp = useNuxtApp()
|
||||
await new Promise(resolve => setTimeout(resolve, 150))
|
||||
const isSameApp = nuxtApp === useNuxtApp()
|
||||
if (!isSameApp) {
|
||||
throw new Error('💀')
|
||||
}
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
This should be false: {{ $wasVueAppInstanceWronglyPreserved }}
|
||||
This should be true: {{ isSameApp }}
|
||||
</div>
|
||||
</template>
|
9
test/fixtures/basic/plugins/context-error.ts
vendored
Normal file
9
test/fixtures/basic/plugins/context-error.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
export default defineNuxtPlugin(() => {
|
||||
// this should be undefined
|
||||
const vueApp = getCurrentInstance()
|
||||
return {
|
||||
provide: {
|
||||
wasVueAppInstanceWronglyPreserved: !!vueApp
|
||||
}
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user