diff --git a/packages/nuxt/src/app/composables/asyncContext.ts b/packages/nuxt/src/app/composables/asyncContext.ts index 5fa88df529..56fb88232c 100644 --- a/packages/nuxt/src/app/composables/asyncContext.ts +++ b/packages/nuxt/src/app/composables/asyncContext.ts @@ -1,9 +1,11 @@ // @ts-expect-error withAsyncContext is internal API import { getCurrentInstance, withAsyncContext as withVueAsyncContext } from 'vue' -export function withAsyncContext (fn: () => PromiseLike) { - return withVueAsyncContext(() => { - const nuxtApp = getCurrentInstance()?.appContext.app.$nuxt - return nuxtApp ? nuxtApp.runWithContext(fn) : fn() - }) +export function withNuxtContext (fn: () => T) { + const nuxtApp = getCurrentInstance()?.appContext.app.$nuxt + return nuxtApp ? nuxtApp.runWithContext(fn) : fn() +} + +export function withAsyncContext (fn: () => PromiseLike) { + return withVueAsyncContext(() => withNuxtContext(fn)) } diff --git a/packages/nuxt/src/app/composables/component.ts b/packages/nuxt/src/app/composables/component.ts index 31e43f8c6e..8d28f5608e 100644 --- a/packages/nuxt/src/app/composables/component.ts +++ b/packages/nuxt/src/app/composables/component.ts @@ -1,8 +1,9 @@ -import { getCurrentInstance, reactive, toRefs } from 'vue' -import type { DefineComponent, defineComponent } from 'vue' +import { defineComponent as _defineComponent, getCurrentInstance, reactive, toRefs } from 'vue' +import type { ComponentOptions, DefineComponent } from 'vue' import { useHead } from '@unhead/vue' import type { NuxtApp } from '../nuxt' import { useNuxtApp } from '../nuxt' +import { withNuxtContext } from './asyncContext' import { useAsyncData } from './asyncData' import { useRoute } from './router' import { createError } from './error' @@ -28,7 +29,7 @@ async function runLegacyAsyncData (res: Record | Promise, arg2?: Partial) => { + if (typeof arg1 === 'function') { + return _defineComponent((...args) => withNuxtContext(() => arg1(...args)), arg2) + } + + if (arg1.setup) { + return _defineComponent({ + ...arg1, + setup: (...args: any[]) => withNuxtContext(() => arg1.setup(...args)) + }) as any + } + + return _defineComponent(arg1) +} diff --git a/packages/nuxt/src/imports/presets.ts b/packages/nuxt/src/imports/presets.ts index 7794446281..4f89620713 100644 --- a/packages/nuxt/src/imports/presets.ts +++ b/packages/nuxt/src/imports/presets.ts @@ -30,7 +30,7 @@ const granularAppPresets: InlinePreset[] = [ from: '#app/config' }, { - imports: ['defineNuxtComponent'], + imports: ['defineComponent', 'defineNuxtComponent'], from: '#app/composables/component' }, { @@ -156,7 +156,6 @@ const vuePreset = defineUnimportPreset({ 'onScopeDispose', // Component - 'defineComponent', 'defineAsyncComponent', 'resolveComponent', 'getCurrentInstance', diff --git a/packages/nuxt/test/auto-imports.test.ts b/packages/nuxt/test/auto-imports.test.ts index 9f8477aafa..024fefd9db 100644 --- a/packages/nuxt/test/auto-imports.test.ts +++ b/packages/nuxt/test/auto-imports.test.ts @@ -81,6 +81,8 @@ describe('imports:nuxt', () => { }) const excludedVueHelpers = [ + // Nuxt stub for this helper + 'defineComponent', // Already globally registered 'defineEmits', 'defineExpose', diff --git a/packages/schema/src/config/build.ts b/packages/schema/src/config/build.ts index b9ec0fafdf..ea2cf44e0f 100644 --- a/packages/schema/src/config/build.ts +++ b/packages/schema/src/config/build.ts @@ -189,6 +189,7 @@ export default defineUntypedSchema({ asyncTransforms: { asyncFunctions: ['defineNuxtPlugin', 'defineNuxtRouteMiddleware'], objectDefinitions: { + defineComponent: ['setup'], defineNuxtComponent: ['asyncData', 'setup'], defineNuxtPlugin: ['setup'], definePageMeta: ['middleware', 'validate'] diff --git a/test/basic.test.ts b/test/basic.test.ts index 1b2172c7e3..88b67b1289 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -1951,10 +1951,14 @@ describe.skipIf(isDev() || isWindows || !isRenderingJson)('payload rendering', ( }) }) -describe.skipIf(process.env.TEST_CONTEXT !== 'async')('Async context', () => { - it('should be available', async () => { +describe('Async context', () => { + it.skipIf(process.env.TEST_CONTEXT !== 'async')('should be available', async () => { expect(await $fetch('/async-context')).toContain('"hasApp": true') }) + it('should transform `setup` within defineComponent', async () => { + const html = await $fetch('/async-transform-component') + expect(html).toContain('using automatic `setup` async transform') + }) }) describe.skipIf(isWindows)('useAsyncData', () => { diff --git a/test/fixtures/basic/pages/async-transform-component.vue b/test/fixtures/basic/pages/async-transform-component.vue new file mode 100644 index 0000000000..03b7e2a3e0 --- /dev/null +++ b/test/fixtures/basic/pages/async-transform-component.vue @@ -0,0 +1,14 @@ + + +