diff --git a/packages/next/server/app-render.tsx b/packages/next/server/app-render.tsx
index 6e2b8fd2cc10c..cda73f9dc0161 100644
--- a/packages/next/server/app-render.tsx
+++ b/packages/next/server/app-render.tsx
@@ -39,6 +39,31 @@ import { HeadManagerContext } from '../shared/lib/head-manager-context'
import { Writable } from 'stream'
import stringHash from 'next/dist/compiled/string-hash'
+function preloadComponent(Component: any, props: any) {
+ const prev = console.error
+ // Hide invalid hook call warning when calling component
+ console.error = (msg) => {
+ if (msg.startsWith('Invalid hook call..')) {
+ // ignore
+ } else {
+ // @ts-expect-error argument is defined
+ prev.apply(console, arguments)
+ }
+ }
+ try {
+ let result = Component(props)
+ return function () {
+ // We know what this component will render already.
+ return result
+ }
+ } catch (x) {
+ // something suspended or errored, try again later
+ } finally {
+ console.error = prev
+ }
+ return Component
+}
+
const INTERNAL_HEADERS_INSTANCE = Symbol('internal for headers readonly')
function readonlyHeadersError() {
@@ -1027,7 +1052,7 @@ export async function renderToHTMLOrFlight(
/**
* The React Component to render.
*/
- const Component = layoutOrPageMod
+ let Component = layoutOrPageMod
? interopDefault(layoutOrPageMod)
: undefined
@@ -1181,10 +1206,23 @@ export async function renderToHTMLOrFlight(
}
}
+ const props = {
+ ...parallelRouteComponents,
+ // TODO-APP: params and query have to be blocked parallel route names. Might have to add a reserved name list.
+ // Params are always the current params that apply to the layout
+ // If you have a `/dashboard/[team]/layout.js` it will provide `team` as a param but not anything further down.
+ params: currentParams,
+ // Query is only provided to page
+ ...(isPage ? { searchParams: query } : {}),
+ }
+
+ // Eagerly execute layout/page component to trigger fetches early.
+ Component = await Promise.resolve().then(() => {
+ return preloadComponent(Component, props)
+ })
+
return {
Component: () => {
- let props = {}
-
// Add extra cache busting (DEV only) for https://github.com/vercel/next.js/issues/5860
// See also https://bugs.webkit.org/show_bug.cgi?id=187726
const cacheBustingUrlSuffix = dev ? `?ts=${Date.now()}` : ''
@@ -1218,16 +1256,7 @@ export async function renderToHTMLOrFlight(
/>
))
: null}
-
{data.message}
diff --git a/test/e2e/app-dir/rendering.test.ts b/test/e2e/app-dir/rendering.test.ts index 28350408f17e6..3b6b0ac0cea83 100644 --- a/test/e2e/app-dir/rendering.test.ts +++ b/test/e2e/app-dir/rendering.test.ts @@ -37,14 +37,14 @@ describe('app dir rendering', () => { expect($('#page-message').text()).toBe('hello from page') }) - it('should run data in parallel', async () => { - // const startTime = Date.now() + it('should run data fetch in parallel', async () => { + const startTime = Date.now() const html = await renderViaHTTP(next.url, '/ssr-only/slow') - // const endTime = Date.now() - // const duration = endTime - startTime + const endTime = Date.now() + const duration = endTime - startTime // Each part takes 5 seconds so it should be below 10 seconds // Using 7 seconds to ensure external factors causing slight slowness don't fail the tests - // expect(duration < 7000).toBe(true) + expect(duration < 7000).toBe(true) const $ = cheerio.load(html) expect($('#slow-layout-message').text()).toBe('hello from slow layout') expect($('#slow-page-message').text()).toBe('hello from slow page')