vinext 0.0.27 → 0.0.28

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 (114) hide show
  1. package/dist/build/static-export.d.ts +1 -1
  2. package/dist/build/static-export.d.ts.map +1 -1
  3. package/dist/build/static-export.js +2 -1
  4. package/dist/build/static-export.js.map +1 -1
  5. package/dist/cloudflare/kv-cache-handler.d.ts +28 -17
  6. package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
  7. package/dist/cloudflare/kv-cache-handler.js +95 -30
  8. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  9. package/dist/config/config-matchers.d.ts +1 -0
  10. package/dist/config/config-matchers.d.ts.map +1 -1
  11. package/dist/config/config-matchers.js +51 -23
  12. package/dist/config/config-matchers.js.map +1 -1
  13. package/dist/deploy.d.ts +1 -1
  14. package/dist/deploy.d.ts.map +1 -1
  15. package/dist/deploy.js +48 -32
  16. package/dist/deploy.js.map +1 -1
  17. package/dist/entries/app-rsc-entry.d.ts +3 -1
  18. package/dist/entries/app-rsc-entry.d.ts.map +1 -1
  19. package/dist/entries/app-rsc-entry.js +495 -75
  20. package/dist/entries/app-rsc-entry.js.map +1 -1
  21. package/dist/entries/pages-server-entry.d.ts.map +1 -1
  22. package/dist/entries/pages-server-entry.js +68 -22
  23. package/dist/entries/pages-server-entry.js.map +1 -1
  24. package/dist/index.d.ts +23 -7
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +128 -41
  27. package/dist/index.js.map +1 -1
  28. package/dist/plugins/client-reference-dedup.d.ts +19 -0
  29. package/dist/plugins/client-reference-dedup.d.ts.map +1 -0
  30. package/dist/plugins/client-reference-dedup.js +96 -0
  31. package/dist/plugins/client-reference-dedup.js.map +1 -0
  32. package/dist/routing/app-router.d.ts.map +1 -1
  33. package/dist/routing/app-router.js +60 -89
  34. package/dist/routing/app-router.js.map +1 -1
  35. package/dist/routing/pages-router.d.ts +1 -1
  36. package/dist/routing/pages-router.d.ts.map +1 -1
  37. package/dist/routing/pages-router.js +25 -13
  38. package/dist/routing/pages-router.js.map +1 -1
  39. package/dist/routing/route-validation.d.ts +8 -0
  40. package/dist/routing/route-validation.d.ts.map +1 -0
  41. package/dist/routing/route-validation.js +124 -0
  42. package/dist/routing/route-validation.js.map +1 -0
  43. package/dist/server/api-handler.d.ts.map +1 -1
  44. package/dist/server/api-handler.js +24 -7
  45. package/dist/server/api-handler.js.map +1 -1
  46. package/dist/server/dev-server.d.ts.map +1 -1
  47. package/dist/server/dev-server.js +9 -3
  48. package/dist/server/dev-server.js.map +1 -1
  49. package/dist/server/isr-cache.d.ts +5 -13
  50. package/dist/server/isr-cache.d.ts.map +1 -1
  51. package/dist/server/isr-cache.js +13 -12
  52. package/dist/server/isr-cache.js.map +1 -1
  53. package/dist/server/metadata-routes.d.ts +8 -2
  54. package/dist/server/metadata-routes.d.ts.map +1 -1
  55. package/dist/server/metadata-routes.js +73 -28
  56. package/dist/server/metadata-routes.js.map +1 -1
  57. package/dist/server/middleware-codegen.d.ts +1 -1
  58. package/dist/server/middleware-codegen.d.ts.map +1 -1
  59. package/dist/server/middleware-codegen.js +165 -12
  60. package/dist/server/middleware-codegen.js.map +1 -1
  61. package/dist/server/middleware.d.ts +9 -8
  62. package/dist/server/middleware.d.ts.map +1 -1
  63. package/dist/server/middleware.js +74 -13
  64. package/dist/server/middleware.js.map +1 -1
  65. package/dist/server/prod-server.d.ts.map +1 -1
  66. package/dist/server/prod-server.js +84 -54
  67. package/dist/server/prod-server.js.map +1 -1
  68. package/dist/shims/cache.d.ts +2 -0
  69. package/dist/shims/cache.d.ts.map +1 -1
  70. package/dist/shims/cache.js +20 -8
  71. package/dist/shims/cache.js.map +1 -1
  72. package/dist/shims/fetch-cache.d.ts.map +1 -1
  73. package/dist/shims/fetch-cache.js +5 -2
  74. package/dist/shims/fetch-cache.js.map +1 -1
  75. package/dist/shims/form.d.ts.map +1 -1
  76. package/dist/shims/form.js +103 -8
  77. package/dist/shims/form.js.map +1 -1
  78. package/dist/shims/headers.d.ts +11 -3
  79. package/dist/shims/headers.d.ts.map +1 -1
  80. package/dist/shims/headers.js +180 -25
  81. package/dist/shims/headers.js.map +1 -1
  82. package/dist/shims/internal/parse-cookie-header.d.ts +12 -0
  83. package/dist/shims/internal/parse-cookie-header.d.ts.map +1 -0
  84. package/dist/shims/internal/parse-cookie-header.js +32 -0
  85. package/dist/shims/internal/parse-cookie-header.js.map +1 -0
  86. package/dist/shims/link.d.ts +2 -1
  87. package/dist/shims/link.d.ts.map +1 -1
  88. package/dist/shims/link.js +8 -2
  89. package/dist/shims/link.js.map +1 -1
  90. package/dist/shims/navigation.d.ts +3 -7
  91. package/dist/shims/navigation.d.ts.map +1 -1
  92. package/dist/shims/navigation.js +20 -10
  93. package/dist/shims/navigation.js.map +1 -1
  94. package/dist/shims/readonly-url-search-params.d.ts +11 -0
  95. package/dist/shims/readonly-url-search-params.d.ts.map +1 -0
  96. package/dist/shims/readonly-url-search-params.js +24 -0
  97. package/dist/shims/readonly-url-search-params.js.map +1 -0
  98. package/dist/shims/router.d.ts +4 -3
  99. package/dist/shims/router.d.ts.map +1 -1
  100. package/dist/shims/router.js +42 -29
  101. package/dist/shims/router.js.map +1 -1
  102. package/dist/shims/server.d.ts +1 -1
  103. package/dist/shims/server.d.ts.map +1 -1
  104. package/dist/shims/server.js +7 -13
  105. package/dist/shims/server.js.map +1 -1
  106. package/dist/utils/manifest-paths.d.ts +4 -0
  107. package/dist/utils/manifest-paths.d.ts.map +1 -0
  108. package/dist/utils/manifest-paths.js +20 -0
  109. package/dist/utils/manifest-paths.js.map +1 -0
  110. package/dist/utils/query.d.ts +9 -0
  111. package/dist/utils/query.d.ts.map +1 -1
  112. package/dist/utils/query.js +59 -9
  113. package/dist/utils/query.js.map +1 -1
  114. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21,8 +21,10 @@ import { isExternalUrl, proxyExternalRequest, matchHeaders, matchRedirect, match
21
21
  import { scanMetadataFiles } from "./server/metadata-routes.js";
22
22
  import { buildRequestHeadersFromMiddlewareResponse } from "./server/middleware-request-headers.js";
23
23
  import { detectPackageManager } from "./utils/project.js";
24
+ import { manifestFileWithBase, manifestFilesWithBase, normalizeManifestFile, } from "./utils/manifest-paths.js";
24
25
  import { hasBasePath } from "./utils/base-path.js";
25
26
  import { asyncHooksStubPlugin } from "./plugins/async-hooks-stub.js";
27
+ import { clientReferenceDedupPlugin } from "./plugins/client-reference-dedup.js";
26
28
  import { hasWranglerConfig, formatMissingCloudflarePluginError } from "./deploy.js";
27
29
  import tsconfigPaths from "vite-tsconfig-paths";
28
30
  import react from "@vitejs/plugin-react";
@@ -502,6 +504,57 @@ function computeLazyChunks(buildManifest) {
502
504
  }
503
505
  return lazyChunks;
504
506
  }
507
+ function normalizeManifestModuleId(moduleId, root) {
508
+ const normalizedId = moduleId.replace(/\\/g, "/");
509
+ const isWindowsAbsolute = /^[a-zA-Z]:[\\/]/.test(moduleId) || moduleId.startsWith("\\\\");
510
+ if (isWindowsAbsolute) {
511
+ const relativeId = path.win32.relative(root, moduleId).replace(/\\/g, "/");
512
+ if (!relativeId || relativeId.startsWith("../"))
513
+ return normalizedId;
514
+ return relativeId;
515
+ }
516
+ if (!path.isAbsolute(moduleId))
517
+ return normalizedId;
518
+ const relativeId = path.relative(root, moduleId).replace(/\\/g, "/");
519
+ if (!relativeId || relativeId.startsWith("../"))
520
+ return normalizedId;
521
+ return relativeId;
522
+ }
523
+ function augmentSsrManifestFromBundle(ssrManifest, bundle, root, base = "/") {
524
+ const nextManifest = Object.fromEntries(Object.entries(ssrManifest).map(([key, files]) => [
525
+ key,
526
+ new Set(files.map((file) => normalizeManifestFile(file))),
527
+ ]));
528
+ for (const item of Object.values(bundle)) {
529
+ if (item.type !== "chunk")
530
+ continue;
531
+ const chunk = item;
532
+ const files = new Set();
533
+ files.add(manifestFileWithBase(chunk.fileName, base));
534
+ for (const importedFile of chunk.imports ?? []) {
535
+ files.add(manifestFileWithBase(importedFile, base));
536
+ }
537
+ for (const cssFile of chunk.viteMetadata?.importedCss ?? []) {
538
+ files.add(manifestFileWithBase(cssFile, base));
539
+ }
540
+ for (const assetFile of chunk.viteMetadata?.importedAssets ?? []) {
541
+ files.add(manifestFileWithBase(assetFile, base));
542
+ }
543
+ for (const moduleId of Object.keys(chunk.modules ?? {})) {
544
+ const key = normalizeManifestModuleId(moduleId, root);
545
+ if (key.startsWith("node_modules/") || key.includes("/node_modules/"))
546
+ continue;
547
+ if (key.startsWith("\0"))
548
+ continue;
549
+ if (!nextManifest[key])
550
+ nextManifest[key] = new Set();
551
+ for (const file of files) {
552
+ nextManifest[key].add(file);
553
+ }
554
+ }
555
+ }
556
+ return Object.fromEntries(Object.entries(nextManifest).map(([key, files]) => [key, [...files]]));
557
+ }
505
558
  export default function vinext(options = {}) {
506
559
  let root;
507
560
  let pagesDir;
@@ -711,6 +764,8 @@ export default function vinext(options = {}) {
711
764
  defines["process.env.__VINEXT_DRAFT_SECRET"] = JSON.stringify(crypto.randomUUID());
712
765
  // Build ID — resolved from next.config generateBuildId() or random UUID.
713
766
  // Exposed so server entries and the next/server shim can inject it.
767
+ // Also used to namespace ISR cache keys so old cached entries from a
768
+ // previous deploy are never served by the new one.
714
769
  defines["process.env.__VINEXT_BUILD_ID"] = JSON.stringify(nextConfig.buildId);
715
770
  // Build the shim alias map — used by both resolve.alias and resolveId
716
771
  // (resolveId handles .js extension variants for libraries like nuqs)
@@ -1205,6 +1260,7 @@ export default function vinext(options = {}) {
1205
1260
  allowedOrigins: nextConfig?.serverActionsAllowedOrigins,
1206
1261
  allowedDevOrigins: nextConfig?.allowedDevOrigins,
1207
1262
  bodySizeLimit: nextConfig?.serverActionsBodySizeLimit,
1263
+ i18n: nextConfig?.i18n,
1208
1264
  }, instrumentationPath);
1209
1265
  }
1210
1266
  if (id === RESOLVED_APP_SSR_ENTRY && hasAppDir) {
@@ -1217,6 +1273,8 @@ export default function vinext(options = {}) {
1217
1273
  },
1218
1274
  // Stub node:async_hooks in client builds — see src/plugins/async-hooks-stub.ts
1219
1275
  asyncHooksStubPlugin,
1276
+ // Dedup client references from RSC proxy modules — see src/plugins/client-reference-dedup.ts
1277
+ clientReferenceDedupPlugin(),
1220
1278
  // Proxy plugin for @mdx-js/rollup. The real MDX plugin is created lazily
1221
1279
  // during vinext:config's config() (when MDX files are detected), but
1222
1280
  // plugins returned from config() hooks run too late in the pipeline —
@@ -1685,6 +1743,30 @@ export default function vinext(options = {}) {
1685
1743
  return;
1686
1744
  }
1687
1745
  }
1746
+ // When @cloudflare/vite-plugin is present, delegate the entire
1747
+ // Pages Router request pipeline to the Worker/miniflare side.
1748
+ // That keeps middleware, headers, redirects, rewrites, API
1749
+ // routes, and rendering in one place instead of mutating the
1750
+ // host request and forwarding post-middleware state downstream.
1751
+ if (hasCloudflarePlugin)
1752
+ return next();
1753
+ // Snapshot of req.headers before middleware runs. Used for both
1754
+ // preMiddlewareReqCtx and the middleware Request itself. Intentionally
1755
+ // captured once here — applyRequestHeadersToNodeRequest() mutates
1756
+ // req.headers later, but by then this Headers object is no longer read.
1757
+ const nodeRequestHeaders = new Headers(Object.fromEntries(Object.entries(req.headers)
1758
+ .filter(([, v]) => v !== undefined)
1759
+ .map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
1760
+ const requestOrigin = `http://${req.headers.host || "localhost"}`;
1761
+ const preMiddlewareReqUrl = new URL(url, requestOrigin);
1762
+ const preMiddlewareReqCtx = requestContextFromRequest(new Request(preMiddlewareReqUrl, { headers: nodeRequestHeaders }));
1763
+ // Config redirects run before middleware, but still match against
1764
+ // the original normalized pathname and request headers/cookies.
1765
+ if (nextConfig?.redirects.length) {
1766
+ const redirected = applyRedirects(pathname, res, nextConfig.redirects, preMiddlewareReqCtx, nextConfig.basePath ?? "");
1767
+ if (redirected)
1768
+ return;
1769
+ }
1688
1770
  const applyRequestHeadersToNodeRequest = (nextRequestHeaders) => {
1689
1771
  for (const key of Object.keys(req.headers)) {
1690
1772
  delete req.headers[key];
@@ -1708,11 +1790,9 @@ export default function vinext(options = {}) {
1708
1790
  const origin = `${mwProto}://${req.headers.host || "localhost"}`;
1709
1791
  const middlewareRequest = new Request(new URL(url, origin), {
1710
1792
  method: req.method,
1711
- headers: Object.fromEntries(Object.entries(req.headers)
1712
- .filter(([, v]) => v !== undefined)
1713
- .map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])),
1793
+ headers: nodeRequestHeaders,
1714
1794
  });
1715
- const result = await runMiddleware(getPagesRunner(), middlewarePath, middlewareRequest);
1795
+ const result = await runMiddleware(getPagesRunner(), middlewarePath, middlewareRequest, nextConfig?.i18n);
1716
1796
  if (!result.continue) {
1717
1797
  if (result.redirectUrl) {
1718
1798
  const redirectHeaders = {
@@ -1787,46 +1867,19 @@ export default function vinext(options = {}) {
1787
1867
  req.__vinextRewriteStatus = result.rewriteStatus;
1788
1868
  }
1789
1869
  }
1790
- // ── Cloudflare Workers dev mode ────────────────────────────
1791
- // When @cloudflare/vite-plugin is present, ALL rendering runs
1792
- // inside the miniflare Worker subprocess — both App Router (via
1793
- // virtual:vinext-rsc-entry) and Pages Router (via
1794
- // virtual:vinext-server-entry → renderPage/handleApiRoute).
1795
- //
1796
- // The Worker entry already handles config redirects, rewrites,
1797
- // headers, and all routing internally. Running them here too
1798
- // would duplicate that logic and produce incorrect behaviour
1799
- // (double redirects, headers set on the wrong object, etc.).
1800
- //
1801
- // Middleware.ts is the only thing that belongs in the host connect
1802
- // handler — it has already run above. Any terminal middleware
1803
- // result (redirect, block response) has already been sent.
1804
- // Any rewrite has been written back to req.url above so the
1805
- // Cloudflare plugin's handler sees the correct path.
1806
- //
1807
- // Call next() to hand off to the Cloudflare plugin's connect
1808
- // handler, which dispatches the request to miniflare.
1809
- if (hasCloudflarePlugin)
1810
- return next();
1811
1870
  // Build request context once for has/missing condition checks
1812
- // across headers, redirects, and rewrites.
1871
+ // for config rules that execute after middleware (rewrites).
1813
1872
  // Convert Node.js IncomingMessage headers to a Web Request for
1814
1873
  // requestContextFromRequest(), which uses the standard Web API.
1815
- const reqUrl = new URL(url, `http://${req.headers.host || "localhost"}`);
1816
- const reqCtxHeaders = middlewareRequestHeaders ??
1817
- new Headers(Object.fromEntries(Object.entries(req.headers)
1818
- .filter(([, v]) => v !== undefined)
1819
- .map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
1874
+ const reqUrl = new URL(url, requestOrigin);
1875
+ const reqCtxHeaders = middlewareRequestHeaders ?? nodeRequestHeaders;
1820
1876
  const reqCtx = requestContextFromRequest(new Request(reqUrl, { headers: reqCtxHeaders }));
1821
1877
  // Apply custom headers from next.config.js
1878
+ // Header matching still uses the original normalized pathname and
1879
+ // pre-middleware request state; middleware response headers win
1880
+ // later because they are already on the outgoing response.
1822
1881
  if (nextConfig?.headers.length) {
1823
- applyHeaders(pathname, res, nextConfig.headers, reqCtx);
1824
- }
1825
- // Apply redirects from next.config.js
1826
- if (nextConfig?.redirects.length) {
1827
- const redirected = applyRedirects(pathname, res, nextConfig.redirects, reqCtx, nextConfig.basePath ?? "");
1828
- if (redirected)
1829
- return;
1882
+ applyHeaders(pathname, res, nextConfig.headers, preMiddlewareReqCtx);
1830
1883
  }
1831
1884
  // Apply rewrites from next.config.js (beforeFiles)
1832
1885
  let resolvedUrl = url;
@@ -2561,6 +2614,38 @@ export default function vinext(options = {}) {
2561
2614
  },
2562
2615
  },
2563
2616
  },
2617
+ // Vite can emit empty SSR manifest entries for modules that Rollup inlines
2618
+ // into another chunk. Pages Router looks up assets by page module path at
2619
+ // runtime, so rebuild those mappings from the emitted client bundle.
2620
+ {
2621
+ name: "vinext:ssr-manifest-backfill",
2622
+ apply: "build",
2623
+ enforce: "post",
2624
+ writeBundle: {
2625
+ sequential: true,
2626
+ order: "post",
2627
+ handler(options, bundle) {
2628
+ const outDir = options.dir;
2629
+ if (!outDir)
2630
+ return;
2631
+ const viteDir = path.join(outDir, ".vite");
2632
+ const ssrManifestPath = path.join(viteDir, "ssr-manifest.json");
2633
+ if (!fs.existsSync(ssrManifestPath))
2634
+ return;
2635
+ try {
2636
+ const ssrManifest = JSON.parse(fs.readFileSync(ssrManifestPath, "utf-8"));
2637
+ const buildRoot = this.environment?.config.root ?? process.cwd();
2638
+ const buildBase = this.environment?.config.base ?? "/";
2639
+ const augmentedManifest = augmentSsrManifestFromBundle(ssrManifest, bundle, buildRoot, buildBase);
2640
+ fs.writeFileSync(ssrManifestPath, JSON.stringify(augmentedManifest, null, 2));
2641
+ }
2642
+ catch (err) {
2643
+ // Leave Vite's manifest untouched if parsing fails.
2644
+ console.warn("[vinext] Failed to augment SSR manifest:", err);
2645
+ }
2646
+ },
2647
+ },
2648
+ },
2564
2649
  // Cloudflare Workers production build integration:
2565
2650
  // After all environments are built, compute lazy chunks from the client
2566
2651
  // build manifest and inject globals into the worker entry.
@@ -2592,6 +2677,7 @@ export default function vinext(options = {}) {
2592
2677
  if (!fs.existsSync(distDir))
2593
2678
  return;
2594
2679
  const clientDir = path.resolve(buildRoot, "dist", "client");
2680
+ const clientBase = envConfig.base ?? "/";
2595
2681
  // Read build manifest and compute lazy chunks (only reachable via
2596
2682
  // dynamic imports). This runs for BOTH App Router and Pages Router.
2597
2683
  // clientEntryFile is only used by the Pages Router path below —
@@ -2604,11 +2690,11 @@ export default function vinext(options = {}) {
2604
2690
  const buildManifest = JSON.parse(fs.readFileSync(buildManifestPath, "utf-8"));
2605
2691
  for (const [, value] of Object.entries(buildManifest)) {
2606
2692
  if (value && value.isEntry && value.file) {
2607
- clientEntryFile = value.file;
2693
+ clientEntryFile = manifestFileWithBase(value.file, clientBase);
2608
2694
  break;
2609
2695
  }
2610
2696
  }
2611
- const lazy = computeLazyChunks(buildManifest);
2697
+ const lazy = manifestFilesWithBase(computeLazyChunks(buildManifest), clientBase);
2612
2698
  if (lazy.length > 0)
2613
2699
  lazyChunksData = lazy;
2614
2700
  }
@@ -2675,7 +2761,7 @@ export default function vinext(options = {}) {
2675
2761
  const entry = files.find((f) => (f.includes("vinext-client-entry") || f.includes("vinext-app-browser-entry")) &&
2676
2762
  f.endsWith(".js"));
2677
2763
  if (entry)
2678
- clientEntryFile = "assets/" + entry;
2764
+ clientEntryFile = manifestFileWithBase("assets/" + entry, clientBase);
2679
2765
  }
2680
2766
  }
2681
2767
  // Prepend globals to worker entry
@@ -3054,6 +3140,7 @@ function scanDirForMdx(dir) {
3054
3140
  export { staticExportPages, staticExportApp } from "./build/static-export.js";
3055
3141
  // Exported for CLI and testing
3056
3142
  export { clientManualChunks, clientOutputConfig, clientTreeshakeConfig, computeLazyChunks };
3143
+ export { augmentSsrManifestFromBundle as _augmentSsrManifestFromBundle };
3057
3144
  export { resolvePostcssStringPlugins as _resolvePostcssStringPlugins };
3058
3145
  export { parseStaticObjectLiteral as _parseStaticObjectLiteral };
3059
3146
  export { stripServerExports as _stripServerExports };