vinext 0.0.28 → 0.0.29

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 (89) hide show
  1. package/dist/build/report.d.ts +117 -0
  2. package/dist/build/report.d.ts.map +1 -0
  3. package/dist/build/report.js +303 -0
  4. package/dist/build/report.js.map +1 -0
  5. package/dist/cli.js +106 -9
  6. package/dist/cli.js.map +1 -1
  7. package/dist/cloudflare/kv-cache-handler.d.ts.map +1 -1
  8. package/dist/cloudflare/kv-cache-handler.js +14 -12
  9. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  10. package/dist/cloudflare/tpr.d.ts +10 -0
  11. package/dist/cloudflare/tpr.d.ts.map +1 -1
  12. package/dist/cloudflare/tpr.js +36 -41
  13. package/dist/cloudflare/tpr.js.map +1 -1
  14. package/dist/config/next-config.d.ts.map +1 -1
  15. package/dist/config/next-config.js +16 -0
  16. package/dist/config/next-config.js.map +1 -1
  17. package/dist/entries/app-rsc-entry.d.ts.map +1 -1
  18. package/dist/entries/app-rsc-entry.js +19 -24
  19. package/dist/entries/app-rsc-entry.js.map +1 -1
  20. package/dist/entries/pages-server-entry.d.ts.map +1 -1
  21. package/dist/entries/pages-server-entry.js +94 -44
  22. package/dist/entries/pages-server-entry.js.map +1 -1
  23. package/dist/index.d.ts +17 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +111 -38
  26. package/dist/index.js.map +1 -1
  27. package/dist/routing/app-router.d.ts +2 -0
  28. package/dist/routing/app-router.d.ts.map +1 -1
  29. package/dist/routing/app-router.js +92 -79
  30. package/dist/routing/app-router.js.map +1 -1
  31. package/dist/routing/pages-router.d.ts.map +1 -1
  32. package/dist/routing/pages-router.js +17 -57
  33. package/dist/routing/pages-router.js.map +1 -1
  34. package/dist/routing/route-trie.d.ts +57 -0
  35. package/dist/routing/route-trie.d.ts.map +1 -0
  36. package/dist/routing/route-trie.js +160 -0
  37. package/dist/routing/route-trie.js.map +1 -0
  38. package/dist/routing/route-validation.d.ts.map +1 -1
  39. package/dist/routing/route-validation.js +13 -1
  40. package/dist/routing/route-validation.js.map +1 -1
  41. package/dist/routing/utils.d.ts +19 -0
  42. package/dist/routing/utils.d.ts.map +1 -1
  43. package/dist/routing/utils.js +47 -0
  44. package/dist/routing/utils.js.map +1 -1
  45. package/dist/server/api-handler.d.ts.map +1 -1
  46. package/dist/server/api-handler.js +28 -13
  47. package/dist/server/api-handler.js.map +1 -1
  48. package/dist/server/dev-server.d.ts.map +1 -1
  49. package/dist/server/dev-server.js +58 -6
  50. package/dist/server/dev-server.js.map +1 -1
  51. package/dist/server/image-optimization.d.ts.map +1 -1
  52. package/dist/server/image-optimization.js +1 -1
  53. package/dist/server/image-optimization.js.map +1 -1
  54. package/dist/server/instrumentation.d.ts.map +1 -1
  55. package/dist/server/instrumentation.js +17 -8
  56. package/dist/server/instrumentation.js.map +1 -1
  57. package/dist/server/middleware-codegen.d.ts +10 -0
  58. package/dist/server/middleware-codegen.d.ts.map +1 -1
  59. package/dist/server/middleware-codegen.js +39 -0
  60. package/dist/server/middleware-codegen.js.map +1 -1
  61. package/dist/server/middleware.d.ts.map +1 -1
  62. package/dist/server/middleware.js +2 -1
  63. package/dist/server/middleware.js.map +1 -1
  64. package/dist/server/prod-server.d.ts +8 -2
  65. package/dist/server/prod-server.d.ts.map +1 -1
  66. package/dist/server/prod-server.js +60 -20
  67. package/dist/server/prod-server.js.map +1 -1
  68. package/dist/shims/headers.d.ts.map +1 -1
  69. package/dist/shims/headers.js +2 -5
  70. package/dist/shims/headers.js.map +1 -1
  71. package/dist/shims/link.d.ts.map +1 -1
  72. package/dist/shims/link.js +11 -43
  73. package/dist/shims/link.js.map +1 -1
  74. package/dist/shims/metadata.d.ts +56 -0
  75. package/dist/shims/metadata.d.ts.map +1 -1
  76. package/dist/shims/metadata.js +66 -0
  77. package/dist/shims/metadata.js.map +1 -1
  78. package/dist/shims/navigation.d.ts +2 -0
  79. package/dist/shims/navigation.d.ts.map +1 -1
  80. package/dist/shims/navigation.js +41 -29
  81. package/dist/shims/navigation.js.map +1 -1
  82. package/dist/shims/router.d.ts.map +1 -1
  83. package/dist/shims/router.js +13 -19
  84. package/dist/shims/router.js.map +1 -1
  85. package/dist/shims/url-utils.d.ts +20 -6
  86. package/dist/shims/url-utils.d.ts.map +1 -1
  87. package/dist/shims/url-utils.js +79 -0
  88. package/dist/shims/url-utils.js.map +1 -1
  89. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { createDirectRunner } from "./server/dev-module-runner.js";
10
10
  import { generateRscEntry } from "./entries/app-rsc-entry.js";
11
11
  import { generateSsrEntry } from "./entries/app-ssr-entry.js";
12
12
  import { generateBrowserEntry } from "./entries/app-browser-entry.js";
13
+ import { normalizePathnameForRouteMatchStrict } from "./routing/utils.js";
13
14
  import { loadNextConfig, resolveNextConfig, } from "./config/next-config.js";
14
15
  import { findMiddlewareFile, runMiddleware } from "./server/middleware.js";
15
16
  import { logRequest, now } from "./server/request-log.js";
@@ -227,6 +228,12 @@ const POSTCSS_CONFIG_FILES = [
227
228
  ".postcssrc.yaml",
228
229
  ".postcssrc.yml",
229
230
  ];
231
+ /**
232
+ * Module-level cache for resolvePostcssStringPlugins — avoids re-scanning per Vite environment.
233
+ * Stores the Promise itself so concurrent calls (RSC/SSR/Client config() hooks firing in
234
+ * parallel) all await the same in-flight scan rather than each starting their own.
235
+ */
236
+ const _postcssCache = new Map();
230
237
  /**
231
238
  * Resolve PostCSS string plugin names in a project's PostCSS config.
232
239
  *
@@ -239,7 +246,14 @@ const POSTCSS_CONFIG_FILES = [
239
246
  * Returns the resolved PostCSS config object to inject into Vite's
240
247
  * `css.postcss`, or `undefined` if no resolution is needed.
241
248
  */
242
- async function resolvePostcssStringPlugins(projectRoot) {
249
+ function resolvePostcssStringPlugins(projectRoot) {
250
+ if (_postcssCache.has(projectRoot))
251
+ return _postcssCache.get(projectRoot);
252
+ const promise = _resolvePostcssStringPluginsUncached(projectRoot);
253
+ _postcssCache.set(projectRoot, promise);
254
+ return promise;
255
+ }
256
+ async function _resolvePostcssStringPluginsUncached(projectRoot) {
243
257
  // Find the PostCSS config file
244
258
  let configPath = null;
245
259
  for (const name of POSTCSS_CONFIG_FILES) {
@@ -249,8 +263,9 @@ async function resolvePostcssStringPlugins(projectRoot) {
249
263
  break;
250
264
  }
251
265
  }
252
- if (!configPath)
266
+ if (!configPath) {
253
267
  return undefined;
268
+ }
254
269
  // Load the config file
255
270
  let config;
256
271
  try {
@@ -277,11 +292,13 @@ async function resolvePostcssStringPlugins(projectRoot) {
277
292
  }
278
293
  // Only process array-form plugins that contain string entries
279
294
  // (either bare strings or tuple form ["plugin-name", { options }])
280
- if (!config || !Array.isArray(config.plugins))
295
+ if (!config || !Array.isArray(config.plugins)) {
281
296
  return undefined;
297
+ }
282
298
  const hasStringPlugins = config.plugins.some((p) => typeof p === "string" || (Array.isArray(p) && typeof p[0] === "string"));
283
- if (!hasStringPlugins)
299
+ if (!hasStringPlugins) {
284
300
  return undefined;
301
+ }
285
302
  // Resolve string plugin names to actual plugin functions
286
303
  const req = createRequire(path.join(projectRoot, "package.json"));
287
304
  const resolved = await Promise.all(config.plugins.filter(Boolean).map(async (plugin) => {
@@ -556,6 +573,7 @@ function augmentSsrManifestFromBundle(ssrManifest, bundle, root, base = "/") {
556
573
  return Object.fromEntries(Object.entries(nextManifest).map(([key, files]) => [key, [...files]]));
557
574
  }
558
575
  export default function vinext(options = {}) {
576
+ const viteMajorVersion = getViteMajorVersion();
559
577
  let root;
560
578
  let pagesDir;
561
579
  let appDir;
@@ -571,6 +589,11 @@ export default function vinext(options = {}) {
571
589
  const shimsDir = path.resolve(__dirname, "shims");
572
590
  // Shim alias map — populated in config(), used by resolveId() for .js variants
573
591
  let nextShimMap = {};
592
+ // Build-only cache for og-inline-fetch-assets to avoid repeated file reads
593
+ // during a single production build. Dev mode skips the cache so asset edits
594
+ // are picked up without restarting the Vite server.
595
+ const _ogInlineCache = new Map();
596
+ let _ogInlineIsBuild = false;
574
597
  /**
575
598
  * Generate the virtual SSR server entry module.
576
599
  * This is the entry point for `vite build --ssr`.
@@ -650,7 +673,8 @@ export default function vinext(options = {}) {
650
673
  const plugins = [
651
674
  // Resolve tsconfig paths/baseUrl aliases so real-world Next.js repos
652
675
  // that use @/*, #/*, or baseUrl imports work out of the box.
653
- tsconfigPaths(),
676
+ // Vite 8+ supports this natively via resolve.tsconfigPaths.
677
+ ...(viteMajorVersion >= 8 ? [] : [tsconfigPaths()]),
654
678
  // React Fast Refresh + JSX transform for client components.
655
679
  reactPlugin,
656
680
  // Transform CJS require()/module.exports to ESM before other plugins
@@ -661,6 +685,8 @@ export default function vinext(options = {}) {
661
685
  enforce: "pre",
662
686
  async config(config, env) {
663
687
  root = config.root ?? process.cwd();
688
+ const userResolve = config.resolve;
689
+ const shouldEnableNativeTsconfigPaths = viteMajorVersion >= 8 && userResolve?.tsconfigPaths === undefined;
664
690
  // Load .env files into process.env before anything else.
665
691
  // Next.js loads .env files before evaluating next.config.js, so
666
692
  // env vars are available in config, server-side code, and as
@@ -767,33 +793,55 @@ export default function vinext(options = {}) {
767
793
  // Also used to namespace ISR cache keys so old cached entries from a
768
794
  // previous deploy are never served by the new one.
769
795
  defines["process.env.__VINEXT_BUILD_ID"] = JSON.stringify(nextConfig.buildId);
770
- // Build the shim alias map used by both resolve.alias and resolveId
771
- // (resolveId handles .js extension variants for libraries like nuqs)
796
+ // Build the shim alias map. Exact `.js` variants are included for the
797
+ // public Next entrypoints that are file-backed in `next/package.json`.
798
+ // Some libraries (for example `nuqs`) import `next/navigation.js`
799
+ // directly; aliasing the `.js` form ensures optimizeDeps pre-bundles
800
+ // vinext's shim instead of real Next.
772
801
  nextShimMap = {
773
802
  ...nextConfig.aliases,
774
803
  "next/link": path.join(shimsDir, "link"),
804
+ "next/link.js": path.join(shimsDir, "link"),
775
805
  "next/head": path.join(shimsDir, "head"),
806
+ "next/head.js": path.join(shimsDir, "head"),
776
807
  "next/router": path.join(shimsDir, "router"),
808
+ "next/router.js": path.join(shimsDir, "router"),
777
809
  "next/compat/router": path.join(shimsDir, "compat-router"),
810
+ "next/compat/router.js": path.join(shimsDir, "compat-router"),
778
811
  "next/image": path.join(shimsDir, "image"),
812
+ "next/image.js": path.join(shimsDir, "image"),
779
813
  "next/legacy/image": path.join(shimsDir, "legacy-image"),
814
+ "next/legacy/image.js": path.join(shimsDir, "legacy-image"),
780
815
  "next/dynamic": path.join(shimsDir, "dynamic"),
816
+ "next/dynamic.js": path.join(shimsDir, "dynamic"),
781
817
  "next/app": path.join(shimsDir, "app"),
818
+ "next/app.js": path.join(shimsDir, "app"),
782
819
  "next/document": path.join(shimsDir, "document"),
820
+ "next/document.js": path.join(shimsDir, "document"),
783
821
  "next/config": path.join(shimsDir, "config"),
784
822
  "next/script": path.join(shimsDir, "script"),
823
+ "next/script.js": path.join(shimsDir, "script"),
785
824
  "next/server": path.join(shimsDir, "server"),
825
+ "next/server.js": path.join(shimsDir, "server"),
786
826
  "next/navigation": path.join(shimsDir, "navigation"),
827
+ "next/navigation.js": path.join(shimsDir, "navigation"),
787
828
  "next/headers": path.join(shimsDir, "headers"),
829
+ "next/headers.js": path.join(shimsDir, "headers"),
788
830
  "next/font/google": path.join(shimsDir, "font-google"),
789
831
  "next/font/local": path.join(shimsDir, "font-local"),
790
832
  "next/cache": path.join(shimsDir, "cache"),
833
+ "next/cache.js": path.join(shimsDir, "cache"),
791
834
  "next/form": path.join(shimsDir, "form"),
835
+ "next/form.js": path.join(shimsDir, "form"),
792
836
  "next/og": path.join(shimsDir, "og"),
837
+ "next/og.js": path.join(shimsDir, "og"),
793
838
  "next/web-vitals": path.join(shimsDir, "web-vitals"),
839
+ "next/web-vitals.js": path.join(shimsDir, "web-vitals"),
794
840
  "next/amp": path.join(shimsDir, "amp"),
795
841
  "next/error": path.join(shimsDir, "error"),
842
+ "next/error.js": path.join(shimsDir, "error"),
796
843
  "next/constants": path.join(shimsDir, "constants"),
844
+ "next/constants.js": path.join(shimsDir, "constants"),
797
845
  // Internal next/dist/* paths used by popular libraries
798
846
  // (next-intl, @clerk/nextjs, @sentry/nextjs, next-nprogress-bar, etc.)
799
847
  "next/dist/shared/lib/app-router-context.shared-runtime": path.join(shimsDir, "internal", "app-router-context"),
@@ -986,6 +1034,7 @@ export default function vinext(options = {}) {
986
1034
  // causing cryptic "Invalid hook call" errors. This is a no-op
987
1035
  // when only one copy exists.
988
1036
  dedupe: ["react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"],
1037
+ ...(shouldEnableNativeTsconfigPaths ? { tsconfigPaths: true } : {}),
989
1038
  },
990
1039
  // Exclude vinext from dependency optimization so esbuild doesn't
991
1040
  // scan dist files containing virtual module imports (virtual:vinext-*)
@@ -998,7 +1047,7 @@ export default function vinext(options = {}) {
998
1047
  },
999
1048
  // Enable JSX in .tsx/.jsx files
1000
1049
  // Vite 7 uses `esbuild` for transforms, Vite 8+ uses `oxc`
1001
- ...(getViteMajorVersion() >= 8
1050
+ ...(viteMajorVersion >= 8
1002
1051
  ? { oxc: { jsx: { runtime: "automatic" } } }
1003
1052
  : { esbuild: { jsx: "automatic" } }),
1004
1053
  // Define env vars for client bundle
@@ -1099,6 +1148,10 @@ export default function vinext(options = {}) {
1099
1148
  consumer: "client",
1100
1149
  optimizeDeps: {
1101
1150
  exclude: ["vinext"],
1151
+ // Crawl app/ source files up front so client-only deps imported
1152
+ // by user components are discovered during startup instead of
1153
+ // triggering a late re-optimisation + full page reload.
1154
+ entries: appEntries,
1102
1155
  // React packages aren't crawled from app/ source files,
1103
1156
  // so must be pre-included to avoid late discovery (#25).
1104
1157
  include: [
@@ -1193,18 +1246,6 @@ export default function vinext(options = {}) {
1193
1246
  // ID (with \0 prefix). We need to re-resolve it so the client
1194
1247
  // environment's import-analysis can find it.
1195
1248
  const cleanId = id.startsWith("\0") ? id.slice(1) : id;
1196
- // Handle next/* imports with .js extension (e.g. "next/navigation.js")
1197
- // Libraries like nuqs import "next/navigation.js" which doesn't match
1198
- // our resolve.alias for "next/navigation". Strip the .js and resolve
1199
- // through our shim map, appending .js to the resolved path.
1200
- if (cleanId.startsWith("next/") && cleanId.endsWith(".js")) {
1201
- const withoutExt = cleanId.slice(0, -3);
1202
- if (nextShimMap[withoutExt]) {
1203
- const shimPath = nextShimMap[withoutExt];
1204
- // Alias values don't include .js — append it for resolveId
1205
- return shimPath.endsWith(".js") ? shimPath : shimPath + ".js";
1206
- }
1207
- }
1208
1249
  // Pages Router virtual modules
1209
1250
  if (cleanId === VIRTUAL_SERVER_ENTRY)
1210
1251
  return RESOLVED_SERVER_ENTRY;
@@ -1695,7 +1736,7 @@ export default function vinext(options = {}) {
1695
1736
  // decodeURIComponent prevents /%61dmin bypassing /admin matchers.
1696
1737
  // normalizePath collapses // and resolves . / .. segments.
1697
1738
  try {
1698
- pathname = normalizePath(decodeURIComponent(pathname));
1739
+ pathname = normalizePath(normalizePathnameForRouteMatchStrict(pathname));
1699
1740
  }
1700
1741
  catch {
1701
1742
  // Malformed percent-encoding (e.g. /%E0%A4%A) — return 400 instead of crashing.
@@ -1821,7 +1862,7 @@ export default function vinext(options = {}) {
1821
1862
  for (const [key, value] of result.response.headers) {
1822
1863
  res.appendHeader(key, value);
1823
1864
  }
1824
- const body = await result.response.text();
1865
+ const body = Buffer.from(await result.response.arrayBuffer());
1825
1866
  res.end(body);
1826
1867
  return;
1827
1868
  }
@@ -2462,11 +2503,20 @@ export default function vinext(options = {}) {
2462
2503
  {
2463
2504
  name: "vinext:og-inline-fetch-assets",
2464
2505
  enforce: "pre",
2465
- transform(code, id) {
2506
+ configResolved(config) {
2507
+ _ogInlineIsBuild = config.command === "build";
2508
+ },
2509
+ buildStart() {
2510
+ if (_ogInlineIsBuild) {
2511
+ _ogInlineCache.clear();
2512
+ }
2513
+ },
2514
+ async transform(code, id) {
2466
2515
  // Quick bail-out: only process modules that use new URL(..., import.meta.url)
2467
2516
  if (!code.includes("import.meta.url")) {
2468
2517
  return null;
2469
2518
  }
2519
+ const useCache = _ogInlineIsBuild;
2470
2520
  const moduleDir = path.dirname(id);
2471
2521
  let newCode = code;
2472
2522
  let didReplace = false;
@@ -2478,13 +2528,19 @@ export default function vinext(options = {}) {
2478
2528
  const fullMatch = match[0];
2479
2529
  const relPath = match[2]; // e.g. "./noto-sans-v27-latin-regular.ttf"
2480
2530
  const absPath = path.resolve(moduleDir, relPath);
2481
- let fileBase64;
2482
- try {
2483
- fileBase64 = fs.readFileSync(absPath).toString("base64");
2484
- }
2485
- catch {
2486
- // File not found on disk — skip (may be a runtime-only asset)
2487
- continue;
2531
+ let fileBase64 = useCache ? _ogInlineCache.get(absPath) : undefined;
2532
+ if (fileBase64 === undefined) {
2533
+ try {
2534
+ const buf = await fs.promises.readFile(absPath);
2535
+ fileBase64 = buf.toString("base64");
2536
+ if (useCache) {
2537
+ _ogInlineCache.set(absPath, fileBase64);
2538
+ }
2539
+ }
2540
+ catch {
2541
+ // File not found on disk — skip (may be a runtime-only asset)
2542
+ continue;
2543
+ }
2488
2544
  }
2489
2545
  // Replace fetch(...).then(...) with an inline IIFE that returns Promise<ArrayBuffer>.
2490
2546
  const inlined = [
@@ -2509,13 +2565,19 @@ export default function vinext(options = {}) {
2509
2565
  const fullMatch = match[0];
2510
2566
  const relPath = match[2]; // e.g. "./noto-sans-v27-latin-regular.ttf"
2511
2567
  const absPath = path.resolve(moduleDir, relPath);
2512
- let fileBase64;
2513
- try {
2514
- fileBase64 = fs.readFileSync(absPath).toString("base64");
2515
- }
2516
- catch {
2517
- // File not found on disk — skip
2518
- continue;
2568
+ let fileBase64 = useCache ? _ogInlineCache.get(absPath) : undefined;
2569
+ if (fileBase64 === undefined) {
2570
+ try {
2571
+ const buf = await fs.promises.readFile(absPath);
2572
+ fileBase64 = buf.toString("base64");
2573
+ if (useCache) {
2574
+ _ogInlineCache.set(absPath, fileBase64);
2575
+ }
2576
+ }
2577
+ catch {
2578
+ // File not found on disk — skip
2579
+ continue;
2580
+ }
2519
2581
  }
2520
2582
  // Replace readFileSync(...) with Buffer.from("<base64>", "base64").
2521
2583
  // Buffer is always available in Node.js and in the vinext SSR/RSC environments.
@@ -3104,15 +3166,23 @@ function findFileWithExts(dir, name, matcher) {
3104
3166
  }
3105
3167
  return null;
3106
3168
  }
3169
+ /** Module-level cache for hasMdxFiles — avoids re-scanning per Vite environment. */
3170
+ const _mdxScanCache = new Map();
3107
3171
  /**
3108
3172
  * Check if the project has .mdx files in app/ or pages/ directories.
3109
3173
  */
3110
3174
  function hasMdxFiles(root, appDir, pagesDir) {
3175
+ const cacheKey = `${root}\0${appDir ?? ""}\0${pagesDir ?? ""}`;
3176
+ if (_mdxScanCache.has(cacheKey))
3177
+ return _mdxScanCache.get(cacheKey);
3111
3178
  const dirs = [appDir, pagesDir].filter(Boolean);
3112
3179
  for (const dir of dirs) {
3113
- if (fs.existsSync(dir) && scanDirForMdx(dir))
3180
+ if (fs.existsSync(dir) && scanDirForMdx(dir)) {
3181
+ _mdxScanCache.set(cacheKey, true);
3114
3182
  return true;
3183
+ }
3115
3184
  }
3185
+ _mdxScanCache.set(cacheKey, false);
3116
3186
  return false;
3117
3187
  }
3118
3188
  function scanDirForMdx(dir) {
@@ -3142,6 +3212,9 @@ export { staticExportPages, staticExportApp } from "./build/static-export.js";
3142
3212
  export { clientManualChunks, clientOutputConfig, clientTreeshakeConfig, computeLazyChunks };
3143
3213
  export { augmentSsrManifestFromBundle as _augmentSsrManifestFromBundle };
3144
3214
  export { resolvePostcssStringPlugins as _resolvePostcssStringPlugins };
3215
+ export { _postcssCache };
3216
+ export { hasMdxFiles as _hasMdxFiles };
3217
+ export { _mdxScanCache };
3145
3218
  export { parseStaticObjectLiteral as _parseStaticObjectLiteral };
3146
3219
  export { stripServerExports as _stripServerExports };
3147
3220
  export { asyncHooksStubPlugin as _asyncHooksStubPlugin };