next 16.0.1-canary.1 → 16.0.1-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/bin/next +1 -1
  2. package/dist/build/index.js +3 -3
  3. package/dist/build/static-paths/app.d.ts +13 -12
  4. package/dist/build/static-paths/app.js +121 -57
  5. package/dist/build/static-paths/app.js.map +1 -1
  6. package/dist/build/swc/index.js +1 -1
  7. package/dist/build/webpack-config.js +2 -2
  8. package/dist/client/app-bootstrap.js +1 -1
  9. package/dist/client/index.js +1 -1
  10. package/dist/compiled/next-server/pages-api-turbo.runtime.prod.js +1 -1
  11. package/dist/compiled/next-server/pages-api-turbo.runtime.prod.js.map +1 -1
  12. package/dist/compiled/next-server/pages-turbo.runtime.prod.js +1 -1
  13. package/dist/compiled/next-server/pages-turbo.runtime.prod.js.map +1 -1
  14. package/dist/esm/build/index.js +3 -3
  15. package/dist/esm/build/static-paths/app.js +131 -64
  16. package/dist/esm/build/static-paths/app.js.map +1 -1
  17. package/dist/esm/build/swc/index.js +1 -1
  18. package/dist/esm/build/webpack-config.js +2 -2
  19. package/dist/esm/client/app-bootstrap.js +1 -1
  20. package/dist/esm/client/index.js +1 -1
  21. package/dist/esm/server/dev/hot-reloader-turbopack.js +1 -1
  22. package/dist/esm/server/dev/hot-reloader-webpack.js +1 -1
  23. package/dist/esm/server/lib/app-info-log.js +1 -1
  24. package/dist/esm/server/lib/start-server.js +1 -1
  25. package/dist/esm/shared/lib/errors/canary-only-config-error.js +1 -1
  26. package/dist/server/dev/hot-reloader-turbopack.js +1 -1
  27. package/dist/server/dev/hot-reloader-webpack.js +1 -1
  28. package/dist/server/lib/app-info-log.js +1 -1
  29. package/dist/server/lib/start-server.js +1 -1
  30. package/dist/shared/lib/errors/canary-only-config-error.js +1 -1
  31. package/dist/telemetry/anonymous-meta.js +1 -1
  32. package/dist/telemetry/events/session-stopped.js +2 -2
  33. package/dist/telemetry/events/version.js +2 -2
  34. package/package.json +15 -15
package/dist/bin/next CHANGED
@@ -79,7 +79,7 @@ const program = new NextRootCommand();
79
79
  program.name('next').description('The Next.js CLI allows you to develop, build, start your application, and more.').configureHelp({
80
80
  formatHelp: (cmd, helper)=>(0, _formatclihelpoutput.formatCliHelpOutput)(cmd, helper),
81
81
  subcommandTerm: (cmd)=>`${cmd.name()} ${cmd.usage()}`
82
- }).helpCommand(false).helpOption('-h, --help', 'Displays this message.').version(`Next.js v${"16.0.1-canary.1"}`, '-v, --version', 'Outputs the Next.js version.');
82
+ }).helpCommand(false).helpOption('-h, --help', 'Displays this message.').version(`Next.js v${"16.0.1-canary.2"}`, '-v, --version', 'Outputs the Next.js version.');
83
83
  program.command('build').description('Creates an optimized production build of your application. The output displays information about each route.').argument('[directory]', `A directory on which to build the application. ${(0, _picocolors.italic)('If no directory is provided, the current directory will be used.')}`).option('-d, --debug', 'Enables a more verbose build output.').option('--debug-prerender', 'Enables debug mode for prerendering. Not for production use!').option('--no-mangling', 'Disables mangling.').option('--profile', 'Enables production profiling for React.').option('--experimental-app-only', 'Builds only App Router routes.').option('--turbo', 'Builds using Turbopack.').option('--turbopack', 'Builds using Turbopack.').option('--webpack', 'Builds using webpack.').addOption(new _commander.Option('--experimental-build-mode [mode]', 'Uses an experimental build mode.').choices([
84
84
  'compile',
85
85
  'generate',
@@ -375,7 +375,7 @@ async function build(dir, reactProductionProfiling = false, debugOutput = false,
375
375
  try {
376
376
  const nextBuildSpan = (0, _trace.trace)('next-build', undefined, {
377
377
  buildMode: experimentalBuildMode,
378
- version: "16.0.1-canary.1"
378
+ version: "16.0.1-canary.2"
379
379
  });
380
380
  _buildcontext.NextBuildContext.nextBuildSpan = nextBuildSpan;
381
381
  _buildcontext.NextBuildContext.dir = dir;
@@ -896,7 +896,7 @@ async function build(dir, reactProductionProfiling = false, debugOutput = false,
896
896
  // Files outside of the distDir can be "type": "module"
897
897
  await writeFileUtf8(_path.default.join(distDir, 'package.json'), '{"type": "commonjs"}');
898
898
  // These are written to distDir, so they need to come after creating and cleaning distDr.
899
- await (0, _builddiagnostics.recordFrameworkVersion)("16.0.1-canary.1");
899
+ await (0, _builddiagnostics.recordFrameworkVersion)("16.0.1-canary.2");
900
900
  await (0, _builddiagnostics.updateBuildDiagnostics)({
901
901
  buildStage: 'start'
902
902
  });
@@ -2573,7 +2573,7 @@ async function build(dir, reactProductionProfiling = false, debugOutput = false,
2573
2573
  configOutDir: _path.default.join(dir, configOutDir),
2574
2574
  staticPages,
2575
2575
  serverPropsPages,
2576
- nextVersion: "16.0.1-canary.1",
2576
+ nextVersion: "16.0.1-canary.2",
2577
2577
  tracingRoot: outputFileTracingRoot,
2578
2578
  hasNodeMiddleware,
2579
2579
  hasInstrumentationHook,
@@ -4,9 +4,10 @@ import type { AppSegment } from '../segment-config/app/app-segments';
4
4
  import type { FallbackRouteParam, PrerenderedRoute, StaticPathsResult } from './types';
5
5
  import { FallbackMode } from '../../lib/fallback';
6
6
  import type { IncrementalCache } from '../../server/lib/incremental-cache';
7
+ import type { LoaderTree } from '../../server/lib/app-dir-module';
7
8
  import type { NextConfigComplete } from '../../server/config-shared';
8
9
  import type { WorkStore } from '../../server/app-render/work-async-storage.external';
9
- import type { DynamicParamTypes } from '../../shared/lib/app-router-types';
10
+ import type { AppRouteModule } from '../../server/route-modules/app-route/module.compiled';
10
11
  /**
11
12
  * Filters out duplicate parameters from a list of parameters.
12
13
  * This function uses a Map to efficiently store and retrieve unique parameter combinations.
@@ -90,20 +91,20 @@ export declare function assignErrorIfEmpty(prerenderedRoutes: readonly Prerender
90
91
  readonly paramName: string;
91
92
  }>): void;
92
93
  /**
93
- * Resolves parallel route parameters from regular route parameters. This function
94
- * handles the complex logic of determining how to populate parallel route params
95
- * based on their type (catchall, optional-catchall, or regular) and the current
96
- * state of fallback parameters.
94
+ * Resolves parallel route parameters from the loader tree. This function uses
95
+ * tree-based traversal to correctly handle the hierarchical structure of parallel
96
+ * routes and accurately determine parameter values based on their depth in the tree.
97
97
  *
98
- * @param parallelRouteSegments - Array of parallel route segments with their types and param names
98
+ * Unlike interpolateParallelRouteParams (which has a complete URL at runtime),
99
+ * this build-time function determines which parallel route params are unknown.
100
+ * The pathname may contain placeholders like [slug], making it incomplete.
101
+ *
102
+ * @param loaderTree - The loader tree structure containing route hierarchy
99
103
  * @param params - The current route parameters object (will be mutated)
100
- * @param pathname - The current pathname being processed
104
+ * @param pathname - The current pathname being processed (may contain placeholders)
101
105
  * @param fallbackRouteParams - Array of fallback route parameters (will be mutated)
102
106
  */
103
- export declare function resolveParallelRouteParams(parallelRouteSegments: ReadonlyArray<{
104
- readonly paramName: string;
105
- readonly paramType: DynamicParamTypes;
106
- }>, params: Params, pathname: string, fallbackRouteParams: FallbackRouteParam[]): void;
107
+ export declare function resolveParallelRouteParams(loaderTree: LoaderTree, params: Params, pathname: string, fallbackRouteParams: FallbackRouteParam[]): void;
107
108
  /**
108
109
  * Processes app directory segments to build route parameters from generateStaticParams functions.
109
110
  * This function walks through the segments array and calls generateStaticParams for each segment that has it,
@@ -138,7 +139,7 @@ export declare function buildAppStaticPaths({ dir, page, distDir, cacheComponent
138
139
  cacheMaxMemorySize: number;
139
140
  requestHeaders: IncrementalCache['requestHeaders'];
140
141
  nextConfigOutput: 'standalone' | 'export' | undefined;
141
- ComponentMod: AppPageModule;
142
+ ComponentMod: AppPageModule | AppRouteModule;
142
143
  isRoutePPREnabled: boolean;
143
144
  buildId: string;
144
145
  rootParamKeys: readonly string[];
@@ -49,6 +49,8 @@ const _escapepathdelimiters = /*#__PURE__*/ _interop_require_default(require("..
49
49
  const _createincrementalcache = require("../../export/helpers/create-incremental-cache");
50
50
  const _invarianterror = require("../../shared/lib/invariant-error");
51
51
  const _getsegmentparam = require("../../shared/lib/router/utils/get-segment-param");
52
+ const _parseloadertree = require("../../shared/lib/router/utils/parse-loader-tree");
53
+ const _interceptionroutes = require("../../shared/lib/router/utils/interception-routes");
52
54
  const _emptygeneratestaticparamserror = require("../../shared/lib/errors/empty-generate-static-params-error");
53
55
  function _interop_require_default(obj) {
54
56
  return obj && obj.__esModule ? obj : {
@@ -404,55 +406,119 @@ function assignErrorIfEmpty(prerenderedRoutes, childrenRouteParams) {
404
406
  }
405
407
  }
406
408
  }
407
- function resolveParallelRouteParams(parallelRouteSegments, params, pathname, fallbackRouteParams) {
408
- // Resolve parallel route params from the regular route params
409
- for (const { paramType, paramName } of parallelRouteSegments){
410
- // Check if we can resolve this from existing params
411
- if (params[paramName]) {
412
- continue;
409
+ function resolveParallelRouteParams(loaderTree, params, pathname, fallbackRouteParams) {
410
+ // Stack-based traversal with depth and parallel route key tracking
411
+ const stack = [
412
+ {
413
+ tree: loaderTree,
414
+ depth: 0,
415
+ parallelKey: 'children'
413
416
  }
414
- if (paramType === 'catchall' || paramType === 'optional-catchall') {
415
- // If there are any fallback route segments then we can't use the
416
- // pathname to derive the value because it's not complete. We can
417
- // make this assumption because the routes are always resolved left
418
- // to right and the catchall is always the last segment, so any
419
- // route parameters that are unknown will always contribute to the
420
- // pathname and therefore the catchall param too.
421
- if (fallbackRouteParams.some((param)=>!param.isParallelRouteParam)) {
422
- fallbackRouteParams.push((0, _utils.createFallbackRouteParam)(paramName, paramType, true));
423
- continue;
424
- }
425
- // For catchall routes in parallel segments, derive from pathname
426
- // Similar to getDynamicParam's pagePath parsing logic
427
- const pathSegments = pathname.split('/').filter(Boolean);
428
- // For catchall parallel routes, we use the full path segments
429
- // This mimics the behavior in getDynamicParam where the pagePath
430
- // is split and used to populate catchall values
431
- if (pathSegments.length > 0) {
432
- // FIXME: (NAR-335) this should handle prefixed segments
433
- params[paramName] = pathSegments;
434
- } else if (paramType === 'optional-catchall') {
435
- params[paramName] = [];
436
- } else {
437
- // We shouldn't be able to match a catchall segment without any path
438
- // segments if it's not an optional catchall.
439
- throw Object.defineProperty(new _invarianterror.InvariantError(`Unexpected empty path segments match for a pathname "${pathname}" with param "${paramName}" of type "${paramType}"`), "__NEXT_ERROR_CODE", {
440
- value: "E792",
441
- enumerable: false,
442
- configurable: true
443
- });
417
+ ];
418
+ // Parse pathname into segments for depth-based resolution
419
+ const pathSegments = pathname.split('/').filter(Boolean);
420
+ while(stack.length > 0){
421
+ const { tree, depth, parallelKey } = stack.pop();
422
+ const { segment, parallelRoutes } = (0, _parseloadertree.parseLoaderTree)(tree);
423
+ // Only process segments that are in parallel routes (not the main 'children' route)
424
+ if (parallelKey !== 'children') {
425
+ const segmentParam = (0, _getsegmentparam.getSegmentParam)(segment);
426
+ if (segmentParam && !params.hasOwnProperty(segmentParam.param)) {
427
+ const { param: paramName, type: paramType } = segmentParam;
428
+ switch(paramType){
429
+ case 'catchall':
430
+ case 'optional-catchall':
431
+ case 'catchall-intercepted':
432
+ // If there are any non-parallel fallback route segments, we can't use the
433
+ // pathname to derive the value because it's not complete. We can make
434
+ // this assumption because routes are resolved left to right.
435
+ if (fallbackRouteParams.some((param)=>!param.isParallelRouteParam)) {
436
+ fallbackRouteParams.push((0, _utils.createFallbackRouteParam)(paramName, paramType, true));
437
+ break;
438
+ }
439
+ // For catchall routes in parallel segments, derive from pathname
440
+ // using depth to determine which segments to use
441
+ const remainingSegments = pathSegments.slice(depth);
442
+ // Process segments to handle any embedded dynamic params
443
+ // Track if we encounter any unknown param placeholders
444
+ let hasUnknownParam = false;
445
+ const processedSegments = remainingSegments.flatMap((pathSegment)=>{
446
+ const param = (0, _getsegmentparam.getSegmentParam)(pathSegment);
447
+ if (param) {
448
+ // If the segment is a param placeholder, check if we have its value
449
+ if (!params.hasOwnProperty(param.param)) {
450
+ // Unknown param placeholder in pathname - can't derive full value
451
+ hasUnknownParam = true;
452
+ return undefined;
453
+ }
454
+ // If the segment matches a param, return the param value
455
+ // We don't encode values here as that's handled during retrieval.
456
+ return params[param.param];
457
+ }
458
+ // Otherwise it's a static segment
459
+ return pathSegment;
460
+ }).filter((s)=>s !== undefined);
461
+ // If we encountered any unknown param placeholders, we can't derive
462
+ // the full catch-all value from the pathname, so mark as fallback.
463
+ if (hasUnknownParam) {
464
+ fallbackRouteParams.push((0, _utils.createFallbackRouteParam)(paramName, paramType, true));
465
+ break;
466
+ }
467
+ if (processedSegments.length > 0) {
468
+ params[paramName] = processedSegments;
469
+ } else if (paramType === 'optional-catchall') {
470
+ params[paramName] = [];
471
+ } else {
472
+ // We shouldn't be able to match a catchall segment without any path
473
+ // segments if it's not an optional catchall
474
+ throw Object.defineProperty(new _invarianterror.InvariantError(`Unexpected empty path segments match for a pathname "${pathname}" with param "${paramName}" of type "${paramType}"`), "__NEXT_ERROR_CODE", {
475
+ value: "E792",
476
+ enumerable: false,
477
+ configurable: true
478
+ });
479
+ }
480
+ break;
481
+ case 'dynamic':
482
+ case 'dynamic-intercepted':
483
+ // For regular dynamic parameters, take the segment at this depth
484
+ if (depth < pathSegments.length) {
485
+ const pathSegment = pathSegments[depth];
486
+ const param = (0, _getsegmentparam.getSegmentParam)(pathSegment);
487
+ // Check if the segment at this depth is a placeholder for an unknown param
488
+ if (param && !params.hasOwnProperty(param.param)) {
489
+ // The segment is a placeholder like [category] and we don't have the value
490
+ fallbackRouteParams.push((0, _utils.createFallbackRouteParam)(paramName, paramType, true));
491
+ break;
492
+ }
493
+ // If the segment matches a param, use the param value from params object
494
+ // Otherwise it's a static segment, just use it directly
495
+ // We don't encode values here as that's handled during retrieval
496
+ params[paramName] = param ? params[param.param] : pathSegment;
497
+ } else {
498
+ // No segment at this depth, mark as fallback.
499
+ fallbackRouteParams.push((0, _utils.createFallbackRouteParam)(paramName, paramType, true));
500
+ }
501
+ break;
502
+ default:
503
+ paramType;
504
+ }
444
505
  }
445
- } else if (paramType === 'dynamic') {
446
- // We can't resolve dynamic param values at build time because they're
447
- // inferred from the request pathname.
448
- fallbackRouteParams.push((0, _utils.createFallbackRouteParam)(paramName, paramType, true));
449
- } else {
450
- // This is some other type of route param that shouldn't get resolved
451
- // statically.
452
- throw Object.defineProperty(new _invarianterror.InvariantError(`Unexpected match for a pathname "${pathname}" with a param "${paramName}" of type "${paramType}"`), "__NEXT_ERROR_CODE", {
453
- value: "E791",
454
- enumerable: false,
455
- configurable: true
506
+ }
507
+ // Calculate next depth - increment if this is not a route group and not empty
508
+ let nextDepth = depth;
509
+ // Route groups are like (marketing) or (dashboard), NOT interception routes like (.)photo
510
+ // Interception routes start with markers like (.), (..), (...), (..)(..)) and should increment depth
511
+ const isInterceptionRoute = _interceptionroutes.INTERCEPTION_ROUTE_MARKERS.some((marker)=>segment.startsWith(marker));
512
+ const isRouteGroup = !isInterceptionRoute && segment.startsWith('(') && segment.endsWith(')');
513
+ if (!isRouteGroup && segment !== '') {
514
+ nextDepth++;
515
+ }
516
+ // Add all parallel routes to the stack for processing.
517
+ for (const [key, route] of Object.entries(parallelRoutes)){
518
+ stack.push({
519
+ tree: route,
520
+ depth: nextDepth,
521
+ parallelKey: key
456
522
  });
457
523
  }
458
524
  }
@@ -552,7 +618,6 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
552
618
  cacheMaxMemorySize
553
619
  });
554
620
  const childrenRouteParamSegments = [];
555
- const parallelRouteSegments = [];
556
621
  // These are all the parallel fallback route params that will be included when
557
622
  // we're emitting the route for the base route.
558
623
  const parallelFallbackRouteParams = [];
@@ -576,13 +641,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
576
641
  if (nonParallelParamNames.has(segment.paramName)) {
577
642
  continue;
578
643
  }
579
- // Collect all the parallel route segments that have dynamic params for
580
- // second-pass resolution.
581
- parallelRouteSegments.push({
582
- name: segment.name,
583
- paramName: segment.paramName,
584
- paramType: segment.paramType
585
- });
644
+ // Collect parallel fallback route params for the base route.
645
+ // The actual parallel route param resolution is now handled by
646
+ // resolveParallelRouteParams using the loader tree.
586
647
  parallelFallbackRouteParams.push((0, _utils.createFallbackRouteParam)(segment.paramName, segment.paramType, true));
587
648
  } else {
588
649
  // Collect all the route param keys that are not parallel route params.
@@ -712,8 +773,11 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
712
773
  pathname = pathname.replace(segment.name, (0, _utils.encodeParam)(paramValue, (value)=>(0, _escapepathdelimiters.default)(value, true)));
713
774
  encodedPathname = encodedPathname.replace(segment.name, (0, _utils.encodeParam)(paramValue, encodeURIComponent));
714
775
  }
715
- // Resolve parallel route params from the regular route params
716
- resolveParallelRouteParams(parallelRouteSegments, params, pathname, fallbackRouteParams);
776
+ // Resolve parallel route params from the loader tree if this is from an
777
+ // app page.
778
+ if ('loaderTree' in ComponentMod.routeModule.userland && Array.isArray(ComponentMod.routeModule.userland.loaderTree)) {
779
+ resolveParallelRouteParams(ComponentMod.routeModule.userland.loaderTree, params, pathname, fallbackRouteParams);
780
+ }
717
781
  const fallbackRootParams = [];
718
782
  for (const { paramName, isParallelRouteParam } of fallbackRouteParams){
719
783
  // Only add the param to the fallback root params if it's not a