vinext 0.1.0 → 0.1.1

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 (119) hide show
  1. package/dist/build/assets-ignore.d.ts +32 -0
  2. package/dist/build/assets-ignore.js +48 -0
  3. package/dist/build/client-build-config.d.ts +27 -1
  4. package/dist/build/client-build-config.js +58 -1
  5. package/dist/cli.js +2 -0
  6. package/dist/client/navigation-runtime.d.ts +8 -0
  7. package/dist/client/navigation-runtime.js +1 -1
  8. package/dist/client/vinext-next-data.d.ts +2 -1
  9. package/dist/config/config-matchers.d.ts +20 -1
  10. package/dist/config/config-matchers.js +35 -1
  11. package/dist/config/next-config.d.ts +16 -3
  12. package/dist/config/next-config.js +30 -2
  13. package/dist/deploy.js +40 -304
  14. package/dist/entries/app-rsc-entry.d.ts +8 -2
  15. package/dist/entries/app-rsc-entry.js +54 -4
  16. package/dist/entries/app-rsc-manifest.js +20 -2
  17. package/dist/entries/pages-server-entry.js +9 -1
  18. package/dist/index.js +162 -217
  19. package/dist/plugins/postcss.js +18 -14
  20. package/dist/plugins/require-context.d.ts +6 -0
  21. package/dist/plugins/require-context.js +184 -0
  22. package/dist/routing/app-route-graph.d.ts +12 -1
  23. package/dist/routing/app-route-graph.js +137 -5
  24. package/dist/routing/route-pattern.d.ts +2 -1
  25. package/dist/routing/route-pattern.js +16 -1
  26. package/dist/server/api-handler.js +4 -0
  27. package/dist/server/app-browser-entry.js +84 -39
  28. package/dist/server/app-browser-interception-context.d.ts +2 -1
  29. package/dist/server/app-browser-interception-context.js +15 -2
  30. package/dist/server/app-browser-navigation-controller.d.ts +11 -1
  31. package/dist/server/app-browser-navigation-controller.js +77 -1
  32. package/dist/server/app-browser-popstate.d.ts +12 -3
  33. package/dist/server/app-browser-popstate.js +19 -4
  34. package/dist/server/app-browser-state.d.ts +3 -0
  35. package/dist/server/app-browser-state.js +6 -3
  36. package/dist/server/app-browser-visible-commit.js +9 -7
  37. package/dist/server/app-history-state.d.ts +45 -1
  38. package/dist/server/app-history-state.js +109 -1
  39. package/dist/server/app-page-boundary-render.js +41 -19
  40. package/dist/server/app-page-dispatch.d.ts +6 -0
  41. package/dist/server/app-page-dispatch.js +3 -1
  42. package/dist/server/app-page-element-builder.d.ts +1 -0
  43. package/dist/server/app-page-element-builder.js +22 -10
  44. package/dist/server/app-page-render.d.ts +6 -0
  45. package/dist/server/app-page-render.js +5 -3
  46. package/dist/server/app-page-request.d.ts +8 -6
  47. package/dist/server/app-page-request.js +12 -9
  48. package/dist/server/app-page-response.d.ts +2 -2
  49. package/dist/server/app-page-response.js +1 -1
  50. package/dist/server/app-page-route-wiring.js +2 -1
  51. package/dist/server/app-page-stream.d.ts +37 -2
  52. package/dist/server/app-page-stream.js +36 -3
  53. package/dist/server/app-pages-bridge.d.ts +16 -0
  54. package/dist/server/app-pages-bridge.js +23 -3
  55. package/dist/server/app-route-handler-cache.d.ts +1 -0
  56. package/dist/server/app-route-handler-cache.js +1 -0
  57. package/dist/server/app-route-handler-dispatch.d.ts +1 -0
  58. package/dist/server/app-route-handler-dispatch.js +2 -0
  59. package/dist/server/app-route-handler-execution.d.ts +1 -0
  60. package/dist/server/app-route-handler-execution.js +1 -0
  61. package/dist/server/app-route-handler-runtime.d.ts +1 -0
  62. package/dist/server/app-route-handler-runtime.js +3 -2
  63. package/dist/server/app-rsc-handler.d.ts +1 -0
  64. package/dist/server/app-rsc-handler.js +4 -3
  65. package/dist/server/app-rsc-route-matching.d.ts +20 -1
  66. package/dist/server/app-rsc-route-matching.js +29 -4
  67. package/dist/server/app-server-action-execution.d.ts +11 -1
  68. package/dist/server/app-server-action-execution.js +68 -10
  69. package/dist/server/app-ssr-entry.d.ts +6 -0
  70. package/dist/server/app-ssr-entry.js +17 -1
  71. package/dist/server/dev-server.d.ts +1 -1
  72. package/dist/server/dev-server.js +54 -31
  73. package/dist/server/isr-cache.d.ts +37 -1
  74. package/dist/server/isr-cache.js +85 -1
  75. package/dist/server/navigation-planner.js +5 -3
  76. package/dist/server/navigation-trace.d.ts +1 -1
  77. package/dist/server/pages-node-compat.d.ts +2 -0
  78. package/dist/server/pages-node-compat.js +4 -0
  79. package/dist/server/pages-page-data.d.ts +10 -7
  80. package/dist/server/pages-page-data.js +4 -2
  81. package/dist/server/pages-page-handler.d.ts +9 -2
  82. package/dist/server/pages-page-handler.js +29 -16
  83. package/dist/server/pages-page-response.d.ts +11 -2
  84. package/dist/server/pages-page-response.js +8 -1
  85. package/dist/server/pages-readiness.d.ts +36 -0
  86. package/dist/server/pages-readiness.js +21 -0
  87. package/dist/server/pages-request-pipeline.d.ts +99 -0
  88. package/dist/server/pages-request-pipeline.js +209 -0
  89. package/dist/server/pages-revalidate.d.ts +15 -0
  90. package/dist/server/pages-revalidate.js +19 -0
  91. package/dist/server/prod-server.d.ts +6 -2
  92. package/dist/server/prod-server.js +101 -217
  93. package/dist/server/socket-error-backstop.d.ts +19 -1
  94. package/dist/server/socket-error-backstop.js +77 -4
  95. package/dist/shims/app-router-scroll.js +22 -4
  96. package/dist/shims/cache-runtime.js +31 -1
  97. package/dist/shims/error-boundary.d.ts +21 -11
  98. package/dist/shims/error-boundary.js +8 -1
  99. package/dist/shims/fetch-cache.d.ts +14 -1
  100. package/dist/shims/fetch-cache.js +18 -1
  101. package/dist/shims/hash-scroll.d.ts +1 -0
  102. package/dist/shims/hash-scroll.js +3 -1
  103. package/dist/shims/internal/link-status-registry.d.ts +43 -0
  104. package/dist/shims/internal/link-status-registry.js +42 -0
  105. package/dist/shims/internal/route-pattern-for-warning.d.ts +27 -0
  106. package/dist/shims/internal/route-pattern-for-warning.js +40 -0
  107. package/dist/shims/internal/utils.d.ts +1 -0
  108. package/dist/shims/link.js +20 -6
  109. package/dist/shims/navigation.d.ts +2 -2
  110. package/dist/shims/navigation.js +63 -7
  111. package/dist/shims/router-state.d.ts +1 -0
  112. package/dist/shims/router-state.js +2 -0
  113. package/dist/shims/router.d.ts +6 -3
  114. package/dist/shims/router.js +128 -21
  115. package/dist/utils/client-build-manifest.d.ts +8 -1
  116. package/dist/utils/client-build-manifest.js +30 -5
  117. package/dist/utils/client-entry-manifest.d.ts +11 -0
  118. package/dist/utils/client-entry-manifest.js +29 -0
  119. package/package.json +5 -1
package/dist/index.js CHANGED
@@ -1,13 +1,11 @@
1
1
  import { detectPackageManager } from "./utils/project.js";
2
2
  import { normalizePathnameForRouteMatchStrict } from "./routing/utils.js";
3
3
  import { buildViteResolveExtensions, createValidFileMatcher, findFileWithExts } from "./routing/file-matcher.js";
4
- import { hasBasePath } from "./utils/base-path.js";
5
4
  import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./routing/pages-router.js";
6
5
  import { normalizePathSeparators } from "./utils/path.js";
7
6
  import { INTERNAL_HEADERS, VINEXT_INTERNAL_HEADERS, VINEXT_MW_CTX_HEADER, VINEXT_TIMING_HEADER } from "./server/headers.js";
8
- import { buildRequestHeadersFromMiddlewareResponse } from "./server/middleware-request-headers.js";
9
7
  import { normalizePath as normalizePath$1 } from "./server/normalize-path.js";
10
- import { isExternalUrl, matchHeaders, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "./config/config-matchers.js";
8
+ import { proxyExternalRequest } from "./config/config-matchers.js";
11
9
  import { filterInternalHeaders, isOpenRedirectShaped, normalizeTrailingSlash } from "./server/request-pipeline.js";
12
10
  import { findMiddlewareFile, runMiddleware } from "./server/middleware.js";
13
11
  import { generateServerEntry } from "./entries/pages-server-entry.js";
@@ -15,9 +13,7 @@ import { generateClientEntry } from "./entries/pages-client-entry.js";
15
13
  import { appRouteGraph, appRouter, invalidateAppRouteCache } from "./routing/app-router.js";
16
14
  import { findInstrumentationClientFile, findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
17
15
  import { isUnknownRecord } from "./utils/record.js";
18
- import { mergeRewriteQuery } from "./utils/query.js";
19
16
  import { logRequest, now } from "./server/request-log.js";
20
- import { normalizeDefaultLocalePathname, stripI18nLocaleForApiRoute } from "./server/pages-i18n.js";
21
17
  import { createSSRHandler } from "./server/dev-server.js";
22
18
  import { handleApiRoute } from "./server/api-handler.js";
23
19
  import { isImageOptimizationPath } from "./server/image-optimization.js";
@@ -39,9 +35,11 @@ import { getViteMajorVersion } from "./utils/vite-version.js";
39
35
  import { createRscCompatibilityId, findNextConfigPath, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
40
36
  import { isNextDataPathname, parseNextDataPathname } from "./server/pages-data-route.js";
41
37
  import { precompressAssets } from "./build/precompress.js";
38
+ import { ensureAssetsIgnore } from "./build/assets-ignore.js";
42
39
  import { emitNextClientRuntimeManifests } from "./build/next-client-runtime-manifests.js";
43
40
  import { collectInlineCssManifest, injectInlineCssManifestGlobal } from "./build/inline-css.js";
44
41
  import { installDevStackSourcemapMiddleware } from "./server/dev-stack-sourcemap.js";
42
+ import { runPagesRequest } from "./server/pages-request-pipeline.js";
45
43
  import { manifestFilesWithBase } from "./utils/manifest-paths.js";
46
44
  import { asyncHooksStubPlugin } from "./plugins/async-hooks-stub.js";
47
45
  import { clientReferenceDedupPlugin } from "./plugins/client-reference-dedup.js";
@@ -56,16 +54,18 @@ import { generateRouteTypes } from "./typegen.js";
56
54
  import { SSR_EXTERNAL_REACT_ENTRIES, VINEXT_OPTIMIZE_DEPS_EXCLUDE, mergeOptimizeDepsExclude } from "./plugins/rsc-client-shim-excludes.js";
57
55
  import { createServerExternalsManifestPlugin } from "./plugins/server-externals-manifest.js";
58
56
  import { computeLazyChunks } from "./utils/lazy-chunks.js";
59
- import { findClientEntryFile, readClientBuildManifest } from "./utils/client-build-manifest.js";
57
+ import { findClientEntryFile, findPagesClientEntryFile, readClientBuildManifest } from "./utils/client-build-manifest.js";
58
+ import { VINEXT_CLIENT_ENTRY_MANIFEST, findClientEntryFileFromVinextManifest, findPagesClientEntryFileFromVinextManifest, readClientEntryManifest } from "./utils/client-entry-manifest.js";
60
59
  import { formatMissingCloudflarePluginError, hasWranglerConfig } from "./deploy.js";
61
60
  import { resolvePostcssStringPlugins } from "./plugins/postcss.js";
62
61
  import { buildSassPreprocessorOptions } from "./plugins/sass.js";
63
- import { createClientAssetFileNames, createClientCodeSplittingConfig, createClientManualChunks, createClientOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, withBuildBundlerOptions } from "./build/client-build-config.js";
62
+ import { createClientAssetFileNames, createClientCodeSplittingConfig, createClientManualChunks, createClientOutputConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, withBuildBundlerOptions } from "./build/client-build-config.js";
64
63
  import { markCssUrlAssetReferences, restoreDedupedCssAssetReferences } from "./build/css-url-assets.js";
65
64
  import { augmentSsrManifestFromBundle, relativeWithinRoot, tryRealpathSync } from "./build/ssr-manifest.js";
66
65
  import { stripServerExports } from "./plugins/strip-server-exports.js";
67
66
  import { removeConsoleCalls } from "./plugins/remove-console.js";
68
67
  import { createImportMetaUrlPlugin } from "./plugins/import-meta-url.js";
68
+ import { createRequireContextPlugin } from "./plugins/require-context.js";
69
69
  import { hasMdxFiles } from "./utils/mdx-scan.js";
70
70
  import { scanPublicFileRoutes } from "./utils/public-routes.js";
71
71
  import { staticExportApp, staticExportPages } from "./build/static-export.js";
@@ -306,6 +306,11 @@ const _fontGoogleShimPath = resolveShimModulePath(_shimsDir, "font-google");
306
306
  function isValidExportIdentifier(name) {
307
307
  return /^[$A-Z_a-z][$\w]*$/.test(name);
308
308
  }
309
+ function isVirtualEntryFacade(id, virtualId) {
310
+ if (!id) return false;
311
+ const cleanId = id.startsWith("\0") ? id.slice(1) : id;
312
+ return cleanId === virtualId || cleanId.endsWith("/" + virtualId) || cleanId.endsWith("\\" + virtualId);
313
+ }
309
314
  /**
310
315
  * Returns true when `code` starts with a React `"use client"` or `"use server"`
311
316
  * directive (after stripping leading comments, hashbang, and whitespace).
@@ -825,6 +830,8 @@ function vinext(options = {}) {
825
830
  const appEntries = [`${path.relative(root, appDir)}/**/*.{tsx,ts,jsx,js}`];
826
831
  const explicitInstrumentationEntries = [instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : []);
827
832
  const optimizeEntries = [...new Set([...appEntries, ...explicitInstrumentationEntries])];
833
+ const appClientInput = { index: VIRTUAL_APP_BROWSER_ENTRY };
834
+ if (hasPagesDir) appClientInput["vinext-client-entry"] = VIRTUAL_CLIENT_ENTRY;
828
835
  viteConfig.environments = {
829
836
  rsc: {
830
837
  ...hasCloudflarePlugin || hasNitroPlugin ? {} : { resolve: {
@@ -842,7 +849,10 @@ function vinext(options = {}) {
842
849
  },
843
850
  build: {
844
851
  outDir: options.rscOutDir ?? "dist/server",
845
- ...withBuildBundlerOptions(viteMajorVersion, { input: { index: VIRTUAL_RSC_ENTRY } })
852
+ ...withBuildBundlerOptions(viteMajorVersion, {
853
+ input: { index: VIRTUAL_RSC_ENTRY },
854
+ output: createRscFrameworkChunkOutputConfig(viteMajorVersion)
855
+ })
846
856
  }
847
857
  },
848
858
  ssr: {
@@ -874,10 +884,11 @@ function vinext(options = {}) {
874
884
  ])]
875
885
  },
876
886
  build: {
877
- ...hasCloudflarePlugin ? { manifest: true } : {},
887
+ ...hasCloudflarePlugin || hasPagesDir ? { manifest: true } : {},
888
+ ...hasPagesDir ? { ssrManifest: true } : {},
878
889
  assetsInlineLimit: clientAssetsInlineLimit,
879
890
  ...withBuildBundlerOptions(viteMajorVersion, {
880
- input: { index: VIRTUAL_APP_BROWSER_ENTRY },
891
+ input: appClientInput,
881
892
  output: getClientOutputConfigForVite(viteMajorVersion, clientAssetsDir),
882
893
  treeshake: getClientTreeshakeConfigForVite(viteMajorVersion)
883
894
  })
@@ -1003,10 +1014,12 @@ function vinext(options = {}) {
1003
1014
  allowedOrigins: nextConfig?.serverActionsAllowedOrigins,
1004
1015
  allowedDevOrigins: nextConfig?.allowedDevOrigins,
1005
1016
  bodySizeLimit: nextConfig?.serverActionsBodySizeLimit,
1017
+ bodySizeLimitLabel: nextConfig?.serverActionsBodySizeLimitLabel,
1006
1018
  htmlLimitedBots: nextConfig?.htmlLimitedBots,
1007
1019
  clientTraceMetadata: nextConfig?.clientTraceMetadata,
1008
1020
  assetPrefix: nextConfig?.assetPrefix,
1009
1021
  expireTime: nextConfig?.expireTime,
1022
+ reactMaxHeadersLength: nextConfig?.reactMaxHeadersLength,
1010
1023
  cacheMaxMemorySize: nextConfig?.cacheMaxMemorySize,
1011
1024
  inlineCss: nextConfig?.inlineCss,
1012
1025
  i18n: nextConfig?.i18n,
@@ -1106,6 +1119,25 @@ function vinext(options = {}) {
1106
1119
  });
1107
1120
  }
1108
1121
  },
1122
+ {
1123
+ name: "vinext:client-entry-manifest",
1124
+ apply: "build",
1125
+ generateBundle(_options, bundle) {
1126
+ if (this.environment?.name !== "client") return;
1127
+ const manifest = {};
1128
+ for (const chunk of Object.values(bundle)) {
1129
+ if (chunk.type !== "chunk" || !chunk.isEntry) continue;
1130
+ if (isVirtualEntryFacade(chunk.facadeModuleId, VIRTUAL_CLIENT_ENTRY)) manifest.pagesClientEntry = chunk.fileName;
1131
+ else if (isVirtualEntryFacade(chunk.facadeModuleId, VIRTUAL_APP_BROWSER_ENTRY)) manifest.appBrowserEntry = chunk.fileName;
1132
+ }
1133
+ if (!manifest.pagesClientEntry && !manifest.appBrowserEntry) return;
1134
+ this.emitFile({
1135
+ type: "asset",
1136
+ fileName: VINEXT_CLIENT_ENTRY_MANIFEST,
1137
+ source: JSON.stringify(manifest, null, 2) + "\n"
1138
+ });
1139
+ }
1140
+ },
1109
1141
  asyncHooksStubPlugin,
1110
1142
  createInstrumentationClientTransformPlugin(() => instrumentationClientPath),
1111
1143
  {
@@ -1381,6 +1413,10 @@ function vinext(options = {}) {
1381
1413
  res.end("Bad Request");
1382
1414
  return;
1383
1415
  }
1416
+ {
1417
+ const qs = url.includes("?") ? url.slice(url.indexOf("?")) : "";
1418
+ url = pathname + qs;
1419
+ }
1384
1420
  const bp = nextConfig?.basePath ?? "";
1385
1421
  if (bp && pathname.startsWith(bp)) {
1386
1422
  const stripped = pathname.slice(bp.length) || "/";
@@ -1421,154 +1457,110 @@ function vinext(options = {}) {
1421
1457
  for (const header of INTERNAL_HEADERS) delete req.headers[header];
1422
1458
  for (const header of VINEXT_INTERNAL_HEADERS) delete req.headers[header];
1423
1459
  const requestOrigin = `http://${req.headers.host || "localhost"}`;
1424
- const preMiddlewareReqUrl = new URL(url, requestOrigin);
1425
- const preMiddlewareReqCtx = requestContextFromRequest(new Request(preMiddlewareReqUrl, { headers: nodeRequestHeaders }));
1426
- const matchPathname = nextConfig?.i18n ? normalizeDefaultLocalePathname(pathname, nextConfig.i18n, { hostname: preMiddlewareReqUrl.hostname }) : pathname;
1427
- const matchResolvedPathname = (p) => nextConfig?.i18n ? normalizeDefaultLocalePathname(p, nextConfig.i18n, { hostname: preMiddlewareReqUrl.hostname }) : p;
1428
- if (nextConfig?.redirects.length) {
1429
- if (applyRedirects(matchPathname, res, nextConfig.redirects, preMiddlewareReqCtx, nextConfig.basePath ?? "")) return;
1430
- }
1460
+ const method = req.method ?? "GET";
1461
+ const webRequest = new Request(new URL(url, requestOrigin), {
1462
+ method,
1463
+ headers: nodeRequestHeaders
1464
+ });
1431
1465
  const applyRequestHeadersToNodeRequest = (nextRequestHeaders) => {
1432
1466
  for (const key of Object.keys(req.headers)) delete req.headers[key];
1433
1467
  for (const [key, value] of nextRequestHeaders) req.headers[key] = value;
1434
1468
  };
1435
- let middlewareRequestHeaders = null;
1436
- let deferredMwResponseHeaders = null;
1437
- const applyDeferredMwHeaders = () => {
1438
- if (deferredMwResponseHeaders) for (const [key, value] of deferredMwResponseHeaders) res.appendHeader(key, value);
1439
- };
1440
- const applyMwRequestHeadersForExternalProxy = () => {
1441
- if (middlewareRequestHeaders) applyRequestHeadersToNodeRequest(middlewareRequestHeaders);
1442
- else delete req.headers[VINEXT_MW_CTX_HEADER];
1443
- };
1444
- if (middlewarePath) {
1469
+ const capturedMiddlewarePath = middlewarePath;
1470
+ const devRunMiddlewareAdapter = capturedMiddlewarePath ? async (_request, _ctx, opts) => {
1445
1471
  const rawProto = process.env.VINEXT_TRUST_PROXY === "1" || (process.env.VINEXT_TRUSTED_HOSTS ?? "").split(",").some((h) => h.trim()) ? String(req.headers["x-forwarded-proto"] || "").split(",")[0].trim() : "";
1446
- const origin = `${rawProto === "https" || rawProto === "http" ? rawProto : "http"}://${req.headers.host || "localhost"}`;
1447
- const middlewareRequest = new Request(new URL(url, origin), {
1472
+ const mwOrigin = `${rawProto === "https" || rawProto === "http" ? rawProto : "http"}://${req.headers.host || "localhost"}`;
1473
+ const middlewareRequest = new Request(new URL(url, mwOrigin), {
1448
1474
  method: req.method,
1449
1475
  headers: nodeRequestHeaders
1450
1476
  });
1451
- const result = await runMiddleware(getPagesRunner(), middlewarePath, middlewareRequest, nextConfig?.i18n, nextConfig?.basePath, nextConfig?.trailingSlash, isDataRequest);
1452
- if (result.waitUntilPromises?.length) Promise.allSettled(result.waitUntilPromises);
1453
- if (!result.continue) {
1454
- if (result.redirectUrl) {
1455
- const redirectHeaders = { Location: result.redirectUrl };
1456
- if (result.responseHeaders) for (const [key, value] of result.responseHeaders) {
1457
- const existing = redirectHeaders[key];
1458
- if (existing === void 0) redirectHeaders[key] = value;
1459
- else if (Array.isArray(existing)) existing.push(value);
1460
- else redirectHeaders[key] = [existing, value];
1461
- }
1462
- res.writeHead(result.redirectStatus ?? 307, redirectHeaders);
1463
- res.end();
1464
- return;
1465
- }
1466
- if (result.response) {
1467
- res.statusCode = result.response.status;
1468
- for (const [key, value] of result.response.headers) res.appendHeader(key, value);
1469
- const body = Buffer.from(await result.response.arrayBuffer());
1470
- res.end(body);
1471
- return;
1472
- }
1473
- }
1474
- if (result.responseHeaders) {
1475
- const currentRequestHeaders = new Headers();
1476
- for (const [key, value] of Object.entries(req.headers)) if (Array.isArray(value)) currentRequestHeaders.set(key, value.join(", "));
1477
- else if (value !== void 0) currentRequestHeaders.set(key, value);
1478
- middlewareRequestHeaders = buildRequestHeadersFromMiddlewareResponse(currentRequestHeaders, result.responseHeaders, { preserveCredentialHeaders: Boolean(result.rewriteUrl && isExternalUrl(result.rewriteUrl)) });
1479
- if (middlewareRequestHeaders && !hasAppDir) applyRequestHeadersToNodeRequest(middlewareRequestHeaders);
1480
- if (hasAppDir) {
1481
- deferredMwResponseHeaders = [];
1482
- for (const [key, value] of result.responseHeaders) if (!key.startsWith("x-middleware-")) deferredMwResponseHeaders.push([key, value]);
1483
- } else for (const [key, value] of result.responseHeaders) if (!key.startsWith("x-middleware-")) res.appendHeader(key, value);
1484
- }
1485
- if (result.rewriteUrl) {
1486
- url = result.rewriteUrl;
1487
- req.url = url;
1488
- }
1489
- const middlewareStatus = result.status ?? result.rewriteStatus;
1490
- if (middlewareStatus !== void 0) req.__vinextMiddlewareStatus = middlewareStatus;
1491
- if (hasAppDir) {
1477
+ const result = await runMiddleware(getPagesRunner(), capturedMiddlewarePath, middlewareRequest, nextConfig?.i18n, nextConfig?.basePath, nextConfig?.trailingSlash, opts.isDataRequest);
1478
+ if (hasAppDir && result.continue) {
1492
1479
  const mwCtxEntries = [];
1493
1480
  if (result.responseHeaders) {
1494
1481
  for (const [key, value] of result.responseHeaders) if (key !== "x-middleware-next" && key !== "x-middleware-rewrite") mwCtxEntries.push([key, value]);
1495
1482
  }
1483
+ const mwStatus = result.status ?? result.rewriteStatus;
1496
1484
  req.headers[VINEXT_MW_CTX_HEADER] = JSON.stringify({
1497
1485
  h: mwCtxEntries,
1498
- s: middlewareStatus ?? null,
1486
+ s: mwStatus ?? null,
1499
1487
  r: result.rewriteUrl ?? null
1500
1488
  });
1501
1489
  }
1502
- }
1503
- const reqUrl = new URL(url, requestOrigin);
1504
- const reqCtx = requestContextFromRequest(new Request(reqUrl, { headers: middlewareRequestHeaders ?? nodeRequestHeaders }));
1505
- if (nextConfig?.headers.length) applyHeaders(matchPathname, res, nextConfig.headers, preMiddlewareReqCtx, bp);
1506
- let resolvedUrl = url;
1507
- if (nextConfig?.rewrites.beforeFiles.length) {
1508
- const rewritten = applyRewrites(matchPathname, nextConfig.rewrites.beforeFiles, reqCtx, bp);
1509
- if (rewritten) resolvedUrl = mergeRewriteQuery(url, rewritten);
1510
- }
1511
- if (isExternalUrl(resolvedUrl)) {
1512
- applyDeferredMwHeaders();
1513
- applyMwRequestHeadersForExternalProxy();
1514
- await proxyExternalRewriteNode(req, res, resolvedUrl);
1490
+ return result;
1491
+ } : null;
1492
+ const devPageRoutes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
1493
+ const pipelineResult = await runPagesRequest(webRequest, {
1494
+ basePath: bp,
1495
+ trailingSlash: nextConfig?.trailingSlash ?? false,
1496
+ i18nConfig: nextConfig?.i18n ?? null,
1497
+ configRedirects: nextConfig?.redirects ?? [],
1498
+ configRewrites: nextConfig?.rewrites ?? {
1499
+ beforeFiles: [],
1500
+ afterFiles: [],
1501
+ fallback: []
1502
+ },
1503
+ configHeaders: nextConfig?.headers ?? [],
1504
+ hadBasePath: true,
1505
+ isDataReq,
1506
+ isDataRequest,
1507
+ rawSearch: url.includes("?") ? url.slice(url.indexOf("?")) : "",
1508
+ runMiddleware: devRunMiddlewareAdapter,
1509
+ matchPageRoute: (resolvedPathname) => {
1510
+ const m = matchRoute(resolvedPathname, devPageRoutes);
1511
+ return m ? { route: { isDynamic: m.route.isDynamic } } : null;
1512
+ },
1513
+ proxyExternal: async (currentRequest, externalUrl) => {
1514
+ const externalMethod = req.method ?? "GET";
1515
+ const hasBody = externalMethod !== "GET" && externalMethod !== "HEAD";
1516
+ const externalInit = {
1517
+ method: externalMethod,
1518
+ headers: currentRequest.headers
1519
+ };
1520
+ if (hasBody) {
1521
+ const { Readable } = await import("node:stream");
1522
+ externalInit.body = Readable.toWeb(req);
1523
+ externalInit.duplex = "half";
1524
+ }
1525
+ return proxyExternalRequest(new Request(new URL(url, requestOrigin), externalInit), externalUrl);
1526
+ }
1527
+ });
1528
+ if (pipelineResult.type === "response") {
1529
+ await writeWebResponseToNodeRes(res, pipelineResult.response);
1515
1530
  return;
1516
1531
  }
1517
- const apiLookupUrl = stripI18nLocaleForApiRoute(resolvedUrl, nextConfig?.i18n);
1518
- const resolvedPathname = apiLookupUrl.split("?")[0];
1519
- if (resolvedPathname.startsWith("/api/") || resolvedPathname === "/api") {
1532
+ if (pipelineResult.type === "next") return next();
1533
+ if (pipelineResult.type === "handled") return;
1534
+ const flushStagedHeaders = () => {
1535
+ for (const [key, value] of Object.entries(pipelineResult.stagedHeaders)) if (Array.isArray(value)) for (const v of value) res.appendHeader(key, v);
1536
+ else res.appendHeader(key, value);
1537
+ };
1538
+ const flushRequestHeaders = () => {
1539
+ applyRequestHeadersToNodeRequest(pipelineResult.requestHeaders);
1540
+ };
1541
+ if (pipelineResult.type === "api") {
1520
1542
  const apiRoutes = await apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
1521
- if (matchRoute(apiLookupUrl, apiRoutes)) {
1522
- applyDeferredMwHeaders();
1523
- if (middlewareRequestHeaders) applyRequestHeadersToNodeRequest(middlewareRequestHeaders);
1543
+ if (matchRoute(pipelineResult.apiUrl, apiRoutes)) {
1544
+ flushStagedHeaders();
1545
+ flushRequestHeaders();
1546
+ if (pipelineResult.middlewareStatus !== void 0) req.__vinextMiddlewareStatus = pipelineResult.middlewareStatus;
1524
1547
  }
1525
- if (await handleApiRoute(getPagesRunner(), req, res, apiLookupUrl, apiRoutes)) return;
1548
+ if (await handleApiRoute(getPagesRunner(), req, res, pipelineResult.apiUrl, apiRoutes)) return;
1526
1549
  if (hasAppDir) return next();
1527
1550
  res.statusCode = 404;
1528
1551
  res.end("404 - API route not found");
1529
1552
  return;
1530
1553
  }
1531
- const routes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
1532
- let match = matchRoute(resolvedUrl.split("?")[0], routes);
1533
- if ((!match || match.route.isDynamic) && nextConfig?.rewrites.afterFiles.length) {
1534
- const afterRewrite = applyRewrites(matchResolvedPathname(resolvedUrl.split("?")[0]), nextConfig.rewrites.afterFiles, reqCtx, bp);
1535
- if (afterRewrite) {
1536
- resolvedUrl = mergeRewriteQuery(resolvedUrl, afterRewrite);
1537
- match = matchRoute(resolvedUrl.split("?")[0], routes);
1538
- }
1539
- }
1540
- if (isExternalUrl(resolvedUrl)) {
1541
- applyDeferredMwHeaders();
1542
- applyMwRequestHeadersForExternalProxy();
1543
- await proxyExternalRewriteNode(req, res, resolvedUrl);
1544
- return;
1545
- }
1546
- const handler = createSSRHandler(server, getPagesRunner(), routes, pagesDir, nextConfig?.i18n, fileMatcher, nextConfig?.basePath ?? "", nextConfig?.trailingSlash ?? false, middlewarePath !== null, nextConfig?.clientTraceMetadata);
1547
- const mwStatus = req.__vinextMiddlewareStatus;
1548
- if (match) {
1549
- applyDeferredMwHeaders();
1550
- if (middlewareRequestHeaders) applyRequestHeadersToNodeRequest(middlewareRequestHeaders);
1551
- await handler(req, res, resolvedUrl, mwStatus, isDataReq);
1552
- return;
1553
- }
1554
- if (nextConfig?.rewrites.fallback.length) {
1555
- const fallbackRewrite = applyRewrites(matchResolvedPathname(resolvedUrl.split("?")[0]), nextConfig.rewrites.fallback, reqCtx, bp);
1556
- if (fallbackRewrite) {
1557
- if (isExternalUrl(fallbackRewrite)) {
1558
- applyDeferredMwHeaders();
1559
- applyMwRequestHeadersForExternalProxy();
1560
- await proxyExternalRewriteNode(req, res, fallbackRewrite);
1561
- return;
1562
- }
1563
- if (!matchRoute(fallbackRewrite.split("?")[0], routes) && hasAppDir) return next();
1564
- applyDeferredMwHeaders();
1565
- if (middlewareRequestHeaders) applyRequestHeadersToNodeRequest(middlewareRequestHeaders);
1566
- await handler(req, res, fallbackRewrite, mwStatus, isDataReq);
1567
- return;
1568
- }
1554
+ {
1555
+ const routes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
1556
+ if (!matchRoute(pipelineResult.resolvedUrl.split("?")[0], routes) && hasAppDir) return next();
1557
+ const handler = createSSRHandler(server, getPagesRunner(), routes, pagesDir, nextConfig?.i18n, fileMatcher, nextConfig?.basePath ?? "", nextConfig?.trailingSlash ?? false, middlewarePath !== null, (nextConfig?.rewrites.beforeFiles.length ?? 0) > 0 || (nextConfig?.rewrites.afterFiles.length ?? 0) > 0 || (nextConfig?.rewrites.fallback.length ?? 0) > 0, nextConfig?.clientTraceMetadata);
1558
+ flushStagedHeaders();
1559
+ flushRequestHeaders();
1560
+ if (pipelineResult.middlewareStatus !== void 0) req.__vinextMiddlewareStatus = pipelineResult.middlewareStatus;
1561
+ req.url = pipelineResult.resolvedUrl;
1562
+ await handler(req, res, pipelineResult.resolvedUrl, req.__vinextMiddlewareStatus, pipelineResult.isDataReq);
1569
1563
  }
1570
- if (hasAppDir) return next();
1571
- await handler(req, res, resolvedUrl, mwStatus, isDataReq);
1572
1564
  } catch (e) {
1573
1565
  next(e);
1574
1566
  }
@@ -1635,9 +1627,12 @@ function vinext(options = {}) {
1635
1627
  {
1636
1628
  name: "vinext:compiler-define-server",
1637
1629
  configEnvironment(name) {
1638
- if (Object.keys(nextConfig.compilerDefineServer).length === 0) return null;
1639
1630
  if (name === "client") return null;
1640
- return { define: { ...nextConfig.compilerDefineServer } };
1631
+ const serverDefines = { ...nextConfig.compilerDefineServer };
1632
+ const sharedRevalidateSecret = process.env.__VINEXT_SHARED_REVALIDATE_SECRET;
1633
+ if (sharedRevalidateSecret) serverDefines["process.env.__VINEXT_REVALIDATE_SECRET"] = JSON.stringify(sharedRevalidateSecret);
1634
+ if (Object.keys(serverDefines).length === 0) return null;
1635
+ return { define: serverDefines };
1641
1636
  }
1642
1637
  },
1643
1638
  {
@@ -1830,6 +1825,7 @@ function vinext(options = {}) {
1830
1825
  }
1831
1826
  },
1832
1827
  createImportMetaUrlPlugin({ getRoot: () => root }),
1828
+ createRequireContextPlugin(),
1833
1829
  createOgInlineFetchAssetsPlugin(),
1834
1830
  createOgAssetsPlugin(),
1835
1831
  createServerExternalsManifestPlugin(),
@@ -2064,9 +2060,11 @@ function vinext(options = {}) {
2064
2060
  const clientBase = envConfig.base ?? "/";
2065
2061
  let lazyChunksData = null;
2066
2062
  let clientEntryFile = null;
2063
+ const clientEntryManifest = readClientEntryManifest(clientDir);
2064
+ clientEntryFile = (hasAppDir && hasPagesDir ? findPagesClientEntryFileFromVinextManifest : findClientEntryFileFromVinextManifest)(clientEntryManifest, clientBase) ?? null;
2067
2065
  const buildManifest = readClientBuildManifest(path.join(clientDir, ".vite", "manifest.json"));
2068
2066
  if (buildManifest) {
2069
- clientEntryFile = findClientEntryFile({
2067
+ if (!clientEntryFile) clientEntryFile = (hasAppDir && hasPagesDir ? findPagesClientEntryFile : findClientEntryFile)({
2070
2068
  buildManifest,
2071
2069
  clientDir,
2072
2070
  assetsSubdir: resolveAssetsDir(nextConfig?.assetPrefix),
@@ -2082,9 +2080,15 @@ function vinext(options = {}) {
2082
2080
  } catch {}
2083
2081
  if (hasAppDir) {
2084
2082
  const workerEntry = path.resolve(distDir, "server", "index.js");
2085
- if (fs.existsSync(workerEntry) && (lazyChunksData || ssrManifestData)) {
2083
+ if (!clientEntryFile && hasPagesDir) clientEntryFile = findPagesClientEntryFile({
2084
+ clientDir,
2085
+ assetsSubdir: resolveAssetsDir(nextConfig?.assetPrefix),
2086
+ assetBase: clientBase
2087
+ }) ?? null;
2088
+ if (fs.existsSync(workerEntry) && (lazyChunksData || ssrManifestData || hasPagesDir && clientEntryFile)) {
2086
2089
  let code = fs.readFileSync(workerEntry, "utf-8");
2087
2090
  const globals = [];
2091
+ if (hasPagesDir && clientEntryFile) globals.push(`globalThis.__VINEXT_CLIENT_ENTRY__ = ${JSON.stringify(clientEntryFile)};`);
2088
2092
  if (ssrManifestData) globals.push(`globalThis.__VINEXT_SSR_MANIFEST__ = ${JSON.stringify(ssrManifestData)};`);
2089
2093
  if (lazyChunksData) globals.push(`globalThis.__VINEXT_LAZY_CHUNKS__ = ${JSON.stringify(lazyChunksData)};`);
2090
2094
  code = globals.join("\n") + "\n" + code;
@@ -2129,6 +2133,7 @@ function vinext(options = {}) {
2129
2133
  fs.mkdirSync(clientDir, { recursive: true });
2130
2134
  fs.writeFileSync(headersPath, headersContent);
2131
2135
  }
2136
+ ensureAssetsIgnore(clientDir);
2132
2137
  }
2133
2138
  }
2134
2139
  },
@@ -2202,91 +2207,31 @@ function getNextPublicEnvDefines() {
2202
2207
  return defines;
2203
2208
  }
2204
2209
  /**
2205
- * Apply redirect rules from next.config.js.
2206
- * Returns true if a redirect was applied.
2210
+ * Write a Web API Response to a Node.js ServerResponse.
2211
+ * Handles multi-value headers (Set-Cookie) correctly.
2207
2212
  */
2208
- function applyRedirects(pathname, res, redirects, ctx, basePath = "") {
2209
- const result = matchRedirect(pathname, redirects, ctx, {
2210
- basePath,
2211
- hadBasePath: true
2213
+ async function writeWebResponseToNodeRes(res, response) {
2214
+ const nodeHeaders = {};
2215
+ response.headers.forEach((value, key) => {
2216
+ if (key === "set-cookie") return;
2217
+ const existing = nodeHeaders[key];
2218
+ if (existing !== void 0) nodeHeaders[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
2219
+ else nodeHeaders[key] = value;
2212
2220
  });
2213
- if (result) {
2214
- const dest = sanitizeDestination(basePath && !isExternalUrl(result.destination) && !hasBasePath(result.destination, basePath) ? basePath + result.destination : result.destination);
2215
- res.writeHead(result.permanent ? 308 : 307, { Location: dest });
2216
- res.end();
2217
- return true;
2218
- }
2219
- return false;
2220
- }
2221
- async function proxyExternalRewriteNode(req, res, externalUrl) {
2222
- try {
2223
- const origin = `http://${req.headers.host || "localhost"}`;
2224
- const method = req.method ?? "GET";
2225
- const hasBody = method !== "GET" && method !== "HEAD";
2226
- const init = {
2227
- method,
2228
- headers: Object.fromEntries(Object.entries(req.headers).filter(([, v]) => v !== void 0).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)]))
2229
- };
2230
- if (hasBody) {
2231
- const { Readable } = await import("node:stream");
2232
- init.body = Readable.toWeb(req);
2233
- init.duplex = "half";
2234
- }
2235
- const proxyResponse = await proxyExternalRequest(new Request(new URL(req.url ?? "/", origin), init), externalUrl);
2236
- const nodeHeaders = {};
2237
- proxyResponse.headers.forEach((value, key) => {
2238
- const existing = nodeHeaders[key];
2239
- if (existing !== void 0) nodeHeaders[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
2240
- else nodeHeaders[key] = value;
2221
+ const cookies = response.headers.getSetCookie?.() ?? [];
2222
+ if (cookies.length > 0) nodeHeaders["set-cookie"] = cookies;
2223
+ if (response.statusText) res.writeHead(response.status, response.statusText, nodeHeaders);
2224
+ else res.writeHead(response.status, nodeHeaders);
2225
+ if (response.body) {
2226
+ const { Readable } = await import("node:stream");
2227
+ const nodeStream = Readable.fromWeb(response.body);
2228
+ await new Promise((resolve, reject) => {
2229
+ nodeStream.on("error", reject);
2230
+ res.on("error", reject);
2231
+ nodeStream.pipe(res);
2232
+ nodeStream.on("end", resolve);
2241
2233
  });
2242
- res.writeHead(proxyResponse.status, nodeHeaders);
2243
- if (proxyResponse.body) {
2244
- const { Readable: ReadableImport } = await import("node:stream");
2245
- ReadableImport.fromWeb(proxyResponse.body).pipe(res);
2246
- } else res.end();
2247
- } catch (e) {
2248
- console.error("[vinext] External rewrite proxy error:", e);
2249
- if (!res.headersSent) {
2250
- res.writeHead(502);
2251
- res.end("Bad Gateway");
2252
- }
2253
- }
2254
- }
2255
- /**
2256
- * Apply rewrite rules from next.config.js.
2257
- * Returns the rewritten URL or null if no rewrite matched.
2258
- */
2259
- function applyRewrites(pathname, rewrites, ctx, basePath = "") {
2260
- const dest = matchRewrite(pathname, rewrites, ctx, {
2261
- basePath,
2262
- hadBasePath: true
2263
- });
2264
- if (dest) return sanitizeDestination(dest);
2265
- return null;
2266
- }
2267
- /**
2268
- * Apply custom header rules from next.config.js.
2269
- * Middleware headers take precedence: if a header key was already set on the
2270
- * response (by middleware), the config value is skipped for that key.
2271
- */
2272
- function applyHeaders(pathname, res, headers, ctx, basePath = "") {
2273
- const matched = matchHeaders(pathname, headers, ctx, {
2274
- basePath,
2275
- hadBasePath: true
2276
- });
2277
- for (const header of matched) {
2278
- const lk = header.key.toLowerCase();
2279
- if (lk === "set-cookie") {
2280
- const existing = res.getHeader(lk);
2281
- if (Array.isArray(existing)) res.setHeader(header.key, [...existing, header.value]);
2282
- else if (existing) res.setHeader(header.key, [String(existing), header.value]);
2283
- else res.setHeader(header.key, header.value);
2284
- } else if (lk === "vary") {
2285
- const existing = res.getHeader(lk);
2286
- if (existing) res.setHeader(header.key, existing + ", " + header.value);
2287
- else res.setHeader(header.key, header.value);
2288
- } else if (!res.getHeader(lk)) res.setHeader(header.key, header.value);
2289
- }
2234
+ } else res.end();
2290
2235
  }
2291
2236
  //#endregion
2292
2237
  export { vinext as default, staticExportApp, staticExportPages };
@@ -73,20 +73,24 @@ async function resolvePostcssStringPluginsUncached(projectRoot) {
73
73
  if (!config || !Array.isArray(config.plugins)) return;
74
74
  if (!config.plugins.some((p) => typeof p === "string" || Array.isArray(p) && typeof p[0] === "string")) return;
75
75
  const req = createRequire(path.join(projectRoot, "package.json"));
76
- return { plugins: await Promise.all(config.plugins.filter(Boolean).map(async (plugin) => {
77
- if (typeof plugin === "string") {
78
- const mod = await import(pathToFileURL(req.resolve(plugin)).href);
79
- const fn = mod.default ?? mod;
80
- return typeof fn === "function" ? fn() : fn;
81
- }
82
- if (Array.isArray(plugin) && typeof plugin[0] === "string") {
83
- const [name, options] = plugin;
84
- const mod = await import(pathToFileURL(req.resolve(name)).href);
85
- const fn = mod.default ?? mod;
86
- return typeof fn === "function" ? fn(options) : fn;
87
- }
88
- return plugin;
89
- })) };
76
+ try {
77
+ return { plugins: await Promise.all(config.plugins.filter(Boolean).map(async (plugin) => {
78
+ if (typeof plugin === "string") {
79
+ const mod = await import(pathToFileURL(req.resolve(plugin)).href);
80
+ const fn = mod.default ?? mod;
81
+ return typeof fn === "function" ? fn() : fn;
82
+ }
83
+ if (Array.isArray(plugin) && typeof plugin[0] === "string") {
84
+ const [name, options] = plugin;
85
+ const mod = await import(pathToFileURL(req.resolve(name)).href);
86
+ const fn = mod.default ?? mod;
87
+ return typeof fn === "function" ? fn(options) : fn;
88
+ }
89
+ return plugin;
90
+ })) };
91
+ } catch {
92
+ return;
93
+ }
90
94
  }
91
95
  //#endregion
92
96
  export { postcssCache, resolvePostcssStringPlugins };
@@ -0,0 +1,6 @@
1
+ import { Plugin } from "vite";
2
+
3
+ //#region src/plugins/require-context.d.ts
4
+ declare function createRequireContextPlugin(): Plugin;
5
+ //#endregion
6
+ export { createRequireContextPlugin };