@@ -47,6 +47,7 @@ export type AppLoaderOptions = {
47
47
isDev ?: boolean
48
48
basePath : string
49
49
nextConfigOutput ?: NextConfig [ 'output' ]
50
+ nextConfigExperimentalUseEarlyImport ?: boolean
50
51
middlewareConfig : string
51
52
}
52
53
type AppLoader = webpack . LoaderDefinitionFunction < AppLoaderOptions >
@@ -170,6 +171,7 @@ async function createTreeCodeFromPath(
170
171
metadataResolver,
171
172
pageExtensions,
172
173
basePath,
174
+ collectedAsyncImports,
173
175
} : {
174
176
page : string
175
177
resolveDir : DirResolver
@@ -181,6 +183,7 @@ async function createTreeCodeFromPath(
181
183
loaderContext : webpack . LoaderContext < AppLoaderOptions >
182
184
pageExtensions : PageExtensions
183
185
basePath : string
186
+ collectedAsyncImports : string [ ]
184
187
}
185
188
) : Promise < {
186
189
treeCode : string
@@ -233,7 +236,8 @@ async function createTreeCodeFromPath(
233
236
}
234
237
235
238
async function createSubtreePropsFromSegmentPath (
236
- segments : string [ ]
239
+ segments : string [ ] ,
240
+ nestedCollectedAsyncImports : string [ ]
237
241
) : Promise < {
238
242
treeCode : string
239
243
} > {
@@ -280,7 +284,10 @@ async function createTreeCodeFromPath(
280
284
} /page`
281
285
282
286
const resolvedPagePath = await resolver ( matchedPagePath )
283
- if ( resolvedPagePath ) pages . push ( resolvedPagePath )
287
+ if ( resolvedPagePath ) {
288
+ pages . push ( resolvedPagePath )
289
+ nestedCollectedAsyncImports . push ( resolvedPagePath )
290
+ }
284
291
285
292
// Use '' for segment as it's the page. There can't be a segment called '' so this is the safest way to add it.
286
293
props [
@@ -291,8 +298,7 @@ async function createTreeCodeFromPath(
291
298
) } ), ${ JSON . stringify ( resolvedPagePath ) } ],
292
299
${ createMetadataExportsCode ( metadata ) }
293
300
}]`
294
-
295
- continue
301
+ if ( resolvedPagePath ) continue
296
302
}
297
303
298
304
// if the parallelSegment was not matched to the __PAGE__ slot, then it's a parallel route at this level.
@@ -321,7 +327,10 @@ async function createTreeCodeFromPath(
321
327
}
322
328
323
329
const { treeCode : pageSubtreeCode } =
324
- await createSubtreePropsFromSegmentPath ( subSegmentPath )
330
+ await createSubtreePropsFromSegmentPath (
331
+ subSegmentPath ,
332
+ nestedCollectedAsyncImports
333
+ )
325
334
326
335
const parallelSegmentPath = subSegmentPath . join ( '/' )
327
336
@@ -399,6 +408,7 @@ async function createTreeCodeFromPath(
399
408
const notFoundPath =
400
409
definedFilePaths . find ( ( [ type ] ) => type === 'not-found' ) ?. [ 1 ] ??
401
410
defaultNotFoundPath
411
+ nestedCollectedAsyncImports . push ( notFoundPath )
402
412
subtreeCode = `{
403
413
children: ['${ PAGE_SEGMENT_KEY } ', {}, {
404
414
page: [
@@ -414,6 +424,7 @@ async function createTreeCodeFromPath(
414
424
const componentsCode = `{
415
425
${ definedFilePaths
416
426
. map ( ( [ file , filePath ] ) => {
427
+ if ( filePath ) nestedCollectedAsyncImports . push ( filePath )
417
428
return `'${ file } ': [() => import(/* webpackMode: "eager" */ ${ JSON . stringify (
418
429
filePath
419
430
) } ), ${ JSON . stringify ( filePath ) } ],`
@@ -456,6 +467,7 @@ async function createTreeCodeFromPath(
456
467
defaultPath = normalizedDefault ?? PARALLEL_ROUTE_DEFAULT_PATH
457
468
}
458
469
470
+ nestedCollectedAsyncImports . push ( defaultPath )
459
471
props [ normalizeParallelKey ( adjacentParallelSegment ) ] = `[
460
472
'${ DEFAULT_SEGMENT_KEY } ',
461
473
{},
@@ -476,7 +488,10 @@ async function createTreeCodeFromPath(
476
488
}
477
489
}
478
490
479
- const { treeCode } = await createSubtreePropsFromSegmentPath ( [ ] )
491
+ const { treeCode } = await createSubtreePropsFromSegmentPath (
492
+ [ ] ,
493
+ collectedAsyncImports
494
+ )
480
495
481
496
return {
482
497
treeCode : `${ treeCode } .children;` ,
@@ -510,9 +525,11 @@ const nextAppLoader: AppLoader = async function nextAppLoader() {
510
525
preferredRegion,
511
526
basePath,
512
527
middlewareConfig : middlewareConfigBase64 ,
528
+ nextConfigExperimentalUseEarlyImport,
513
529
} = loaderOptions
514
530
515
531
const buildInfo = getModuleBuildInfo ( ( this as any ) . _module )
532
+ const collectedAsyncImports : string [ ] = [ ]
516
533
const page = name . replace ( / ^ a p p / , '' )
517
534
const middlewareConfig : MiddlewareConfig = JSON . parse (
518
535
Buffer . from ( middlewareConfigBase64 , 'base64' ) . toString ( )
@@ -690,6 +707,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() {
690
707
loaderContext : this ,
691
708
pageExtensions,
692
709
basePath,
710
+ collectedAsyncImports,
693
711
} )
694
712
695
713
if ( ! treeCodeResult . rootLayout ) {
@@ -738,6 +756,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() {
738
756
loaderContext : this ,
739
757
pageExtensions,
740
758
basePath,
759
+ collectedAsyncImports,
741
760
} )
742
761
}
743
762
}
@@ -746,7 +765,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() {
746
765
747
766
// Prefer to modify next/src/server/app-render/entry-base.ts since this is shared with Turbopack.
748
767
// Any changes to this code should be reflected in Turbopack's app_source.rs and/or app-renderer.tsx as well.
749
- return await loadEntrypoint (
768
+ const code = await loadEntrypoint (
750
769
'app-page' ,
751
770
{
752
771
VAR_DEFINITION_PAGE : page ,
@@ -761,6 +780,19 @@ const nextAppLoader: AppLoader = async function nextAppLoader() {
761
780
__next_app_load_chunk__ : '() => Promise.resolve()' ,
762
781
}
763
782
)
783
+
784
+ // Evaluated the imported modules early in the generated code
785
+ const earlyEvaluateCode =
786
+ nextConfigExperimentalUseEarlyImport &&
787
+ process . env . NODE_ENV === 'production'
788
+ ? collectedAsyncImports
789
+ . map ( ( modulePath ) => {
790
+ return `import ${ JSON . stringify ( modulePath ) } ;`
791
+ } )
792
+ . join ( '\n' )
793
+ : ''
794
+
795
+ return earlyEvaluateCode + code
764
796
}
765
797
766
798
export default nextAppLoader
0 commit comments