diff --git a/packages/nuxt/src/pages/runtime/page.ts b/packages/nuxt/src/pages/runtime/page.ts
index 7e971a3652..d906c008f8 100644
--- a/packages/nuxt/src/pages/runtime/page.ts
+++ b/packages/nuxt/src/pages/runtime/page.ts
@@ -54,6 +54,7 @@ export default defineComponent({
return _wrapIf(Transition, hasTransition && transitionProps,
wrapInKeepAlive(props.keepalive ?? routeProps.route.meta.keepalive ?? (defaultKeepaliveConfig as KeepAliveProps), h(Suspense, {
+ suspensible: true,
onPending: () => nuxtApp.callHook('page:start', routeProps.Component),
onResolve: () => { nextTick(() => nuxtApp.callHook('page:finish', routeProps.Component).finally(done)) }
}, { default: () => h(RouteProvider, { key, routeProps, pageKey: key, hasTransition } as {}) })
diff --git a/test/basic.test.ts b/test/basic.test.ts
index af4a2f0fc6..c7d2a94d00 100644
--- a/test/basic.test.ts
+++ b/test/basic.test.ts
@@ -891,6 +891,36 @@ describe('deferred app suspense resolve', () => {
})
})
+describe('nested suspense', () => {
+ const navigations = [
+ ['/suspense/sync-1/async-1/', '/suspense/sync-2/async-1/'],
+ ['/suspense/sync-1/sync-1/', '/suspense/sync-2/async-1/'],
+ ['/suspense/async-1/async-1/', '/suspense/async-2/async-1/'],
+ ['/suspense/async-1/sync-1/', '/suspense/async-2/async-1/']
+ ]
+
+ it.each(navigations)('should navigate from %s to %s with no white flash', async (start, nav) => {
+ const page = await createPage(start, {})
+ await page.waitForLoadState('networkidle')
+
+ const slug = nav.replace(/[/-]+/g, '-')
+ await page.click(`[href^="${nav}"]`)
+
+ const text = await page.waitForFunction(slug => document.querySelector(`#${slug}`)?.innerHTML, slug)
+ // @ts-expect-error TODO: fix upstream in playwright - types for evaluate are broken
+ .then(r => r.evaluate(r => r))
+
+ // expect(text).toMatchInlineSnapshot()
+
+ // const parent = await page.waitForSelector(`#${slug}`, { state: 'attached' })
+
+ // const text = await parent.innerText()
+ expect(text).toContain('Async child: 2 - 1')
+
+ await page.close()
+ })
+})
+
// Bug #6592
describe('page key', () => {
it('should not cause run of setup if navigation not change page key and layout', async () => {
diff --git a/test/fixtures/basic/pages/suspense.vue b/test/fixtures/basic/pages/suspense.vue
new file mode 100644
index 0000000000..0e082baa04
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense.vue
@@ -0,0 +1,22 @@
+
+
+
+
+ This exists to test synchronous transitions between nested Suspense components.
+
+
+ {{ link }}
+
+
+
+
+
+
+
diff --git a/test/fixtures/basic/pages/suspense/async-[parent].vue b/test/fixtures/basic/pages/suspense/async-[parent].vue
new file mode 100644
index 0000000000..9f778ef62c
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense/async-[parent].vue
@@ -0,0 +1,14 @@
+
+
+
+
+ Async parent: {{ route.params.parent }}
+
+
+
+
diff --git a/test/fixtures/basic/pages/suspense/async-[parent]/async-[child].vue b/test/fixtures/basic/pages/suspense/async-[parent]/async-[child].vue
new file mode 100644
index 0000000000..a7689a79de
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense/async-[parent]/async-[child].vue
@@ -0,0 +1,15 @@
+
+
+
+
+ Async child: {{ route.params.parent }} - {{ route.params.child }}
+
+ {{ data }}
+
+
diff --git a/test/fixtures/basic/pages/suspense/async-[parent]/sync-[child].vue b/test/fixtures/basic/pages/suspense/async-[parent]/sync-[child].vue
new file mode 100644
index 0000000000..a84b1b5625
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense/async-[parent]/sync-[child].vue
@@ -0,0 +1,10 @@
+
+
+
+
+ Sync child: {{ route.params.parent }} - {{ route.params.child }}
+
+
diff --git a/test/fixtures/basic/pages/suspense/sync-[parent].vue b/test/fixtures/basic/pages/suspense/sync-[parent].vue
new file mode 100644
index 0000000000..bb18dd3bf2
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense/sync-[parent].vue
@@ -0,0 +1,12 @@
+
+
+
+
+ Sync parent: {{ route.params.parent }}
+
+
+
+
diff --git a/test/fixtures/basic/pages/suspense/sync-[parent]/async-[child].vue b/test/fixtures/basic/pages/suspense/sync-[parent]/async-[child].vue
new file mode 100644
index 0000000000..82d7ee7057
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense/sync-[parent]/async-[child].vue
@@ -0,0 +1,15 @@
+
+
+
+
+ Async child: {{ route.params.parent }} - {{ route.params.child }}
+
+ {{ data }}
+
+
diff --git a/test/fixtures/basic/pages/suspense/sync-[parent]/sync-[child].vue b/test/fixtures/basic/pages/suspense/sync-[parent]/sync-[child].vue
new file mode 100644
index 0000000000..5918ad9d1d
--- /dev/null
+++ b/test/fixtures/basic/pages/suspense/sync-[parent]/sync-[child].vue
@@ -0,0 +1,10 @@
+
+
+
+
+ Sync child: {{ route.params.parent }} - {{ route.params.child }}
+
+