Skip to content

Commit cce371f

Browse files
authored
fix(nextjs): Handle dynamicIO errors when request apis are accessed on prerender (#4836)
1 parent 7182b93 commit cce371f

File tree

3 files changed

+32
-16
lines changed

3 files changed

+32
-16
lines changed

.changeset/brown-kids-camp.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@clerk/nextjs': patch
3+
---
4+
5+
Handle `dynamicIO` errors when request apis are accessed on prerender. This fixes issues with `ppr: true, dynamicIO: true` when using `<ClerkProvider dynamic/>`.

packages/nextjs/src/app-router/server/ClerkProvider.tsx

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { AuthObject } from '@clerk/backend';
21
import type { InitialState, Without } from '@clerk/types';
32
import { headers } from 'next/headers';
43
import React from 'react';
@@ -27,21 +26,33 @@ export async function ClerkProvider(
2726
props: Without<NextClerkProviderProps, '__unstable_invokeMiddlewareOnAuthStateChange'>,
2827
) {
2928
const { children, dynamic, ...rest } = props;
30-
let statePromise: Promise<null | AuthObject> = Promise.resolve(null);
31-
let nonce = Promise.resolve('');
3229

33-
if (dynamic) {
30+
async function generateStatePromise() {
31+
if (!dynamic) {
32+
return Promise.resolve(null);
33+
}
34+
if (isNext13) {
35+
/**
36+
* For some reason, Next 13 requires that functions which call `headers()` are awaited where they are invoked.
37+
* Without the await here, Next will throw a DynamicServerError during build.
38+
*/
39+
return Promise.resolve(await getDynamicClerkState());
40+
}
41+
return getDynamicClerkState();
42+
}
43+
44+
async function generateNonce() {
45+
if (!dynamic) {
46+
return Promise.resolve('');
47+
}
3448
if (isNext13) {
3549
/**
3650
* For some reason, Next 13 requires that functions which call `headers()` are awaited where they are invoked.
3751
* Without the await here, Next will throw a DynamicServerError during build.
3852
*/
39-
statePromise = Promise.resolve(await getDynamicClerkState());
40-
nonce = Promise.resolve(await getNonceFromCSPHeader());
41-
} else {
42-
statePromise = getDynamicClerkState();
43-
nonce = getNonceFromCSPHeader();
53+
return Promise.resolve(await getNonceFromCSPHeader());
4454
}
55+
return getNonceFromCSPHeader();
4556
}
4657

4758
const propsWithEnvs = mergeNextClerkPropsWithEnv({
@@ -51,8 +62,8 @@ export async function ClerkProvider(
5162
let output = (
5263
<ClientClerkProvider
5364
{...mergeNextClerkPropsWithEnv(rest)}
54-
nonce={await nonce}
55-
initialState={await statePromise}
65+
nonce={await generateNonce()}
66+
initialState={await generateStatePromise()}
5667
>
5768
{children}
5869
</ClientClerkProvider>
@@ -75,8 +86,8 @@ export async function ClerkProvider(
7586
__internal_claimKeylessApplicationUrl: newOrReadKeys.claimUrl,
7687
__internal_copyInstanceKeysUrl: newOrReadKeys.apiKeysUrl,
7788
})}
78-
nonce={await nonce}
79-
initialState={await statePromise}
89+
nonce={await generateNonce()}
90+
initialState={await generateStatePromise()}
8091
>
8192
{children}
8293
</ClientClerkProvider>
@@ -88,7 +99,7 @@ export async function ClerkProvider(
8899
if (dynamic) {
89100
return (
90101
// TODO: fix types so AuthObject is compatible with InitialState
91-
<PromisifiedAuthProvider authPromise={statePromise as unknown as Promise<InitialState>}>
102+
<PromisifiedAuthProvider authPromise={generateStatePromise() as unknown as Promise<InitialState>}>
92103
{output}
93104
</PromisifiedAuthProvider>
94105
);

packages/nextjs/src/app-router/server/utils.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const isPrerenderingBailout = (e: unknown) => {
1919
return routeRegex.test(message) || dynamicServerUsage || bailOutPrerendering;
2020
};
2121

22-
export async function buildRequestLike() {
22+
export async function buildRequestLike(): Promise<NextRequest> {
2323
try {
2424
// Dynamically import next/headers, otherwise Next12 apps will break
2525
// @ts-expect-error: Cannot find module 'next/headers' or its corresponding type declarations.ts(2307)
@@ -67,7 +67,7 @@ export function getScriptNonceFromHeader(cspHeaderValue: string): string | undef
6767
// Grab the nonce by trimming the 'nonce-' prefix.
6868
?.slice(7, -1);
6969

70-
// If we could't find the nonce, then we're done.
70+
// If we couldn't find the nonce, then we're done.
7171
if (!nonce) {
7272
return;
7373
}

0 commit comments

Comments
 (0)