@@ -107,7 +107,7 @@ export function markCurrentScopeAsDynamic(
107
107
// current render because something dynamic is being used.
108
108
// This won't throw so we still need to fall through to determine if/how we handle
109
109
// this specific dynamic request.
110
- abortRSCRenderWithTracking (
110
+ abortRenderWithTracking (
111
111
prerenderStore . controller ,
112
112
store . route ,
113
113
expression
@@ -120,9 +120,9 @@ export function markCurrentScopeAsDynamic(
120
120
errorWithTracking ( prerenderStore . dynamicTracking , store . route , expression )
121
121
} else {
122
122
postponeWithTracking (
123
- prerenderStore . dynamicTracking ,
124
123
store . route ,
125
- expression
124
+ expression ,
125
+ prerenderStore . dynamicTracking
126
126
)
127
127
}
128
128
} else {
@@ -171,7 +171,7 @@ export function trackDynamicDataAccessed(
171
171
// current render because something dynamic is being used.
172
172
// This won't throw so we still need to fall through to determine if/how we handle
173
173
// this specific dynamic request.
174
- abortRSCRenderWithTracking (
174
+ abortRenderWithTracking (
175
175
prerenderStore . controller ,
176
176
store . route ,
177
177
expression
@@ -184,9 +184,9 @@ export function trackDynamicDataAccessed(
184
184
errorWithTracking ( prerenderStore . dynamicTracking , store . route , expression )
185
185
} else {
186
186
postponeWithTracking (
187
- prerenderStore . dynamicTracking ,
188
187
store . route ,
189
- expression
188
+ expression ,
189
+ prerenderStore . dynamicTracking
190
190
)
191
191
}
192
192
} else {
@@ -205,6 +205,75 @@ export function trackDynamicDataAccessed(
205
205
}
206
206
}
207
207
208
+ export function interruptStaticGeneration (
209
+ expression : string ,
210
+ store : StaticGenerationStore
211
+ ) : never {
212
+ store . revalidate = 0
213
+
214
+ // We aren't prerendering but we are generating a static page. We need to bail out of static generation
215
+ const err = new DynamicServerError (
216
+ `Route ${ store . route } couldn't be rendered statically because it used \`${ expression } \`. See more info here: https://nextjs.org/docs/messages/dynamic-server-error`
217
+ )
218
+ store . dynamicUsageDescription = expression
219
+ store . dynamicUsageStack = err . stack
220
+
221
+ throw err
222
+ }
223
+
224
+ export function trackDynamicDataInDynamicRender ( store : StaticGenerationStore ) {
225
+ store . revalidate = 0
226
+ }
227
+
228
+ export function abortAndErrorOnSynchronousDynamicDataAccess (
229
+ controller : AbortController ,
230
+ route : string ,
231
+ expression : string ,
232
+ dynamicTracking : null | DynamicTrackingState
233
+ ) : never {
234
+ abortRenderWithTracking ( controller , route , expression )
235
+ errorWithTracking ( dynamicTracking , route , expression )
236
+ }
237
+
238
+ export function errorOnSynchronousDynamicDataAccess (
239
+ route : string ,
240
+ expression : string ,
241
+ controller : null | AbortController ,
242
+ dynamicTracking : null | DynamicTrackingState
243
+ ) : never {
244
+ const reason =
245
+ `Route ${ route } needs to bail out of prerendering at this point because it used ${ expression } . ` +
246
+ `React throws this special object to indicate where. It should not be caught by ` +
247
+ `your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error`
248
+
249
+ const error = createPrerenderInterruptedError ( reason )
250
+
251
+ if ( controller ) {
252
+ if ( hasPostpone ) {
253
+ try {
254
+ React . unstable_postpone ( NEXT_PRERENDER_INTERRUPTED )
255
+ } catch ( e ) {
256
+ controller . abort ( e )
257
+ }
258
+ } else {
259
+ controller . abort ( error )
260
+ }
261
+ }
262
+
263
+ if ( dynamicTracking ) {
264
+ dynamicTracking . dynamicAccesses . push ( {
265
+ // When we aren't debugging, we don't need to create another error for the
266
+ // stack trace.
267
+ stack : dynamicTracking . isDebugDynamicAccesses
268
+ ? new Error ( ) . stack
269
+ : undefined ,
270
+ expression,
271
+ } )
272
+ }
273
+
274
+ throw error
275
+ }
276
+
208
277
/**
209
278
* This component will call `React.postpone` that throws the postponed error.
210
279
*/
@@ -215,7 +284,7 @@ type PostponeProps = {
215
284
export function Postpone ( { reason, route } : PostponeProps ) : never {
216
285
const prerenderStore = prerenderAsyncStorage . getStore ( )
217
286
const dynamicTracking = prerenderStore ?. dynamicTracking || null
218
- postponeWithTracking ( dynamicTracking , route , reason )
287
+ postponeWithTracking ( route , reason , dynamicTracking )
219
288
}
220
289
221
290
function errorWithTracking (
@@ -241,10 +310,10 @@ function errorWithTracking(
241
310
throw createPrerenderInterruptedError ( reason )
242
311
}
243
312
244
- function postponeWithTracking (
245
- dynamicTracking : null | DynamicTrackingState ,
313
+ export function postponeWithTracking (
246
314
route : string ,
247
- expression : string
315
+ expression : string ,
316
+ dynamicTracking : null | DynamicTrackingState
248
317
) : never {
249
318
assertPostpone ( )
250
319
if ( dynamicTracking ) {
@@ -281,7 +350,7 @@ export function isRenderInterruptedError(error: unknown) {
281
350
)
282
351
}
283
352
284
- function abortRSCRenderWithTracking (
353
+ function abortRenderWithTracking (
285
354
controller : AbortController ,
286
355
route : string ,
287
356
expression : string
0 commit comments