vinext 0.1.7 → 0.1.8

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 (92) hide show
  1. package/dist/check.d.ts +18 -0
  2. package/dist/check.js +37 -17
  3. package/dist/cli.js +2 -2
  4. package/dist/config/next-config.d.ts +2 -1
  5. package/dist/config/next-config.js +3 -0
  6. package/dist/config/server-external-packages.d.ts +4 -0
  7. package/dist/config/server-external-packages.js +91 -0
  8. package/dist/deploy.d.ts +7 -0
  9. package/dist/deploy.js +25 -18
  10. package/dist/entries/app-rsc-entry.js +54 -10
  11. package/dist/entries/app-rsc-manifest.js +8 -0
  12. package/dist/entries/pages-client-entry.js +1 -0
  13. package/dist/entries/pages-server-entry.js +1 -0
  14. package/dist/index.js +46 -20
  15. package/dist/init.js +2 -1
  16. package/dist/plugins/middleware-server-only.d.ts +8 -6
  17. package/dist/plugins/middleware-server-only.js +8 -7
  18. package/dist/plugins/optimize-imports.js +1 -1
  19. package/dist/routing/app-route-graph.d.ts +6 -2
  20. package/dist/routing/app-route-graph.js +61 -13
  21. package/dist/routing/app-router.d.ts +5 -0
  22. package/dist/routing/app-router.js +5 -0
  23. package/dist/routing/file-matcher.d.ts +5 -0
  24. package/dist/routing/file-matcher.js +7 -1
  25. package/dist/server/app-browser-entry.js +42 -147
  26. package/dist/server/app-browser-history-controller.d.ts +2 -1
  27. package/dist/server/app-browser-history-controller.js +6 -2
  28. package/dist/server/app-browser-server-action-client.d.ts +32 -0
  29. package/dist/server/app-browser-server-action-client.js +128 -0
  30. package/dist/server/app-fallback-renderer.d.ts +3 -1
  31. package/dist/server/app-fallback-renderer.js +6 -2
  32. package/dist/server/app-page-boundary-render.d.ts +3 -0
  33. package/dist/server/app-page-boundary-render.js +14 -3
  34. package/dist/server/app-page-cache-finalizer.d.ts +1 -0
  35. package/dist/server/app-page-cache-finalizer.js +8 -2
  36. package/dist/server/app-page-dispatch.d.ts +33 -4
  37. package/dist/server/app-page-dispatch.js +62 -90
  38. package/dist/server/app-page-element-builder.d.ts +7 -1
  39. package/dist/server/app-page-element-builder.js +56 -19
  40. package/dist/server/app-page-head.d.ts +16 -1
  41. package/dist/server/app-page-head.js +44 -22
  42. package/dist/server/app-page-params.d.ts +2 -1
  43. package/dist/server/app-page-params.js +8 -1
  44. package/dist/server/app-page-ppr-runtime.d.ts +7 -0
  45. package/dist/server/app-page-ppr-runtime.js +70 -0
  46. package/dist/server/app-page-probe.d.ts +1 -0
  47. package/dist/server/app-page-probe.js +1 -1
  48. package/dist/server/app-page-render.d.ts +4 -1
  49. package/dist/server/app-page-render.js +8 -3
  50. package/dist/server/app-page-request.d.ts +8 -1
  51. package/dist/server/app-page-request.js +23 -11
  52. package/dist/server/app-page-route-wiring.d.ts +6 -1
  53. package/dist/server/app-page-route-wiring.js +30 -8
  54. package/dist/server/app-page-search-params-observation.d.ts +4 -2
  55. package/dist/server/app-page-search-params-observation.js +11 -7
  56. package/dist/server/app-ppr-fallback-shell-render.d.ts +4 -3
  57. package/dist/server/app-route-handler-dispatch.js +1 -0
  58. package/dist/server/app-route-handler-execution.js +2 -1
  59. package/dist/server/app-route-module-loader.d.ts +2 -0
  60. package/dist/server/app-route-module-loader.js +1 -0
  61. package/dist/server/app-router-entry.js +7 -6
  62. package/dist/server/app-rsc-errors.js +7 -1
  63. package/dist/server/app-rsc-handler.d.ts +2 -1
  64. package/dist/server/app-rsc-handler.js +6 -9
  65. package/dist/server/app-rsc-route-matching.d.ts +7 -0
  66. package/dist/server/app-rsc-route-matching.js +36 -3
  67. package/dist/server/app-segment-config.d.ts +1 -0
  68. package/dist/server/app-segment-config.js +32 -2
  69. package/dist/server/app-server-action-execution.d.ts +4 -0
  70. package/dist/server/app-server-action-execution.js +41 -10
  71. package/dist/server/app-ssr-entry.js +4 -1
  72. package/dist/server/app-static-generation.d.ts +1 -0
  73. package/dist/server/app-static-generation.js +1 -0
  74. package/dist/server/headers.d.ts +3 -1
  75. package/dist/server/headers.js +3 -1
  76. package/dist/server/prod-server.js +15 -6
  77. package/dist/server/worker-utils.d.ts +2 -1
  78. package/dist/server/worker-utils.js +7 -1
  79. package/dist/shims/error-boundary.d.ts +19 -1
  80. package/dist/shims/error-boundary.js +11 -1
  81. package/dist/shims/headers.d.ts +3 -1
  82. package/dist/shims/headers.js +16 -5
  83. package/dist/shims/link.js +16 -12
  84. package/dist/shims/metadata.d.ts +3 -2
  85. package/dist/shims/metadata.js +8 -4
  86. package/dist/shims/router.js +13 -2
  87. package/dist/typegen.js +6 -5
  88. package/dist/utils/path.d.ts +2 -1
  89. package/dist/utils/path.js +1 -1
  90. package/dist/utils/project.d.ts +4 -0
  91. package/dist/utils/project.js +5 -1
  92. package/package.json +7 -3
@@ -30,6 +30,8 @@ const appElementsPath = resolveEntryPath("../server/app-elements.js", import.met
30
30
  const appPageRouteWiringPath = resolveEntryPath("../server/app-page-route-wiring.js", import.meta.url);
31
31
  const appPageProbePath = resolveEntryPath("../server/app-page-probe.js", import.meta.url);
32
32
  const appPageDispatchPath = resolveEntryPath("../server/app-page-dispatch.js", import.meta.url);
33
+ const appPagePprRuntimePath = resolveEntryPath("../server/app-page-ppr-runtime.js", import.meta.url);
34
+ const fileBasedMetadataPath = resolveEntryPath("../server/file-based-metadata.js", import.meta.url);
33
35
  const appPageRequestPath = resolveEntryPath("../server/app-page-request.js", import.meta.url);
34
36
  const appSegmentConfigPath = resolveEntryPath("../server/app-segment-config.js", import.meta.url);
35
37
  const appRscRouteMatchingPath = resolveEntryPath("../server/app-rsc-route-matching.js", import.meta.url);
@@ -129,6 +131,11 @@ ${hasPagesDir ? `import {
129
131
  const __loadAppRouteHandlerDispatch = () => import(${JSON.stringify(appRouteHandlerDispatchPath)});
130
132
  ${hasServerActions ? `const __loadAppServerActionExecution = () => import(${JSON.stringify(appServerActionExecutionPath)});` : ""}
131
133
  ${(metadataRoutes?.length ?? 0) > 0 ? `const __loadMetadataRouteResponse = () => import(${JSON.stringify(metadataRouteResponsePath)});` : ""}
134
+ ${(metadataRoutes?.length ?? 0) > 0 ? `const __loadFileBasedMetadata = () => import(${JSON.stringify(fileBasedMetadataPath)});
135
+ async function __applyFileBasedMetadata(...args) {
136
+ const { applyFileBasedMetadata } = await __loadFileBasedMetadata();
137
+ return applyFileBasedMetadata(...args);
138
+ }` : ""}
132
139
  import {
133
140
  sanitizeErrorForClient as __sanitizeErrorForClient,
134
141
  } from ${JSON.stringify(appRscErrorsPath)};
@@ -152,6 +159,10 @@ import { buildAppPageProbes as __buildAppPageProbes } from ${JSON.stringify(appP
152
159
  import {
153
160
  dispatchAppPage as __dispatchAppPage,
154
161
  } from ${JSON.stringify(appPageDispatchPath)};
162
+ ${cacheComponents ? `import {
163
+ appPagePprRuntime as __appPagePprRuntime,
164
+ createAppPprFallbackShells as __createAppPprFallbackShells,
165
+ } from ${JSON.stringify(appPagePprRuntimePath)};` : ""}
155
166
  import {
156
167
  resolveAppPageGenerateStaticParamsSources as __resolveAppPageGenerateStaticParamsSources,
157
168
  } from ${JSON.stringify(appPageRequestPath)};
@@ -234,6 +245,11 @@ function __resolveRouteFetchCacheMode(route) {
234
245
  return __resolveAppPageFetchCacheMode({
235
246
  layouts: route.layouts,
236
247
  page: route.page,
248
+ parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
249
+ slot.layout,
250
+ ...(slot.configLayouts ?? []),
251
+ slot.page ?? slot.default,
252
+ ]),
237
253
  });
238
254
  }
239
255
 
@@ -241,6 +257,11 @@ function __resolveRouteDynamicConfig(route) {
241
257
  return __resolveAppPageSegmentConfig({
242
258
  layouts: route.layouts,
243
259
  page: route.page,
260
+ parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
261
+ slot.layout,
262
+ ...(slot.configLayouts ?? []),
263
+ slot.page ?? slot.default,
264
+ ]),
244
265
  }).dynamicConfig ?? null;
245
266
  }
246
267
 
@@ -248,6 +269,11 @@ function __resolveRouteRuntime(route) {
248
269
  return __resolveAppPageSegmentConfig({
249
270
  layouts: route.layouts,
250
271
  page: route.page,
272
+ parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
273
+ slot.layout,
274
+ ...(slot.configLayouts ?? []),
275
+ slot.page ?? slot.default,
276
+ ]),
251
277
  }).runtime ?? null;
252
278
  }
253
279
 
@@ -317,6 +343,7 @@ const createRscOnErrorHandler = (request, pathname, routePath) =>
317
343
  createAppRscOnErrorHandler(_reportRequestError, request, pathname, routePath);
318
344
 
319
345
  const __fallbackRenderer = __createAppFallbackRenderer({
346
+ ${(metadataRoutes?.length ?? 0) > 0 ? "applyFileBasedMetadata: __applyFileBasedMetadata," : ""}
320
347
  basePath: __basePath,
321
348
  trailingSlash: __trailingSlash,
322
349
  rootBoundaries: {
@@ -366,6 +393,7 @@ async function buildPageElements(route, params, routePath, pageRequest, layoutPa
366
393
  // Hydrate lazy page/route-handler modules before any synchronous read.
367
394
  await __ensureRouteLoaded(route);
368
395
  return __buildPageElements({
396
+ ${(metadataRoutes?.length ?? 0) > 0 ? "applyFileBasedMetadata: __applyFileBasedMetadata," : ""}
369
397
  route,
370
398
  params,
371
399
  routePath,
@@ -401,7 +429,6 @@ export const __assetPrefix = ${JSON.stringify(assetPrefix)};
401
429
  export const __inlineCss = ${JSON.stringify(inlineCss)};
402
430
  export const __hasPagesDir = ${JSON.stringify(hasPagesDir)};
403
431
  export const getRenderedConcreteUrlPathsForRoute = __getRenderedConcreteUrlPathsForRoute;
404
- const __cacheComponents = ${JSON.stringify(cacheComponents)};
405
432
 
406
433
  export async function seedMemoryCacheFromPrerender(serverDir) {
407
434
  const { seedMemoryCacheFromPrerender: __seedMemoryCacheFromPrerender } =
@@ -456,7 +483,9 @@ export default createAppRscHandler({
456
483
  },
457
484
  registerCacheAdapters: __registerConfiguredCacheAdapters,
458
485
  configHeaders: __configHeaders,
459
- cacheComponents: __cacheComponents,
486
+ ${cacheComponents ? `createPprFallbackShells(route, params) {
487
+ return __createAppPprFallbackShells(route, params);
488
+ },` : ""}
460
489
  configRedirects: __configRedirects,
461
490
  configRewrites: __configRewrites,
462
491
  imageConfig: __imageConfig,
@@ -492,7 +521,12 @@ export default createAppRscHandler({
492
521
  const __segmentConfig = __resolveAppPageSegmentConfig({
493
522
  layouts: route.layouts,
494
523
  page: route.page,
495
- parallelPages: Object.values(route.slots ?? {}).map((slot) => slot.page),
524
+ parallelPages: Object.values(route.slots ?? {}).map((slot) => slot.page ?? slot.default),
525
+ parallelSegments: Object.values(route.slots ?? {}).flatMap((slot) => [
526
+ slot.layout,
527
+ ...(slot.configLayouts ?? []),
528
+ slot.page ?? slot.default,
529
+ ]),
496
530
  });
497
531
  const __generateStaticParams = __resolveAppPageGenerateStaticParamsSources({
498
532
  layouts: route.layouts,
@@ -506,7 +540,7 @@ export default createAppRscHandler({
506
540
  ensureRouteLoaded: __ensureRouteLoaded,
507
541
  clientTraceMetadata: __clientTraceMetadata,
508
542
  reactMaxHeadersLength: __reactMaxHeadersLength,
509
- buildPageElement(targetRoute, targetParams, targetOpts, targetSearchParams, layoutParamAccess) {
543
+ buildPageElement(targetRoute, targetParams, targetOpts, targetSearchParams, layoutParamAccess, buildOptions) {
510
544
  return buildPageElements(targetRoute, targetParams, cleanPathname, {
511
545
  opts: targetOpts,
512
546
  searchParams: targetSearchParams,
@@ -514,6 +548,8 @@ export default createAppRscHandler({
514
548
  request,
515
549
  mountedSlotsHeader,
516
550
  renderMode,
551
+ observeMetadataSearchParamsAccess: buildOptions?.observeMetadataSearchParamsAccess === true,
552
+ observePageSearchParamsAccess: buildOptions?.observePageSearchParamsAccess === true,
517
553
  }, layoutParamAccess, displayPathname);
518
554
  },
519
555
  clientReuseManifest,
@@ -570,6 +606,7 @@ export default createAppRscHandler({
570
606
  params,
571
607
  pprFallbackCacheShells,
572
608
  pprFallbackShell,
609
+ pprRuntime: ${cacheComponents ? "__appPagePprRuntime" : "undefined"},
573
610
  renderedConcreteUrlPaths,
574
611
  skipStaticParamsValidation,
575
612
  staticParamsValidationParams,
@@ -583,7 +620,7 @@ export default createAppRscHandler({
583
620
  route,
584
621
  });
585
622
  },
586
- async probePage() {
623
+ async probePage(probeSearchParams = searchParams) {
587
624
  const __probeIntercept = findIntercept(cleanPathname, interceptionContext);
588
625
  // The intercepting-route page module is lazy (page: null + __pageLoader).
589
626
  // Resolve it before probing so buildAppPageProbes inspects the real page
@@ -598,21 +635,21 @@ export default createAppRscHandler({
598
635
  route,
599
636
  pageComponent: PageComponent,
600
637
  asyncRouteParams: _asyncRouteParams,
601
- searchParams,
638
+ searchParams: probeSearchParams,
602
639
  intercept: __probeIntercept,
603
640
  isRscRequest,
604
641
  matchedParams: params,
605
642
  makeThenableParams,
606
643
  }));
607
644
  },
608
- renderErrorBoundaryPage(renderErr) {
645
+ renderErrorBoundaryPage(renderErr, errorOrigin) {
609
646
  const __activeIntercept = findIntercept(cleanPathname, interceptionContext);
610
647
  return __fallbackRenderer.renderErrorBoundary(route, renderErr, isRscRequest, request, params, scriptNonce, middlewareContext, {
611
648
  isEdgeRuntime: __isEdgeRuntime(__segmentConfig.runtime),
612
649
  sourcePageSegments: __activeIntercept?.slotKey === __SIBLING_PAGE_INTERCEPT_SLOT_KEY
613
650
  ? __activeIntercept.sourcePageSegments
614
651
  : null,
615
- });
652
+ }, errorOrigin);
616
653
  },
617
654
  renderHttpAccessFallbackPage(statusCode, opts, currentMiddlewareContext) {
618
655
  const __activeIntercept = findIntercept(cleanPathname, interceptionContext);
@@ -762,7 +799,7 @@ export default createAppRscHandler({
762
799
  const __actionMatch = matchRoute(cleanPathname);
763
800
  if (__actionMatch) await __ensureRouteLoaded(__actionMatch.route);
764
801
  const __actionIsEdgeRuntime = __actionMatch
765
- ? __isEdgeRuntime(__resolveAppPageSegmentConfig({ layouts: __actionMatch.route.layouts, page: __actionMatch.route.page }).runtime)
802
+ ? __isEdgeRuntime(__resolveRouteRuntime(__actionMatch.route))
766
803
  : false;
767
804
  return __handleServerActionRscRequest({
768
805
  actionId,
@@ -780,6 +817,8 @@ export default createAppRscHandler({
780
817
  request: actionRequest,
781
818
  mountedSlotsHeader: actionMountedSlotsHeader,
782
819
  renderMode: actionRenderMode,
820
+ observeMetadataSearchParamsAccess,
821
+ observePageSearchParamsAccess,
783
822
  }) {
784
823
  return buildPageElements(actionRoute, actionParams, actionCleanPathname, {
785
824
  opts: interceptOpts,
@@ -788,6 +827,8 @@ export default createAppRscHandler({
788
827
  request: actionRequest,
789
828
  mountedSlotsHeader: actionMountedSlotsHeader,
790
829
  renderMode: actionRenderMode,
830
+ observeMetadataSearchParamsAccess: observeMetadataSearchParamsAccess === true,
831
+ observePageSearchParamsAccess: observePageSearchParamsAccess === true,
791
832
  });
792
833
  },
793
834
  cleanPathname,
@@ -813,6 +854,7 @@ export default createAppRscHandler({
813
854
  },
814
855
  createTemporaryReferenceSet,
815
856
  decodeReply,
857
+ draftModeSecret: __draftModeSecret,
816
858
  findIntercept(pathnameToMatch) {
817
859
  return findIntercept(pathnameToMatch, interceptionContext);
818
860
  },
@@ -856,6 +898,8 @@ export default createAppRscHandler({
856
898
  return {
857
899
  interceptionContext,
858
900
  interceptLayouts: intercept.interceptLayouts,
901
+ interceptLayoutSegments: intercept.interceptLayoutSegments,
902
+ interceptBranchSegments: intercept.interceptBranchSegments,
859
903
  interceptSlotId: intercept.slotId,
860
904
  interceptSlotKey: intercept.slotKey,
861
905
  interceptSourceMatchedUrl: interceptionContext,
@@ -895,7 +939,7 @@ export default createAppRscHandler({
895
939
  },` : ""}
896
940
  publicFiles: __publicFiles,
897
941
  renderNotFound({ isRscRequest, matchedParams, middlewareContext, request, route, scriptNonce }) {
898
- const __isEdge = route ? __isEdgeRuntime(__resolveAppPageSegmentConfig({ layouts: route.layouts, page: route.page }).runtime) : false;
942
+ const __isEdge = route ? __isEdgeRuntime(__resolveRouteRuntime(route)) : false;
899
943
  return __fallbackRenderer.renderNotFound(route, isRscRequest, request, matchedParams, scriptNonce, middlewareContext, { isEdgeRuntime: __isEdge });
900
944
  },
901
945
  ${hasPagesDir ? `async renderPagesFallback({ allowRscDocumentFallback, appRouteMatch, isDataRequest, isRscRequest, matchKind, middlewareContext, pathname, pagesDataRequest, request, url }) {
@@ -74,6 +74,7 @@ function registerRouteModules(routes, imports) {
74
74
  if (slot.pagePath) imports.getLazyLoaderVar(slot.pagePath);
75
75
  if (slot.defaultPath) imports.getLazyLoaderVar(slot.defaultPath);
76
76
  if (slot.layoutPath) imports.getLazyLoaderVar(slot.layoutPath);
77
+ for (const layoutPath of slot.configLayoutPaths ?? []) imports.getLazyLoaderVar(layoutPath);
77
78
  if (slot.loadingPath) imports.getLazyLoaderVar(slot.loadingPath);
78
79
  if (slot.errorPath) imports.getLazyLoaderVar(slot.errorPath);
79
80
  for (const ir of slot.interceptingRoutes) {
@@ -112,6 +113,8 @@ function buildRouteEntries(routes, imports) {
112
113
  slotId: ${JSON.stringify(ir.slotId ?? null)},
113
114
  interceptLayouts: ${moduleArray(ir.layoutPaths.length)},
114
115
  __loadInterceptLayouts: ${lazyLoaderArray(ir.layoutPaths, imports)},
116
+ interceptLayoutSegments: ${JSON.stringify(ir.layoutSegments ?? [])},
117
+ interceptBranchSegments: ${JSON.stringify(ir.branchSegments ?? [])},
115
118
  page: null,
116
119
  __pageLoader: ${imports.getLazyLoaderVar(ir.pagePath)},
117
120
  params: ${JSON.stringify(ir.params)},
@@ -124,6 +127,8 @@ function buildRouteEntries(routes, imports) {
124
127
  sourcePageSegments: ${JSON.stringify(ir.sourcePageSegments)},
125
128
  interceptLayouts: ${moduleArray(ir.layoutPaths.length)},
126
129
  __loadInterceptLayouts: ${lazyLoaderArray(ir.layoutPaths, imports)},
130
+ interceptLayoutSegments: ${JSON.stringify(ir.layoutSegments ?? [])},
131
+ interceptBranchSegments: ${JSON.stringify(ir.branchSegments ?? [])},
127
132
  page: null,
128
133
  __pageLoader: ${imports.getLazyLoaderVar(ir.pagePath)},
129
134
  params: ${JSON.stringify(ir.params)},
@@ -137,6 +142,9 @@ function buildRouteEntries(routes, imports) {
137
142
  __loadDefault: ${slot.defaultPath ? imports.getLazyLoaderVar(slot.defaultPath) : "null"},
138
143
  layout: null,
139
144
  __loadLayout: ${slot.layoutPath ? imports.getLazyLoaderVar(slot.layoutPath) : "null"},
145
+ configLayouts: ${moduleArray(slot.configLayoutPaths?.length ?? 0)},
146
+ __loadConfigLayouts: ${lazyLoaderArray(slot.configLayoutPaths ?? [], imports)},
147
+ configLayoutTreePositions: ${JSON.stringify(slot.configLayoutTreePositions ?? [])},
140
148
  loading: null,
141
149
  __loadLoading: ${slot.loadingPath ? imports.getLazyLoaderVar(slot.loadingPath) : "null"},
142
150
  error: null,
@@ -2,6 +2,7 @@ import { normalizePathSeparators } from "../utils/path.js";
2
2
  import { findFileWithExts } from "../routing/file-matcher.js";
3
3
  import { patternToNextFormat } from "../routing/route-validation.js";
4
4
  import { apiRouter, pagesRouter } from "../routing/pages-router.js";
5
+ import "./pages-entry-helpers.js";
5
6
  //#region src/entries/pages-client-entry.ts
6
7
  /**
7
8
  * Pages Router client hydration entry generator.
@@ -3,6 +3,7 @@ import { findFileWithExts } from "../routing/file-matcher.js";
3
3
  import { apiRouter, pagesRouter } from "../routing/pages-router.js";
4
4
  import { resolveEntryPath } from "./runtime-entry-module.js";
5
5
  import { isProxyFile } from "../server/middleware.js";
6
+ import "./pages-entry-helpers.js";
6
7
  //#region src/entries/pages-server-entry.ts
7
8
  /**
8
9
  * Pages Router server entry generator.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { detectPackageManager } from "./utils/project.js";
2
- import { normalizePathSeparators, stripJsExtension, stripViteModuleQuery } from "./utils/path.js";
3
2
  import { normalizePathnameForRouteMatchStrict } from "./routing/utils.js";
4
3
  import { escapeRegExp } from "./utils/regex.js";
4
+ import { normalizePathSeparators, stripJsExtension, stripViteModuleQuery } from "./utils/path.js";
5
5
  import { buildViteResolveExtensions, createValidFileMatcher, findFileWithExts, normalizeViteResolveExtensions } from "./routing/file-matcher.js";
6
6
  import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./routing/pages-router.js";
7
7
  import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MW_CTX_HEADER, VINEXT_TIMING_HEADER } from "./server/headers.js";
@@ -35,6 +35,7 @@ import { resolveAssetsDir } from "./utils/asset-prefix.js";
35
35
  import { RESOLVED_VIRTUAL_GOOGLE_FONTS, VIRTUAL_GOOGLE_FONTS, createGoogleFontsPlugin, createLocalFontsPlugin, generateGoogleFontsVirtualModule, parseStaticObjectLiteral } from "./plugins/fonts.js";
36
36
  import { getDepOptimizeNodeEnvOptions, getViteMajorVersion, serializeViteDefine } from "./utils/vite-version.js";
37
37
  import { createRscCompatibilityId, findNextConfigPath, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
38
+ import { mergeServerExternalPackages } from "./config/server-external-packages.js";
38
39
  import { isNextDataPathname, parseNextDataPathname } from "./server/pages-data-route.js";
39
40
  import { precompressAssets } from "./build/precompress.js";
40
41
  import { ensureAssetsIgnore } from "./build/assets-ignore.js";
@@ -85,7 +86,6 @@ import { pathToFileURL } from "node:url";
85
86
  import { createHash, randomBytes, randomUUID } from "node:crypto";
86
87
  import commonjs from "vite-plugin-commonjs";
87
88
  import MagicString from "magic-string";
88
- import tsconfigPaths from "vite-tsconfig-paths";
89
89
  //#region src/index.ts
90
90
  installSocketErrorBackstop();
91
91
  function getCacheDirPrefix(cacheDir) {
@@ -138,6 +138,11 @@ function resolveOptionalDependency(projectRoot, specifier) {
138
138
  } catch {}
139
139
  return null;
140
140
  }
141
+ async function loadVite7TsconfigPathsPlugin(projectRoot) {
142
+ const resolvedPath = resolveOptionalDependency(projectRoot, "vite-tsconfig-paths");
143
+ if (!resolvedPath) throw new Error("[vinext] Vite 7 requires the optional peer dependency vite-tsconfig-paths for tsconfig path alias support. Install vite-tsconfig-paths or upgrade to Vite 8.");
144
+ return (await import(pathToFileURL(resolvedPath).href)).default();
145
+ }
141
146
  function resolveShimModulePath(shimsDir, moduleName) {
142
147
  for (const ext of [
143
148
  ".ts",
@@ -303,6 +308,8 @@ const VIRTUAL_APP_SSR_ENTRY = "virtual:vinext-app-ssr-entry";
303
308
  const RESOLVED_APP_SSR_ENTRY = "\0virtual:vinext-app-ssr-entry";
304
309
  const VIRTUAL_APP_BROWSER_ENTRY = "virtual:vinext-app-browser-entry";
305
310
  const RESOLVED_APP_BROWSER_ENTRY = "\0virtual:vinext-app-browser-entry";
311
+ const VIRTUAL_APP_CAPABILITIES = "virtual:vinext-app-capabilities";
312
+ const RESOLVED_APP_CAPABILITIES = "\0virtual:vinext-app-capabilities";
306
313
  const RESOLVED_ROOT_PARAMS = "\0virtual:vinext-root-params";
307
314
  /** Virtual module that registers config-driven cache adapters (see VinextOptions.cache). */
308
315
  const RESOLVED_CACHE_ADAPTERS = "\0" + VIRTUAL_CACHE_ADAPTERS;
@@ -332,6 +339,7 @@ function createStaticImageAsset(imagePath) {
332
339
  */
333
340
  const _shimsDir = normalizePathSeparators(path.resolve(__dirname, "shims")) + "/";
334
341
  const _fontGoogleShimPath = resolveShimModulePath(_shimsDir, "font-google");
342
+ const _appBrowserServerActionClientPath = resolveShimModulePath(normalizePathSeparators(path.resolve(__dirname, "server")), "app-browser-server-action-client");
335
343
  const _appRscHandlerPath = resolveShimModulePath(normalizePathSeparators(path.resolve(__dirname, "server")), "app-rsc-handler");
336
344
  const _canExternalizeAppRscHandler = _appRscHandlerPath.endsWith(".js");
337
345
  function isValidExportIdentifier(name) {
@@ -531,6 +539,13 @@ function vinext(options = {}) {
531
539
  throw new Error("vinext: Failed to load @vitejs/plugin-rsc.", { cause });
532
540
  });
533
541
  }
542
+ async function resolveHasServerActions(config) {
543
+ if (config.command !== "build" || !rscPluginModulePromise) return true;
544
+ const { getPluginApi } = await rscPluginModulePromise;
545
+ const pluginApi = getPluginApi(config);
546
+ if (!pluginApi || pluginApi.manager.isScanBuild) return true;
547
+ return Object.keys(pluginApi.manager.serverReferenceMetaMap).length > 0;
548
+ }
534
549
  const reactOptions = options.react && options.react !== true ? options.react : void 0;
535
550
  let reactPluginPromise = null;
536
551
  if (options.react !== false) {
@@ -576,7 +591,7 @@ function vinext(options = {}) {
576
591
  return mdxDelegatePromise;
577
592
  }
578
593
  const plugins = [
579
- ...viteMajorVersion >= 8 ? [] : [tsconfigPaths()],
594
+ ...viteMajorVersion >= 8 ? [] : [loadVite7TsconfigPathsPlugin(earlyBaseDir)],
580
595
  reactPluginPromise,
581
596
  commonjs(),
582
597
  ...viteMajorVersion >= 8 ? [{
@@ -606,6 +621,10 @@ function vinext(options = {}) {
606
621
  createMiddlewareServerOnlyPlugin({
607
622
  getMiddlewarePath: () => middlewarePath,
608
623
  getCanonicalMiddlewarePath: () => middlewarePath ? tryRealpathSync(middlewarePath) ?? middlewarePath : null,
624
+ isNeutralServerModule: (id) => {
625
+ const canonicalId = canonicalizePageTransformPath(id);
626
+ return isWithinPagesDirectory(canonicalId) && isApiPage(canonicalId);
627
+ },
609
628
  serverOnlyShimPath: resolveShimModulePath(shimsDir, "server-only")
610
629
  }),
611
630
  dataUrlCssPlugin(),
@@ -681,6 +700,7 @@ function vinext(options = {}) {
681
700
  defines[`process.env.${key}`] = JSON.stringify(value);
682
701
  }
683
702
  defines["process.env.__NEXT_ROUTER_BASEPATH"] = JSON.stringify(nextConfig.basePath);
703
+ defines["process.env.__VINEXT_HAS_PAGES_ROUTER"] = JSON.stringify(String(hasPagesDir));
684
704
  defines["process.env.__NEXT_CLIENT_ROUTER_STATIC_STALETIME"] = JSON.stringify(String(nextConfig.staleTimes.static));
685
705
  defines["process.env.__VINEXT_PREFETCH_INLINING"] = JSON.stringify(nextConfig.prefetchInlining ? "true" : "false");
686
706
  defines["process.env.__NEXT_GESTURE_TRANSITION"] = JSON.stringify(nextConfig.gestureTransition);
@@ -800,6 +820,7 @@ function vinext(options = {}) {
800
820
  hasUserMdxPlugin = pluginsFlat.some((p) => p && typeof p === "object" && "name" in p && typeof p.name === "string" && (p.name === "@mdx-js/rollup" || p.name === "mdx"));
801
821
  if (!hasUserMdxPlugin && hasMdxFiles(root, hasAppDir ? appDir : null, hasPagesDir ? pagesDir : null)) await ensureMdxDelegate("detected");
802
822
  const isSSR = !!config.build?.ssr;
823
+ const nextServerExternal = mergeServerExternalPackages(nextConfig?.serverExternalPackages, nextConfig?.transpilePackages);
803
824
  const isMultiEnv = hasAppDir || hasCloudflarePlugin || hasNitroPlugin;
804
825
  const hasBuildInput = getBuildBundlerOptions(config.build)?.input !== void 0;
805
826
  const shouldInjectPlainPagesEnvironments = !hasAppDir && !hasCloudflarePlugin && !isSSR && !hasBuildInput;
@@ -850,7 +871,9 @@ function vinext(options = {}) {
850
871
  "react",
851
872
  "react-dom",
852
873
  "react-dom/server",
853
- "ipaddr.js"
874
+ "ipaddr.js",
875
+ ...Array.isArray(config.ssr?.external) ? config.ssr.external : [],
876
+ ...nextServerExternal
854
877
  ],
855
878
  noExternal: true
856
879
  } },
@@ -895,7 +918,6 @@ function vinext(options = {}) {
895
918
  ...cssModulesOverride
896
919
  }
897
920
  };
898
- const nextServerExternal = nextConfig?.serverExternalPackages ?? [];
899
921
  const userSsrExternal = Array.isArray(config.ssr?.external) ? [...config.ssr.external, ...nextServerExternal] : config.ssr?.external === true ? true : nextServerExternal;
900
922
  const externalizeSsrReactInDev = env.command === "serve" && !hasCloudflarePlugin && !hasNitroPlugin;
901
923
  const incomingExclude = config.optimizeDeps?.exclude ?? [];
@@ -1031,7 +1053,8 @@ function vinext(options = {}) {
1031
1053
  "react",
1032
1054
  "react-dom",
1033
1055
  "react-dom/server",
1034
- "ipaddr.js"
1056
+ "ipaddr.js",
1057
+ ...nextServerExternal
1035
1058
  ],
1036
1059
  noExternal: true
1037
1060
  },
@@ -1102,7 +1125,7 @@ function vinext(options = {}) {
1102
1125
  resolveId: {
1103
1126
  filter: { id: /(?:next\/|vinext\/(?:shims\/|server\/app-rsc-handler)|virtual:vinext-|@vercel\/og(?:\.js)?$)/ },
1104
1127
  handler(id, importer) {
1105
- const cleanId = id.startsWith("\0") ? id.slice(1) : id;
1128
+ const cleanId = normalizePathSeparators(id.startsWith("\0") ? id.slice(1) : id);
1106
1129
  if (cleanId === "vinext/server/app-rsc-handler") {
1107
1130
  if (_canExternalizeAppRscHandler && this.environment?.name === "rsc" && this.environment.config?.command === "serve") return {
1108
1131
  id: _appRscHandlerPath,
@@ -1114,18 +1137,19 @@ function vinext(options = {}) {
1114
1137
  if (cleanId.startsWith("vinext/shims/")) return resolveShimModulePath(_shimsDir, stripJsExtension(stripViteModuleQuery(cleanId.slice(13))));
1115
1138
  if (cleanId === VIRTUAL_SERVER_ENTRY) return RESOLVED_SERVER_ENTRY;
1116
1139
  if (cleanId === VIRTUAL_CLIENT_ENTRY) return RESOLVED_CLIENT_ENTRY;
1117
- if (cleanId.endsWith("/virtual:vinext-server-entry") || cleanId.endsWith("\\virtual:vinext-server-entry")) return RESOLVED_SERVER_ENTRY;
1118
- if (cleanId.endsWith("/virtual:vinext-client-entry") || cleanId.endsWith("\\virtual:vinext-client-entry")) return RESOLVED_CLIENT_ENTRY;
1140
+ if (cleanId.endsWith("/virtual:vinext-server-entry")) return RESOLVED_SERVER_ENTRY;
1141
+ if (cleanId.endsWith("/virtual:vinext-client-entry")) return RESOLVED_CLIENT_ENTRY;
1119
1142
  if (cleanId === VIRTUAL_RSC_ENTRY) return RESOLVED_RSC_ENTRY;
1120
1143
  if (cleanId === VIRTUAL_APP_SSR_ENTRY) return RESOLVED_APP_SSR_ENTRY;
1121
1144
  if (cleanId === VIRTUAL_APP_BROWSER_ENTRY) return RESOLVED_APP_BROWSER_ENTRY;
1145
+ if (cleanId === VIRTUAL_APP_CAPABILITIES) return RESOLVED_APP_CAPABILITIES;
1122
1146
  if (cleanId === "next/root-params" || cleanId === "next/root-params.js") return RESOLVED_ROOT_PARAMS;
1123
- if (cleanId === "virtual:vinext-cache-adapters" || cleanId.endsWith("/virtual:vinext-cache-adapters") || cleanId.endsWith("\\virtual:vinext-cache-adapters")) return RESOLVED_CACHE_ADAPTERS;
1147
+ if (cleanId === "virtual:vinext-cache-adapters" || cleanId.endsWith("/virtual:vinext-cache-adapters")) return RESOLVED_CACHE_ADAPTERS;
1124
1148
  if (cleanId.startsWith("virtual:vinext-google-fonts?")) return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(VIRTUAL_GOOGLE_FONTS.length);
1125
- if (cleanId.endsWith("/virtual:vinext-rsc-entry") || cleanId.endsWith("\\virtual:vinext-rsc-entry")) return RESOLVED_RSC_ENTRY;
1126
- if (cleanId.endsWith("/virtual:vinext-app-ssr-entry") || cleanId.endsWith("\\virtual:vinext-app-ssr-entry")) return RESOLVED_APP_SSR_ENTRY;
1127
- if (cleanId.endsWith("/virtual:vinext-app-browser-entry") || cleanId.endsWith("\\virtual:vinext-app-browser-entry")) return RESOLVED_APP_BROWSER_ENTRY;
1128
- if (cleanId.includes("/virtual:vinext-google-fonts?") || cleanId.includes("\\virtual:vinext-google-fonts?")) {
1149
+ if (cleanId.endsWith("/virtual:vinext-rsc-entry")) return RESOLVED_RSC_ENTRY;
1150
+ if (cleanId.endsWith("/virtual:vinext-app-ssr-entry")) return RESOLVED_APP_SSR_ENTRY;
1151
+ if (cleanId.endsWith("/virtual:vinext-app-browser-entry")) return RESOLVED_APP_BROWSER_ENTRY;
1152
+ if (cleanId.includes("/virtual:vinext-google-fonts?")) {
1129
1153
  const queryIndex = cleanId.indexOf(VIRTUAL_GOOGLE_FONTS + "?");
1130
1154
  return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(queryIndex + VIRTUAL_GOOGLE_FONTS.length);
1131
1155
  }
@@ -1139,12 +1163,7 @@ function vinext(options = {}) {
1139
1163
  if (id === RESOLVED_RSC_ENTRY && hasAppDir) {
1140
1164
  const routes = await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher);
1141
1165
  const metaRoutes = scanMetadataFiles(appDir);
1142
- let hasServerActions = true;
1143
- if (this.environment?.config.command === "build" && rscPluginModulePromise) {
1144
- const { getPluginApi } = await rscPluginModulePromise;
1145
- const pluginApi = getPluginApi(this.environment.config);
1146
- if (pluginApi && !pluginApi.manager.isScanBuild) hasServerActions = Object.keys(pluginApi.manager.serverReferenceMetaMap).length > 0;
1147
- }
1166
+ const hasServerActions = await resolveHasServerActions(this.environment.config);
1148
1167
  const globalErrorPath = findFileWithExts(appDir, "global-error", fileMatcher);
1149
1168
  const globalNotFoundPath = findFileWithExts(appDir, "global-not-found", fileMatcher);
1150
1169
  rscClassificationManifest = collectRouteClassificationManifest(routes);
@@ -1194,6 +1213,13 @@ function vinext(options = {}) {
1194
1213
  }))] : [];
1195
1214
  return generateBrowserEntry(graph.routes, graph.routeManifest, pagesPrefetchRoutes, nextConfig.rewrites);
1196
1215
  }
1216
+ if (id === RESOLVED_APP_CAPABILITIES && hasAppDir) {
1217
+ const hasServerActions = await resolveHasServerActions(this.environment.config);
1218
+ return `
1219
+ export const hasServerActions = ${JSON.stringify(hasServerActions)};
1220
+ export const loadServerActionClient = ${hasServerActions ? `() => import(${JSON.stringify(_appBrowserServerActionClientPath)})` : "null"};
1221
+ `;
1222
+ }
1197
1223
  if (id.startsWith("\0virtual:vinext-google-fonts?")) return generateGoogleFontsVirtualModule(id, _fontGoogleShimPath);
1198
1224
  },
1199
1225
  // @vitejs/plugin-rsc runs the RSC environment build in two phases:
package/dist/init.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { detectPackageManager, detectPackageManagerName, ensureESModule, hasAppDir, hasViteConfig, renameCJSConfigs } from "./utils/project.js";
2
2
  import { formatReport, runCheck } from "./check.js";
3
+ import { normalizePathSeparators } from "./utils/path.js";
3
4
  import { createRequire } from "node:module";
4
5
  import fs from "node:fs";
5
6
  import path from "node:path";
@@ -176,7 +177,7 @@ function updateGitignore(root) {
176
177
  return true;
177
178
  }
178
179
  async function init(options) {
179
- const root = path.resolve(options.root);
180
+ const root = normalizePathSeparators(path.resolve(options.root));
180
181
  const port = options.port ?? 3001;
181
182
  const exec = options._exec ?? ((cmd, opts) => {
182
183
  const [program, ...args] = cmd.split(" ");
@@ -2,8 +2,8 @@ import { Plugin } from "vite";
2
2
 
3
3
  //#region src/plugins/middleware-server-only.d.ts
4
4
  /**
5
- * Allow `import 'server-only'` from middleware (and any module reachable
6
- * from middleware) in the SSR environment.
5
+ * Allow `import 'server-only'` from neutral server targets (and any module
6
+ * reachable from them) in the SSR environment.
7
7
  *
8
8
  * Background: middleware runs server-side, so importing `server-only` is
9
9
  * semantically correct. However, vinext bundles middleware into the SSR
@@ -13,9 +13,9 @@ import { Plugin } from "vite";
13
13
  *
14
14
  * 'server-only' cannot be imported in client build ('ssr' environment)
15
15
  *
16
- * Next.js solves this with webpack `issuerLayer` rules: middleware (and
17
- * `instrumentation`) sit in the `neutralTarget` layer where `server-only`
18
- * is aliased to a no-op while `client-only` still errors. See
16
+ * Next.js solves this with webpack `issuerLayer` rules: middleware,
17
+ * instrumentation, and Pages API routes sit in server-only or neutral layers
18
+ * where `server-only` is aliased to a no-op while `client-only` still errors. See
19
19
  * packages/next/src/build/webpack-config.ts ("Alias server-only and
20
20
  * client-only to proper exports based on bundling layers")
21
21
  *
@@ -23,7 +23,8 @@ import { Plugin } from "vite";
23
23
  * the behavior with import-chain taint tracking:
24
24
  *
25
25
  * 1. Seed a `tainted` set with the middleware entry path (and its
26
- * canonical realpath).
26
+ * canonical realpath), and recognize other neutral server entry modules
27
+ * such as Pages API routes through `isNeutralServerModule`.
27
28
  * 2. For every resolveId call from a tainted importer, resolve the import
28
29
  * via `this.resolve(..., { skipSelf: true })` and add the resolved id
29
30
  * to the tainted set. This propagates the taint along the import graph
@@ -47,6 +48,7 @@ import { Plugin } from "vite";
47
48
  declare function createMiddlewareServerOnlyPlugin(options: {
48
49
  getMiddlewarePath: () => string | null;
49
50
  getCanonicalMiddlewarePath: () => string | null;
51
+ isNeutralServerModule?: (id: string) => boolean;
50
52
  serverOnlyShimPath: string;
51
53
  }): Plugin;
52
54
  //#endregion
@@ -1,8 +1,8 @@
1
1
  import { normalizePathSeparators } from "../utils/path.js";
2
2
  //#region src/plugins/middleware-server-only.ts
3
3
  /**
4
- * Allow `import 'server-only'` from middleware (and any module reachable
5
- * from middleware) in the SSR environment.
4
+ * Allow `import 'server-only'` from neutral server targets (and any module
5
+ * reachable from them) in the SSR environment.
6
6
  *
7
7
  * Background: middleware runs server-side, so importing `server-only` is
8
8
  * semantically correct. However, vinext bundles middleware into the SSR
@@ -12,9 +12,9 @@ import { normalizePathSeparators } from "../utils/path.js";
12
12
  *
13
13
  * 'server-only' cannot be imported in client build ('ssr' environment)
14
14
  *
15
- * Next.js solves this with webpack `issuerLayer` rules: middleware (and
16
- * `instrumentation`) sit in the `neutralTarget` layer where `server-only`
17
- * is aliased to a no-op while `client-only` still errors. See
15
+ * Next.js solves this with webpack `issuerLayer` rules: middleware,
16
+ * instrumentation, and Pages API routes sit in server-only or neutral layers
17
+ * where `server-only` is aliased to a no-op while `client-only` still errors. See
18
18
  * packages/next/src/build/webpack-config.ts ("Alias server-only and
19
19
  * client-only to proper exports based on bundling layers")
20
20
  *
@@ -22,7 +22,8 @@ import { normalizePathSeparators } from "../utils/path.js";
22
22
  * the behavior with import-chain taint tracking:
23
23
  *
24
24
  * 1. Seed a `tainted` set with the middleware entry path (and its
25
- * canonical realpath).
25
+ * canonical realpath), and recognize other neutral server entry modules
26
+ * such as Pages API routes through `isNeutralServerModule`.
26
27
  * 2. For every resolveId call from a tainted importer, resolve the import
27
28
  * via `this.resolve(..., { skipSelf: true })` and add the resolved id
28
29
  * to the tainted set. This propagates the taint along the import graph
@@ -72,7 +73,7 @@ function createMiddlewareServerOnlyPlugin(options) {
72
73
  async handler(id, importer, opts) {
73
74
  if (this.environment?.name === "rsc") return;
74
75
  if (!importer) return;
75
- if (!isTainted(importer)) return;
76
+ if (!isTainted(importer) && !options.isNeutralServerModule?.(canonicalizeId(importer))) return;
76
77
  if (id === "server-only") return {
77
78
  id: options.serverOnlyShimPath,
78
79
  moduleSideEffects: false
@@ -1,5 +1,5 @@
1
- import { normalizePathSeparators } from "../utils/path.js";
2
1
  import { escapeRegExp } from "../utils/regex.js";
2
+ import { normalizePathSeparators } from "../utils/path.js";
3
3
  import { VIRTUAL_MODULE_ID_RE } from "../utils/virtual-module.js";
4
4
  import { getAstName } from "./ast-utils.js";
5
5
  import { createRequire } from "node:module";
@@ -23,7 +23,9 @@ type InterceptingRoute = {
23
23
  sourceMatchPattern: string; /** Absolute path to the intercepting page component */
24
24
  pagePath: string; /** Filesystem segments from app/ root to the intercepting page directory. */
25
25
  sourcePageSegments?: string[]; /** Absolute layout paths inside the intercepting route tree, outermost to innermost */
26
- layoutPaths: string[]; /** Parameter names for dynamic segments */
26
+ layoutPaths: string[]; /** Normalized branch segments accumulated at each intercept layout. */
27
+ layoutSegments?: string[][]; /** Full normalized interception branch segments through the page. */
28
+ branchSegments?: string[]; /** Parameter names for dynamic segments */
27
29
  params: string[];
28
30
  /**
29
31
  * Synthetic page-carrier slot id for sibling (slot-less) interception.
@@ -40,7 +42,9 @@ type ParallelSlot = {
40
42
  hasPage: boolean; /** Absolute path to the slot's page component */
41
43
  pagePath: string | null; /** Absolute path to the slot's default.tsx fallback */
42
44
  defaultPath: string | null; /** Absolute path to the slot's layout component (wraps slot content) */
43
- layoutPath: string | null; /** Absolute path to the slot's loading component */
45
+ layoutPath: string | null; /** Nested active-branch layouts whose exports contribute route config. */
46
+ configLayoutPaths?: string[]; /** Tree positions of configLayoutPaths relative to the slot root. */
47
+ configLayoutTreePositions?: number[]; /** Absolute path to the slot's loading component */
44
48
  loadingPath: string | null; /** Absolute path to the slot's error component */
45
49
  errorPath: string | null; /** Intercepting routes within this slot */
46
50
  interceptingRoutes: InterceptingRoute[];