vinext 0.0.37 → 0.0.39

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 (262) hide show
  1. package/README.md +33 -20
  2. package/dist/build/nitro-route-rules.d.ts +50 -0
  3. package/dist/build/nitro-route-rules.js +81 -0
  4. package/dist/build/nitro-route-rules.js.map +1 -0
  5. package/dist/build/precompress.d.ts +17 -0
  6. package/dist/build/precompress.js +102 -0
  7. package/dist/build/precompress.js.map +1 -0
  8. package/dist/build/prerender.d.ts +27 -22
  9. package/dist/build/prerender.js +17 -17
  10. package/dist/build/prerender.js.map +1 -1
  11. package/dist/build/report.d.ts +3 -4
  12. package/dist/build/report.js.map +1 -1
  13. package/dist/build/run-prerender.d.ts +3 -4
  14. package/dist/build/run-prerender.js.map +1 -1
  15. package/dist/build/standalone.d.ts +32 -0
  16. package/dist/build/standalone.js +199 -0
  17. package/dist/build/standalone.js.map +1 -0
  18. package/dist/build/static-export.d.ts +17 -29
  19. package/dist/build/static-export.js.map +1 -1
  20. package/dist/cache.d.ts +2 -0
  21. package/dist/cache.js +2 -0
  22. package/dist/check.d.ts +4 -4
  23. package/dist/check.js +1 -1
  24. package/dist/check.js.map +1 -1
  25. package/dist/cli.js +37 -26
  26. package/dist/cli.js.map +1 -1
  27. package/dist/client/empty-module.d.ts +1 -0
  28. package/dist/client/empty-module.js +1 -0
  29. package/dist/client/entry.js +2 -0
  30. package/dist/client/entry.js.map +1 -1
  31. package/dist/client/instrumentation-client-state.d.ts +10 -0
  32. package/dist/client/instrumentation-client-state.js +19 -0
  33. package/dist/client/instrumentation-client-state.js.map +1 -0
  34. package/dist/client/instrumentation-client.d.ts +8 -0
  35. package/dist/client/instrumentation-client.js +8 -0
  36. package/dist/client/instrumentation-client.js.map +1 -0
  37. package/dist/client/vinext-next-data.d.ts +5 -8
  38. package/dist/cloudflare/index.js +1 -1
  39. package/dist/cloudflare/kv-cache-handler.d.ts +5 -3
  40. package/dist/cloudflare/kv-cache-handler.js +1 -1
  41. package/dist/cloudflare/kv-cache-handler.js.map +1 -1
  42. package/dist/cloudflare/tpr.d.ts +35 -27
  43. package/dist/cloudflare/tpr.js +37 -15
  44. package/dist/cloudflare/tpr.js.map +1 -1
  45. package/dist/config/config-matchers.d.ts +2 -2
  46. package/dist/config/config-matchers.js +1 -1
  47. package/dist/config/config-matchers.js.map +1 -1
  48. package/dist/config/dotenv.d.ts +4 -4
  49. package/dist/config/dotenv.js.map +1 -1
  50. package/dist/config/next-config.d.ts +40 -61
  51. package/dist/config/next-config.js +5 -4
  52. package/dist/config/next-config.js.map +1 -1
  53. package/dist/deploy.d.ts +25 -41
  54. package/dist/deploy.js +10 -4
  55. package/dist/deploy.js.map +1 -1
  56. package/dist/entries/app-rsc-entry.d.ts +6 -10
  57. package/dist/entries/app-rsc-entry.js +31 -28
  58. package/dist/entries/app-rsc-entry.js.map +1 -1
  59. package/dist/entries/pages-client-entry.js +2 -0
  60. package/dist/entries/pages-client-entry.js.map +1 -1
  61. package/dist/entries/pages-server-entry.js +42 -263
  62. package/dist/entries/pages-server-entry.js.map +1 -1
  63. package/dist/entries/runtime-entry-module.d.ts +13 -1
  64. package/dist/entries/runtime-entry-module.js +18 -4
  65. package/dist/entries/runtime-entry-module.js.map +1 -1
  66. package/dist/index.d.ts +33 -41
  67. package/dist/index.js +263 -777
  68. package/dist/index.js.map +1 -1
  69. package/dist/init.d.ts +14 -26
  70. package/dist/init.js +8 -2
  71. package/dist/init.js.map +1 -1
  72. package/dist/plugins/client-reference-dedup.js.map +1 -1
  73. package/dist/plugins/fix-use-server-closure-collision.d.ts +29 -0
  74. package/dist/plugins/fix-use-server-closure-collision.js +204 -0
  75. package/dist/plugins/fix-use-server-closure-collision.js.map +1 -0
  76. package/dist/plugins/fonts.d.ts +56 -0
  77. package/dist/plugins/fonts.js +531 -0
  78. package/dist/plugins/fonts.js.map +1 -0
  79. package/dist/plugins/instrumentation-client.d.ts +7 -0
  80. package/dist/plugins/instrumentation-client.js +29 -0
  81. package/dist/plugins/instrumentation-client.js.map +1 -0
  82. package/dist/plugins/og-assets.d.ts +26 -0
  83. package/dist/plugins/og-assets.js +118 -0
  84. package/dist/plugins/og-assets.js.map +1 -0
  85. package/dist/plugins/optimize-imports.d.ts +2 -2
  86. package/dist/plugins/optimize-imports.js +4 -4
  87. package/dist/plugins/optimize-imports.js.map +1 -1
  88. package/dist/plugins/server-externals-manifest.d.ts +27 -0
  89. package/dist/plugins/server-externals-manifest.js +76 -0
  90. package/dist/plugins/server-externals-manifest.js.map +1 -0
  91. package/dist/routing/app-router.d.ts +29 -55
  92. package/dist/routing/app-router.js.map +1 -1
  93. package/dist/routing/file-matcher.d.ts +2 -2
  94. package/dist/routing/file-matcher.js.map +1 -1
  95. package/dist/routing/pages-router.d.ts +6 -11
  96. package/dist/routing/pages-router.js.map +1 -1
  97. package/dist/routing/route-trie.d.ts +2 -2
  98. package/dist/routing/route-trie.js.map +1 -1
  99. package/dist/server/api-handler.js +6 -23
  100. package/dist/server/api-handler.js.map +1 -1
  101. package/dist/server/app-browser-entry.js +274 -39
  102. package/dist/server/app-browser-entry.js.map +1 -1
  103. package/dist/server/app-browser-stream.d.ts +6 -6
  104. package/dist/server/app-browser-stream.js.map +1 -1
  105. package/dist/server/app-page-boundary-render.d.ts +8 -8
  106. package/dist/server/app-page-boundary-render.js +2 -2
  107. package/dist/server/app-page-boundary-render.js.map +1 -1
  108. package/dist/server/app-page-boundary.d.ts +13 -11
  109. package/dist/server/app-page-boundary.js +1 -1
  110. package/dist/server/app-page-boundary.js.map +1 -1
  111. package/dist/server/app-page-cache.d.ts +10 -10
  112. package/dist/server/app-page-cache.js.map +1 -1
  113. package/dist/server/app-page-execution.d.ts +10 -10
  114. package/dist/server/app-page-execution.js.map +1 -1
  115. package/dist/server/app-page-probe.d.ts +2 -2
  116. package/dist/server/app-page-probe.js.map +1 -1
  117. package/dist/server/app-page-render.d.ts +4 -4
  118. package/dist/server/app-page-render.js.map +1 -1
  119. package/dist/server/app-page-request.d.ts +12 -12
  120. package/dist/server/app-page-request.js.map +1 -1
  121. package/dist/server/app-page-response.d.ts +18 -18
  122. package/dist/server/app-page-response.js.map +1 -1
  123. package/dist/server/app-page-stream.d.ts +18 -18
  124. package/dist/server/app-page-stream.js.map +1 -1
  125. package/dist/server/app-route-handler-cache.d.ts +2 -2
  126. package/dist/server/app-route-handler-cache.js.map +1 -1
  127. package/dist/server/app-route-handler-execution.d.ts +6 -6
  128. package/dist/server/app-route-handler-execution.js.map +1 -1
  129. package/dist/server/app-route-handler-policy.d.ts +8 -8
  130. package/dist/server/app-route-handler-policy.js.map +1 -1
  131. package/dist/server/app-route-handler-response.d.ts +6 -6
  132. package/dist/server/app-route-handler-response.js.map +1 -1
  133. package/dist/server/app-route-handler-runtime.d.ts +4 -4
  134. package/dist/server/app-route-handler-runtime.js.map +1 -1
  135. package/dist/server/app-ssr-entry.d.ts +4 -4
  136. package/dist/server/app-ssr-entry.js.map +1 -1
  137. package/dist/server/app-ssr-stream.d.ts +2 -2
  138. package/dist/server/app-ssr-stream.js +1 -3
  139. package/dist/server/app-ssr-stream.js.map +1 -1
  140. package/dist/server/dev-module-runner.d.ts +2 -2
  141. package/dist/server/dev-module-runner.js.map +1 -1
  142. package/dist/server/dev-server.js +8 -8
  143. package/dist/server/dev-server.js.map +1 -1
  144. package/dist/server/image-optimization.d.ts +7 -12
  145. package/dist/server/image-optimization.js.map +1 -1
  146. package/dist/server/instrumentation.d.ts +13 -13
  147. package/dist/server/instrumentation.js +16 -7
  148. package/dist/server/instrumentation.js.map +1 -1
  149. package/dist/server/isr-cache.d.ts +2 -2
  150. package/dist/server/isr-cache.js.map +1 -1
  151. package/dist/server/metadata-routes.d.ts +14 -19
  152. package/dist/server/metadata-routes.js.map +1 -1
  153. package/dist/server/middleware.d.ts +10 -16
  154. package/dist/server/middleware.js +15 -8
  155. package/dist/server/middleware.js.map +1 -1
  156. package/dist/server/pages-api-route.d.ts +23 -0
  157. package/dist/server/pages-api-route.js +40 -0
  158. package/dist/server/pages-api-route.js.map +1 -0
  159. package/dist/server/pages-i18n.d.ts +4 -4
  160. package/dist/server/pages-i18n.js.map +1 -1
  161. package/dist/server/pages-media-type.d.ts +16 -0
  162. package/dist/server/pages-media-type.js +25 -0
  163. package/dist/server/pages-media-type.js.map +1 -0
  164. package/dist/server/pages-node-compat.d.ts +45 -0
  165. package/dist/server/pages-node-compat.js +148 -0
  166. package/dist/server/pages-node-compat.js.map +1 -0
  167. package/dist/server/pages-page-data.d.ts +22 -22
  168. package/dist/server/pages-page-data.js.map +1 -1
  169. package/dist/server/pages-page-response.d.ts +8 -8
  170. package/dist/server/pages-page-response.js.map +1 -1
  171. package/dist/server/prod-server.d.ts +20 -15
  172. package/dist/server/prod-server.js +171 -53
  173. package/dist/server/prod-server.js.map +1 -1
  174. package/dist/server/seed-cache.js.map +1 -1
  175. package/dist/server/static-file-cache.d.ts +57 -0
  176. package/dist/server/static-file-cache.js +219 -0
  177. package/dist/server/static-file-cache.js.map +1 -0
  178. package/dist/shims/app.d.ts +2 -2
  179. package/dist/shims/cache-for-request.d.ts +58 -0
  180. package/dist/shims/cache-for-request.js +74 -0
  181. package/dist/shims/cache-for-request.js.map +1 -0
  182. package/dist/shims/cache-runtime.d.ts +6 -9
  183. package/dist/shims/cache-runtime.js.map +1 -1
  184. package/dist/shims/cache.d.ts +28 -31
  185. package/dist/shims/cache.js.map +1 -1
  186. package/dist/shims/config.d.ts +2 -2
  187. package/dist/shims/config.js.map +1 -1
  188. package/dist/shims/dynamic.d.ts +2 -2
  189. package/dist/shims/dynamic.js +30 -17
  190. package/dist/shims/dynamic.js.map +1 -1
  191. package/dist/shims/error-boundary.d.ts +7 -7
  192. package/dist/shims/error-boundary.js.map +1 -1
  193. package/dist/shims/error.d.ts +2 -2
  194. package/dist/shims/error.js.map +1 -1
  195. package/dist/shims/fetch-cache.d.ts +4 -4
  196. package/dist/shims/fetch-cache.js.map +1 -1
  197. package/dist/shims/font-google-base.d.ts +4 -4
  198. package/dist/shims/font-google-base.js.map +1 -1
  199. package/dist/shims/font-local.d.ts +6 -6
  200. package/dist/shims/font-local.js.map +1 -1
  201. package/dist/shims/form.d.ts +4 -8
  202. package/dist/shims/form.js +4 -6
  203. package/dist/shims/form.js.map +1 -1
  204. package/dist/shims/head-state.d.ts +2 -2
  205. package/dist/shims/head-state.js.map +1 -1
  206. package/dist/shims/head.d.ts +2 -2
  207. package/dist/shims/head.js +18 -20
  208. package/dist/shims/head.js.map +1 -1
  209. package/dist/shims/headers.d.ts +4 -4
  210. package/dist/shims/headers.js +1 -1
  211. package/dist/shims/headers.js.map +1 -1
  212. package/dist/shims/i18n-context.d.ts +2 -2
  213. package/dist/shims/i18n-context.js.map +1 -1
  214. package/dist/shims/i18n-state.d.ts +2 -2
  215. package/dist/shims/i18n-state.js.map +1 -1
  216. package/dist/shims/image-config.d.ts +2 -2
  217. package/dist/shims/image-config.js.map +1 -1
  218. package/dist/shims/image.d.ts +5 -6
  219. package/dist/shims/image.js +24 -8
  220. package/dist/shims/image.js.map +1 -1
  221. package/dist/shims/internal/app-router-context.d.ts +6 -6
  222. package/dist/shims/internal/app-router-context.js.map +1 -1
  223. package/dist/shims/internal/utils.d.ts +2 -2
  224. package/dist/shims/internal/utils.js.map +1 -1
  225. package/dist/shims/layout-segment-context.d.ts +12 -5
  226. package/dist/shims/layout-segment-context.js +18 -7
  227. package/dist/shims/layout-segment-context.js.map +1 -1
  228. package/dist/shims/legacy-image.d.ts +5 -8
  229. package/dist/shims/legacy-image.js.map +1 -1
  230. package/dist/shims/link.d.ts +21 -31
  231. package/dist/shims/link.js +4 -56
  232. package/dist/shims/link.js.map +1 -1
  233. package/dist/shims/metadata.d.ts +23 -31
  234. package/dist/shims/metadata.js.map +1 -1
  235. package/dist/shims/navigation-state.d.ts +2 -2
  236. package/dist/shims/navigation-state.js.map +1 -1
  237. package/dist/shims/navigation.d.ts +102 -17
  238. package/dist/shims/navigation.js +361 -113
  239. package/dist/shims/navigation.js.map +1 -1
  240. package/dist/shims/request-context.d.ts +2 -2
  241. package/dist/shims/request-context.js.map +1 -1
  242. package/dist/shims/router-state.d.ts +4 -4
  243. package/dist/shims/router-state.js.map +1 -1
  244. package/dist/shims/router.d.ts +28 -47
  245. package/dist/shims/router.js.map +1 -1
  246. package/dist/shims/script.d.ts +16 -31
  247. package/dist/shims/script.js.map +1 -1
  248. package/dist/shims/server.d.ts +11 -10
  249. package/dist/shims/server.js +3 -0
  250. package/dist/shims/server.js.map +1 -1
  251. package/dist/shims/unified-request-context.d.ts +4 -4
  252. package/dist/shims/unified-request-context.js +1 -0
  253. package/dist/shims/unified-request-context.js.map +1 -1
  254. package/dist/shims/web-vitals.d.ts +2 -2
  255. package/dist/shims/web-vitals.js.map +1 -1
  256. package/dist/utils/lazy-chunks.d.ts +34 -0
  257. package/dist/utils/lazy-chunks.js +50 -0
  258. package/dist/utils/lazy-chunks.js.map +1 -0
  259. package/dist/utils/vinext-root.d.ts +24 -0
  260. package/dist/utils/vinext-root.js +31 -0
  261. package/dist/utils/vinext-root.js.map +1 -0
  262. package/package.json +8 -4
package/dist/index.js CHANGED
@@ -4,12 +4,12 @@ import { createValidFileMatcher } from "./routing/file-matcher.js";
4
4
  import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./routing/pages-router.js";
5
5
  import { buildRequestHeadersFromMiddlewareResponse } from "./server/middleware-request-headers.js";
6
6
  import { isExternalUrl, matchConfigPattern, matchHeaders, matchRedirect, matchRewrite, proxyExternalRequest, requestContextFromRequest, sanitizeDestination } from "./config/config-matchers.js";
7
- import { normalizePath } from "./server/normalize-path.js";
7
+ import { normalizePath as normalizePath$1 } from "./server/normalize-path.js";
8
8
  import { findMiddlewareFile, runMiddleware } from "./server/middleware.js";
9
9
  import { generateServerEntry } from "./entries/pages-server-entry.js";
10
10
  import { generateClientEntry } from "./entries/pages-client-entry.js";
11
11
  import { appRouter, invalidateAppRouteCache } from "./routing/app-router.js";
12
- import { findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
12
+ import { findInstrumentationClientFile, findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
13
13
  import { hasBasePath } from "./utils/base-path.js";
14
14
  import { logRequest, now } from "./server/request-log.js";
15
15
  import { createSSRHandler } from "./server/dev-server.js";
@@ -21,24 +21,31 @@ import { generateSsrEntry } from "./entries/app-ssr-entry.js";
21
21
  import { generateBrowserEntry } from "./entries/app-browser-entry.js";
22
22
  import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
23
23
  import { findNextConfigPath, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
24
+ import { precompressAssets } from "./build/precompress.js";
24
25
  import { scanMetadataFiles } from "./server/metadata-routes.js";
25
26
  import { manifestFileWithBase, manifestFilesWithBase, normalizeManifestFile } from "./utils/manifest-paths.js";
26
27
  import { asyncHooksStubPlugin } from "./plugins/async-hooks-stub.js";
27
28
  import { clientReferenceDedupPlugin } from "./plugins/client-reference-dedup.js";
29
+ import { createInstrumentationClientTransformPlugin } from "./plugins/instrumentation-client.js";
28
30
  import { createOptimizeImportsPlugin } from "./plugins/optimize-imports.js";
31
+ import { fixUseServerClosureCollisionPlugin } from "./plugins/fix-use-server-closure-collision.js";
32
+ import { createOgInlineFetchAssetsPlugin, ogAssetsPlugin } from "./plugins/og-assets.js";
33
+ import { createServerExternalsManifestPlugin } from "./plugins/server-externals-manifest.js";
34
+ import { RESOLVED_VIRTUAL_GOOGLE_FONTS, VIRTUAL_GOOGLE_FONTS, _findBalancedObject, _findCallEnd, createGoogleFontsPlugin, createLocalFontsPlugin, generateGoogleFontsVirtualModule, parseStaticObjectLiteral } from "./plugins/fonts.js";
35
+ import { computeLazyChunks } from "./utils/lazy-chunks.js";
29
36
  import { formatMissingCloudflarePluginError, hasWranglerConfig } from "./deploy.js";
30
37
  import { staticExportApp, staticExportPages } from "./build/static-export.js";
31
38
  import { createRequire } from "node:module";
32
39
  import fs from "node:fs";
33
40
  import path from "node:path";
34
41
  import { loadEnv, parseAst } from "vite";
35
- import { fileURLToPath, pathToFileURL } from "node:url";
42
+ import { pathToFileURL } from "node:url";
36
43
  import { randomBytes } from "node:crypto";
37
44
  import MagicString from "magic-string";
38
45
  import tsconfigPaths from "vite-tsconfig-paths";
39
46
  import commonjs from "vite-plugin-commonjs";
40
47
  //#region src/index.ts
41
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
48
+ const __dirname = import.meta.dirname;
42
49
  function resolveOptionalDependency(projectRoot, specifier) {
43
50
  try {
44
51
  return createRequire(path.join(projectRoot, "package.json")).resolve(specifier);
@@ -55,113 +62,8 @@ function resolveShimModulePath(shimsDir, moduleName) {
55
62
  }
56
63
  return path.join(shimsDir, `${moduleName}.js`);
57
64
  }
58
- /**
59
- * Fetch Google Fonts CSS, download .woff2 files, cache locally, and return
60
- * @font-face CSS with local file references.
61
- *
62
- * Cache dir structure: .vinext/fonts/<family-hash>/
63
- * - style.css (the rewritten @font-face CSS)
64
- * - *.woff2 (downloaded font files)
65
- */
66
- async function fetchAndCacheFont(cssUrl, family, cacheDir) {
67
- const { createHash } = await import("node:crypto");
68
- const urlHash = createHash("md5").update(cssUrl).digest("hex").slice(0, 12);
69
- const fontDir = path.join(cacheDir, `${family.toLowerCase().replace(/\s+/g, "-")}-${urlHash}`);
70
- const cachedCSSPath = path.join(fontDir, "style.css");
71
- if (fs.existsSync(cachedCSSPath)) return fs.readFileSync(cachedCSSPath, "utf-8");
72
- const cssResponse = await fetch(cssUrl, { headers: { "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" } });
73
- if (!cssResponse.ok) throw new Error(`Failed to fetch Google Fonts CSS: ${cssResponse.status}`);
74
- let css = await cssResponse.text();
75
- const urlRe = /url\((https:\/\/fonts\.gstatic\.com\/[^)]+)\)/g;
76
- const urls = /* @__PURE__ */ new Map();
77
- let urlMatch;
78
- while ((urlMatch = urlRe.exec(css)) !== null) {
79
- const fontUrl = urlMatch[1];
80
- if (!urls.has(fontUrl)) {
81
- const ext = fontUrl.includes(".woff2") ? ".woff2" : fontUrl.includes(".woff") ? ".woff" : ".ttf";
82
- const fileHash = createHash("md5").update(fontUrl).digest("hex").slice(0, 8);
83
- urls.set(fontUrl, `${family.toLowerCase().replace(/\s+/g, "-")}-${fileHash}${ext}`);
84
- }
85
- }
86
- fs.mkdirSync(fontDir, { recursive: true });
87
- for (const [fontUrl, filename] of urls) {
88
- const filePath = path.join(fontDir, filename);
89
- if (!fs.existsSync(filePath)) {
90
- const fontResponse = await fetch(fontUrl);
91
- if (fontResponse.ok) {
92
- const buffer = Buffer.from(await fontResponse.arrayBuffer());
93
- fs.writeFileSync(filePath, buffer);
94
- }
95
- }
96
- css = css.split(fontUrl).join(filePath);
97
- }
98
- fs.writeFileSync(cachedCSSPath, css);
99
- return css;
100
- }
101
- /**
102
- * Safely parse a static JS object literal string into a plain object.
103
- * Uses Vite's parseAst (Rollup/acorn) so no code is ever evaluated.
104
- * Returns null if the expression contains anything dynamic (function calls,
105
- * template literals, identifiers, computed properties, etc.).
106
- *
107
- * Supports: string literals, numeric literals, boolean literals,
108
- * arrays of the above, and nested object literals.
109
- */
110
- function parseStaticObjectLiteral(objectStr) {
111
- let ast;
112
- try {
113
- ast = parseAst(`(${objectStr})`);
114
- } catch {
115
- return null;
116
- }
117
- const body = ast.body;
118
- if (body.length !== 1 || body[0].type !== "ExpressionStatement") return null;
119
- const expr = body[0].expression;
120
- if (expr.type !== "ObjectExpression") return null;
121
- const result = extractStaticValue(expr);
122
- return result === void 0 ? null : result;
123
- }
124
- /**
125
- * Recursively extract a static value from an ESTree AST node.
126
- * Returns undefined (not null) if the node contains any dynamic expression.
127
- *
128
- * Uses `any` for the node parameter because Rollup's internal ESTree types
129
- * (estree.Expression, estree.ObjectExpression, etc.) aren't re-exported by Vite,
130
- * and the recursive traversal touches many different node shapes.
131
- */
132
- function extractStaticValue(node) {
133
- switch (node.type) {
134
- case "Literal": return node.value;
135
- case "UnaryExpression":
136
- if (node.operator === "-" && node.argument?.type === "Literal" && typeof node.argument.value === "number") return -node.argument.value;
137
- return;
138
- case "ArrayExpression": {
139
- const arr = [];
140
- for (const elem of node.elements) {
141
- if (!elem) return void 0;
142
- const val = extractStaticValue(elem);
143
- if (val === void 0) return void 0;
144
- arr.push(val);
145
- }
146
- return arr;
147
- }
148
- case "ObjectExpression": {
149
- const obj = {};
150
- for (const prop of node.properties) {
151
- if (prop.type !== "Property") return void 0;
152
- if (prop.computed) return void 0;
153
- let key;
154
- if (prop.key.type === "Identifier") key = prop.key.name;
155
- else if (prop.key.type === "Literal" && typeof prop.key.value === "string") key = prop.key.value;
156
- else return;
157
- const val = extractStaticValue(prop.value);
158
- if (val === void 0) return void 0;
159
- obj[key] = val;
160
- }
161
- return obj;
162
- }
163
- default: return;
164
- }
65
+ function toRelativeFileEntry(root, absPath) {
66
+ return path.relative(root, absPath).split(path.sep).join("/");
165
67
  }
166
68
  function isRecord(value) {
167
69
  return !!value && typeof value === "object" && !Array.isArray(value);
@@ -217,7 +119,7 @@ function toViteAliasReplacement(absolutePath, projectRoot) {
217
119
  const realPath = tryRealpathSync(absolutePath);
218
120
  if (realPath) pathCandidates.add(realPath);
219
121
  for (const rootCandidate of rootCandidates) for (const pathCandidate of pathCandidates) {
220
- if (pathCandidate === rootCandidate) return "/";
122
+ if (pathCandidate === rootCandidate) return normalizedPath;
221
123
  const relativeId = relativeWithinRoot(rootCandidate, pathCandidate);
222
124
  if (relativeId) return "/" + relativeId;
223
125
  }
@@ -378,18 +280,9 @@ const VIRTUAL_APP_SSR_ENTRY = "virtual:vinext-app-ssr-entry";
378
280
  const RESOLVED_APP_SSR_ENTRY = "\0" + VIRTUAL_APP_SSR_ENTRY;
379
281
  const VIRTUAL_APP_BROWSER_ENTRY = "virtual:vinext-app-browser-entry";
380
282
  const RESOLVED_APP_BROWSER_ENTRY = "\0" + VIRTUAL_APP_BROWSER_ENTRY;
381
- const VIRTUAL_GOOGLE_FONTS = "virtual:vinext-google-fonts";
382
- const RESOLVED_VIRTUAL_GOOGLE_FONTS = "\0" + VIRTUAL_GOOGLE_FONTS;
383
283
  /** Image file extensions handled by the vinext:image-imports plugin.
384
284
  * Shared between the Rolldown hook filter and the transform handler regex. */
385
285
  const IMAGE_EXTS = "png|jpe?g|gif|webp|avif|svg|ico|bmp|tiff?";
386
- const GOOGLE_FONT_UTILITY_EXPORTS = new Set([
387
- "buildGoogleFontsUrl",
388
- "getSSRFontLinks",
389
- "getSSRFontStyles",
390
- "getSSRFontPreloads",
391
- "createFontLoader"
392
- ]);
393
286
  /**
394
287
  * Extract the npm package name from a module ID (file path).
395
288
  * Returns null if not in node_modules.
@@ -410,101 +303,6 @@ function getPackageName(id) {
410
303
  /** Absolute path to vinext's shims directory, used by clientManualChunks. */
411
304
  const _shimsDir = path.resolve(__dirname, "shims") + "/";
412
305
  const _fontGoogleShimPath = resolveShimModulePath(_shimsDir, "font-google");
413
- function parseGoogleFontNamedSpecifiers(specifiersStr, forceType = false) {
414
- return specifiersStr.split(",").map((spec) => spec.trim()).filter(Boolean).map((raw) => {
415
- const isType = forceType || raw.startsWith("type ");
416
- const asParts = (isType ? raw.replace(/^type\s+/, "") : raw).split(/\s+as\s+/);
417
- return {
418
- imported: asParts[0]?.trim() ?? "",
419
- local: (asParts[1] || asParts[0] || "").trim(),
420
- isType,
421
- raw
422
- };
423
- }).filter((spec) => spec.imported.length > 0 && spec.local.length > 0);
424
- }
425
- function parseGoogleFontImportClause(clause) {
426
- const trimmed = clause.trim();
427
- if (trimmed.startsWith("type ")) {
428
- const braceStart = trimmed.indexOf("{");
429
- const braceEnd = trimmed.lastIndexOf("}");
430
- if (braceStart === -1 || braceEnd === -1) return {
431
- defaultLocal: null,
432
- namespaceLocal: null,
433
- named: []
434
- };
435
- return {
436
- defaultLocal: null,
437
- namespaceLocal: null,
438
- named: parseGoogleFontNamedSpecifiers(trimmed.slice(braceStart + 1, braceEnd), true)
439
- };
440
- }
441
- const braceStart = trimmed.indexOf("{");
442
- const braceEnd = trimmed.lastIndexOf("}");
443
- if (braceStart !== -1 && braceEnd !== -1) return {
444
- defaultLocal: trimmed.slice(0, braceStart).trim().replace(/,\s*$/, "").trim() || null,
445
- namespaceLocal: null,
446
- named: parseGoogleFontNamedSpecifiers(trimmed.slice(braceStart + 1, braceEnd))
447
- };
448
- const commaIndex = trimmed.indexOf(",");
449
- if (commaIndex !== -1) {
450
- const defaultLocal = trimmed.slice(0, commaIndex).trim() || null;
451
- const rest = trimmed.slice(commaIndex + 1).trim();
452
- if (rest.startsWith("* as ")) return {
453
- defaultLocal,
454
- namespaceLocal: rest.slice(5).trim() || null,
455
- named: []
456
- };
457
- }
458
- if (trimmed.startsWith("* as ")) return {
459
- defaultLocal: null,
460
- namespaceLocal: trimmed.slice(5).trim() || null,
461
- named: []
462
- };
463
- return {
464
- defaultLocal: trimmed || null,
465
- namespaceLocal: null,
466
- named: []
467
- };
468
- }
469
- function encodeGoogleFontsVirtualId(payload) {
470
- const params = new URLSearchParams();
471
- if (payload.hasDefault) params.set("default", "1");
472
- if (payload.fonts.length > 0) params.set("fonts", payload.fonts.join(","));
473
- if (payload.utilities.length > 0) params.set("utilities", payload.utilities.join(","));
474
- return `${VIRTUAL_GOOGLE_FONTS}?${params.toString()}`;
475
- }
476
- function parseGoogleFontsVirtualId(id) {
477
- const cleanId = id.startsWith("\0") ? id.slice(1) : id;
478
- if (!cleanId.startsWith(VIRTUAL_GOOGLE_FONTS)) return null;
479
- const queryIndex = cleanId.indexOf("?");
480
- const params = new URLSearchParams(queryIndex === -1 ? "" : cleanId.slice(queryIndex + 1));
481
- return {
482
- hasDefault: params.get("default") === "1",
483
- fonts: params.get("fonts")?.split(",").map((value) => value.trim()).filter(Boolean) ?? [],
484
- utilities: params.get("utilities")?.split(",").map((value) => value.trim()).filter(Boolean) ?? []
485
- };
486
- }
487
- function generateGoogleFontsVirtualModule(id) {
488
- const payload = parseGoogleFontsVirtualId(id);
489
- if (!payload) return null;
490
- const utilities = Array.from(new Set(payload.utilities));
491
- const fonts = Array.from(new Set(payload.fonts));
492
- const lines = [];
493
- lines.push(`import { createFontLoader } from ${JSON.stringify(_fontGoogleShimPath)};`);
494
- const reExports = [];
495
- if (payload.hasDefault) reExports.push("default");
496
- reExports.push(...utilities);
497
- if (reExports.length > 0) lines.push(`export { ${reExports.join(", ")} } from ${JSON.stringify(_fontGoogleShimPath)};`);
498
- for (const fontName of fonts) {
499
- const family = fontName.replace(/_/g, " ");
500
- lines.push(`export const ${fontName} = /*#__PURE__*/ createFontLoader(${JSON.stringify(family)});`);
501
- }
502
- lines.push("");
503
- return lines.join("\n");
504
- }
505
- function propertyNameToGoogleFontFamily(prop) {
506
- return prop.replace(/_/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2");
507
- }
508
306
  /**
509
307
  * manualChunks function for client builds.
510
308
  *
@@ -554,6 +352,12 @@ const clientOutputConfig = {
554
352
  manualChunks: clientManualChunks,
555
353
  experimentalMinChunkSize: 1e4
556
354
  };
355
+ const clientCodeSplittingConfig = {
356
+ minSize: 1e4,
357
+ groups: [{ name(moduleId) {
358
+ return clientManualChunks(moduleId) ?? null;
359
+ } }]
360
+ };
557
361
  /**
558
362
  * Rollup treeshake configuration for production client builds.
559
363
  *
@@ -583,50 +387,15 @@ const clientTreeshakeConfig = {
583
387
  preset: "recommended",
584
388
  moduleSideEffects: "no-external"
585
389
  };
586
- /**
587
- * Compute the set of chunk filenames that are ONLY reachable through dynamic
588
- * imports (i.e. behind React.lazy(), next/dynamic, or manual import()).
589
- *
590
- * These chunks should NOT be modulepreloaded in the HTML — they will be
591
- * fetched on demand when the dynamic import executes.
592
- *
593
- * Algorithm: Starting from all entry chunks in the build manifest, walk the
594
- * static `imports` tree (breadth-first). Any chunk file NOT reached by this
595
- * walk is only reachable through `dynamicImports` and is therefore "lazy".
596
- *
597
- * @param buildManifest - Vite's build manifest (manifest.json), which is a
598
- * Record<string, ManifestChunk> where each chunk has `file`, `imports`,
599
- * `dynamicImports`, `isEntry`, and `isDynamicEntry` fields.
600
- * @returns Array of chunk filenames (e.g. "assets/mermaid-NOHMQCX5.js") that
601
- * should be excluded from modulepreload hints.
602
- */
603
- function computeLazyChunks(buildManifest) {
604
- const eagerFiles = /* @__PURE__ */ new Set();
605
- const visited = /* @__PURE__ */ new Set();
606
- const queue = [];
607
- for (const key of Object.keys(buildManifest)) if (buildManifest[key].isEntry) queue.push(key);
608
- while (queue.length > 0) {
609
- const key = queue.shift();
610
- if (visited.has(key)) continue;
611
- visited.add(key);
612
- const chunk = buildManifest[key];
613
- if (!chunk) continue;
614
- eagerFiles.add(chunk.file);
615
- if (chunk.css) for (const cssFile of chunk.css) eagerFiles.add(cssFile);
616
- if (chunk.imports) {
617
- for (const imp of chunk.imports) if (!visited.has(imp)) queue.push(imp);
618
- }
619
- }
620
- const lazyChunks = [];
621
- const allFiles = /* @__PURE__ */ new Set();
622
- for (const key of Object.keys(buildManifest)) {
623
- const chunk = buildManifest[key];
624
- if (chunk.file && !allFiles.has(chunk.file)) {
625
- allFiles.add(chunk.file);
626
- if (!eagerFiles.has(chunk.file) && chunk.file.endsWith(".js")) lazyChunks.push(chunk.file);
627
- }
628
- }
629
- return lazyChunks;
390
+ function getBuildBundlerOptions(build) {
391
+ const buildConfig = build;
392
+ return buildConfig?.rolldownOptions ?? buildConfig?.rollupOptions;
393
+ }
394
+ function withBuildBundlerOptions(viteMajorVersion, bundlerOptions) {
395
+ return viteMajorVersion >= 8 ? { rolldownOptions: bundlerOptions } : { rollupOptions: bundlerOptions };
396
+ }
397
+ function getClientOutputConfigForVite(viteMajorVersion) {
398
+ return viteMajorVersion >= 8 ? { codeSplitting: clientCodeSplittingConfig } : clientOutputConfig;
630
399
  }
631
400
  function tryRealpathSync(candidate) {
632
401
  try {
@@ -702,13 +471,12 @@ function vinext(options = {}) {
702
471
  let fileMatcher;
703
472
  let middlewarePath = null;
704
473
  let instrumentationPath = null;
474
+ let instrumentationClientPath = null;
705
475
  let hasCloudflarePlugin = false;
706
476
  let warnedInlineNextConfigOverride = false;
707
477
  let hasNitroPlugin = false;
708
478
  const shimsDir = path.resolve(__dirname, "shims");
709
479
  let nextShimMap = {};
710
- const _ogInlineCache = /* @__PURE__ */ new Map();
711
- let _ogInlineIsBuild = false;
712
480
  /**
713
481
  * Generate the virtual SSR server entry module.
714
482
  * This is the entry point for `vite build --ssr`.
@@ -760,187 +528,42 @@ function vinext(options = {}) {
760
528
  }
761
529
  const imageImportDimCache = /* @__PURE__ */ new Map();
762
530
  let mdxDelegate = null;
531
+ let mdxDelegatePromise = null;
532
+ let hasUserMdxPlugin = false;
533
+ let warnedMissingMdxPlugin = false;
534
+ async function ensureMdxDelegate(reason) {
535
+ if (mdxDelegate || hasUserMdxPlugin) return mdxDelegate;
536
+ if (!mdxDelegatePromise) mdxDelegatePromise = (async () => {
537
+ try {
538
+ const mdxRollup = await import("@mdx-js/rollup");
539
+ const mdxFactory = mdxRollup.default ?? mdxRollup;
540
+ const mdxOpts = {};
541
+ if (nextConfig.mdx) {
542
+ if (nextConfig.mdx.remarkPlugins) mdxOpts.remarkPlugins = nextConfig.mdx.remarkPlugins;
543
+ if (nextConfig.mdx.rehypePlugins) mdxOpts.rehypePlugins = nextConfig.mdx.rehypePlugins;
544
+ if (nextConfig.mdx.recmaPlugins) mdxOpts.recmaPlugins = nextConfig.mdx.recmaPlugins;
545
+ }
546
+ const delegate = mdxFactory(mdxOpts);
547
+ mdxDelegate = delegate;
548
+ if (reason === "detected") if (nextConfig.mdx) console.log("[vinext] Auto-injected @mdx-js/rollup with remark/rehype plugins from next.config");
549
+ else console.log("[vinext] Auto-injected @mdx-js/rollup for MDX support");
550
+ else console.log("[vinext] Auto-injected @mdx-js/rollup for on-demand MDX support");
551
+ return delegate;
552
+ } catch {
553
+ if (reason === "detected" && !warnedMissingMdxPlugin) {
554
+ warnedMissingMdxPlugin = true;
555
+ console.warn("[vinext] MDX files detected but @mdx-js/rollup is not installed. Install it with: " + detectPackageManager(process.cwd()) + " @mdx-js/rollup");
556
+ }
557
+ return null;
558
+ }
559
+ })();
560
+ return mdxDelegatePromise;
561
+ }
763
562
  const plugins = [
764
563
  ...viteMajorVersion >= 8 ? [] : [tsconfigPaths()],
765
564
  reactPluginPromise,
766
565
  commonjs(),
767
- (
768
- // @vitejs/plugin-rsc uses `periscopic` to find closure variables for
769
- {
770
- name: "vinext:fix-use-server-closure-collision",
771
- enforce: "pre",
772
- transform(code, id) {
773
- if (!code.includes("use server")) return null;
774
- if (!/\.(js|jsx|ts|tsx|mjs|cjs)$/.test(id.split("?")[0])) return null;
775
- let ast;
776
- try {
777
- ast = parseAst(code);
778
- } catch {
779
- return null;
780
- }
781
- function collectPatternNames(pattern, names) {
782
- if (!pattern) return;
783
- if (pattern.type === "Identifier") names.add(pattern.name);
784
- else if (pattern.type === "ObjectPattern") for (const prop of pattern.properties) collectPatternNames(prop.value ?? prop.argument, names);
785
- else if (pattern.type === "ArrayPattern") for (const elem of pattern.elements) collectPatternNames(elem, names);
786
- else if (pattern.type === "RestElement" || pattern.type === "AssignmentPattern") collectPatternNames(pattern.left ?? pattern.argument, names);
787
- }
788
- function hasUseServerDirective(body) {
789
- for (const stmt of body) {
790
- if (stmt.type === "ExpressionStatement" && stmt.expression?.type === "Literal" && typeof stmt.expression.value === "string") {
791
- if (stmt.expression.value === "use server") return true;
792
- continue;
793
- }
794
- break;
795
- }
796
- return false;
797
- }
798
- const s = new MagicString(code);
799
- const renamedRanges = /* @__PURE__ */ new Set();
800
- let changed = false;
801
- function visitNode(node, ancestorNames) {
802
- if (!node || typeof node !== "object") return;
803
- if (!(node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression")) {
804
- const namesForChildren = new Set(ancestorNames);
805
- if (node.type === "CatchClause" && node.param) collectPatternNames(node.param, namesForChildren);
806
- collectFunctionScopedNames(node, namesForChildren);
807
- const immediateStmts = node.type === "Program" ? node.body : node.type === "BlockStatement" ? node.body : [];
808
- for (const stmt of immediateStmts) if (stmt?.type === "VariableDeclaration") for (const decl of stmt.declarations) collectPatternNames(decl.id, namesForChildren);
809
- else if (stmt?.type === "ClassDeclaration" && stmt.id?.name) namesForChildren.add(stmt.id.name);
810
- else if (stmt?.type === "ImportDeclaration") {
811
- for (const spec of stmt.specifiers ?? []) if (spec.local?.name) namesForChildren.add(spec.local.name);
812
- }
813
- for (const key of Object.keys(node)) {
814
- if (key === "type") continue;
815
- const child = node[key];
816
- if (Array.isArray(child)) for (const c of child) visitNode(c, namesForChildren);
817
- else if (child && typeof child === "object" && child.type) visitNode(child, namesForChildren);
818
- }
819
- return;
820
- }
821
- const namesForBody = new Set(ancestorNames);
822
- for (const p of node.params ?? []) collectPatternNames(p, namesForBody);
823
- const bodyStmts = node.body?.type === "BlockStatement" ? node.body.body : [];
824
- if (hasUseServerDirective(bodyStmts)) {
825
- const localDecls = /* @__PURE__ */ new Set();
826
- collectAllDeclaredNames(node.body, localDecls);
827
- const collisionRenames = /* @__PURE__ */ new Map();
828
- for (const name of localDecls) if (namesForBody.has(name)) {
829
- let to = `__local_${name}`;
830
- let suffix = 0;
831
- while (localDecls.has(to) || namesForBody.has(to)) {
832
- to = `__local_${suffix}_${name}`;
833
- suffix++;
834
- }
835
- collisionRenames.set(name, to);
836
- }
837
- if (collisionRenames.size > 0) {
838
- for (const [name, to] of collisionRenames) renamingWalk(node.body, name, to);
839
- changed = true;
840
- }
841
- const namesForChildren = new Set(namesForBody);
842
- for (const name of localDecls) if (collisionRenames.has(name)) {
843
- namesForChildren.delete(name);
844
- namesForChildren.add(collisionRenames.get(name));
845
- } else namesForChildren.add(name);
846
- for (const stmt of bodyStmts) visitNode(stmt, namesForChildren);
847
- for (const p of node.params ?? []) visitNode(p, ancestorNames);
848
- return;
849
- }
850
- const namesForChildren = new Set(namesForBody);
851
- collectFunctionScopedNames(node.body, namesForChildren);
852
- for (const stmt of bodyStmts) if (stmt?.type === "VariableDeclaration" && stmt.kind !== "var") for (const decl of stmt.declarations) collectPatternNames(decl.id, namesForChildren);
853
- for (const key of Object.keys(node)) {
854
- if (key === "type") continue;
855
- const child = node[key];
856
- if (Array.isArray(child)) for (const c of child) visitNode(c, namesForChildren);
857
- else if (child && typeof child === "object" && child.type) visitNode(child, namesForChildren);
858
- }
859
- }
860
- function renamingWalk(node, from, to, parent) {
861
- if (!node || typeof node !== "object") return;
862
- if (node.type === "Identifier" && node.name === from) {
863
- if (parent?.type === "MemberExpression" && parent.property === node && !parent.computed) return;
864
- if (parent?.type === "Property" && parent.key === node && !parent.computed) {
865
- if (parent.shorthand) {
866
- const rangeKey = `${node.start}:${node.end}`;
867
- if (!renamedRanges.has(rangeKey)) {
868
- renamedRanges.add(rangeKey);
869
- s.update(node.start, node.end, `${from}: ${to}`);
870
- }
871
- }
872
- return;
873
- }
874
- if (parent?.type === "Property" && parent.shorthand && parent.value === node) return;
875
- if (parent?.type === "LabeledStatement" && parent.label === node) return;
876
- if ((parent?.type === "BreakStatement" || parent?.type === "ContinueStatement") && parent.label === node) return;
877
- const rangeKey = `${node.start}:${node.end}`;
878
- if (!renamedRanges.has(rangeKey)) {
879
- renamedRanges.add(rangeKey);
880
- s.update(node.start, node.end, to);
881
- }
882
- return;
883
- }
884
- if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
885
- const nestedDecls = /* @__PURE__ */ new Set();
886
- for (const p of node.params ?? []) collectPatternNames(p, nestedDecls);
887
- collectAllDeclaredNames(node.body, nestedDecls);
888
- if (nestedDecls.has(from)) return;
889
- if (node.body?.type === "BlockStatement" && hasUseServerDirective(node.body.body)) return;
890
- }
891
- for (const key of Object.keys(node)) {
892
- if (key === "type" || key === "start" || key === "end") continue;
893
- const child = node[key];
894
- if (Array.isArray(child)) for (const c of child) renamingWalk(c, from, to, node);
895
- else if (child && typeof child === "object" && child.type) renamingWalk(child, from, to, node);
896
- }
897
- }
898
- function collectFunctionScopedNames(node, names) {
899
- if (!node || typeof node !== "object") return;
900
- if (node.type === "FunctionDeclaration") {
901
- if (node.id?.name) names.add(node.id.name);
902
- return;
903
- }
904
- if (node.type === "ClassDeclaration") {
905
- if (node.id?.name) names.add(node.id.name);
906
- return;
907
- }
908
- if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") return;
909
- if (node.type === "VariableDeclaration" && node.kind === "var") for (const decl of node.declarations) collectPatternNames(decl.id, names);
910
- for (const key of Object.keys(node)) {
911
- if (key === "type") continue;
912
- const child = node[key];
913
- if (Array.isArray(child)) for (const c of child) collectFunctionScopedNames(c, names);
914
- else if (child && typeof child === "object" && child.type) collectFunctionScopedNames(child, names);
915
- }
916
- }
917
- function collectAllDeclaredNames(node, names) {
918
- if (!node || typeof node !== "object") return;
919
- if (node.type === "VariableDeclaration") for (const decl of node.declarations) collectPatternNames(decl.id, names);
920
- if (node.type === "FunctionDeclaration") {
921
- if (node.id?.name) names.add(node.id.name);
922
- return;
923
- }
924
- if (node.type === "ClassDeclaration") {
925
- if (node.id?.name) names.add(node.id.name);
926
- return;
927
- }
928
- if (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") return;
929
- for (const key of Object.keys(node)) {
930
- if (key === "type") continue;
931
- const child = node[key];
932
- if (Array.isArray(child)) for (const c of child) collectAllDeclaredNames(c, names);
933
- else if (child && typeof child === "object" && child.type) collectAllDeclaredNames(child, names);
934
- }
935
- }
936
- visitNode(ast, /* @__PURE__ */ new Set());
937
- if (!changed) return null;
938
- return {
939
- code: s.toString(),
940
- map: s.generateMap({ hires: "boundary" })
941
- };
942
- }
943
- }),
566
+ fixUseServerClosureCollisionPlugin,
944
567
  {
945
568
  name: "vinext:config",
946
569
  enforce: "pre",
@@ -972,19 +595,22 @@ function vinext(options = {}) {
972
595
  appDir = path.join(baseDir, "app");
973
596
  hasPagesDir = fs.existsSync(pagesDir);
974
597
  hasAppDir = !options.disableAppRouter && fs.existsSync(appDir);
975
- const phase = env?.command === "build" ? PHASE_PRODUCTION_BUILD : PHASE_DEVELOPMENT_SERVER;
976
- let rawConfig;
977
- if (options.nextConfig) {
978
- const diskConfigPath = findNextConfigPath(root);
979
- if (diskConfigPath && !warnedInlineNextConfigOverride) {
980
- warnedInlineNextConfigOverride = true;
981
- console.warn(`[vinext] vinext({ nextConfig }) overrides ${path.basename(diskConfigPath)}. Remove one of the config sources to avoid drift.`);
982
- }
983
- rawConfig = await resolveNextConfigInput(options.nextConfig, phase);
984
- } else rawConfig = await loadNextConfig(root, phase);
985
- nextConfig = await resolveNextConfig(rawConfig, root);
598
+ if (!nextConfig) {
599
+ const phase = env?.command === "build" ? PHASE_PRODUCTION_BUILD : PHASE_DEVELOPMENT_SERVER;
600
+ let rawConfig;
601
+ if (options.nextConfig) {
602
+ const diskConfigPath = findNextConfigPath(root);
603
+ if (diskConfigPath && !warnedInlineNextConfigOverride) {
604
+ warnedInlineNextConfigOverride = true;
605
+ console.warn(`[vinext] vinext({ nextConfig }) overrides ${path.basename(diskConfigPath)}. Remove one of the config sources to avoid drift.`);
606
+ }
607
+ rawConfig = await resolveNextConfigInput(options.nextConfig, phase);
608
+ } else rawConfig = await loadNextConfig(root, phase);
609
+ nextConfig = await resolveNextConfig(rawConfig, root);
610
+ }
986
611
  fileMatcher = createValidFileMatcher(nextConfig.pageExtensions);
987
612
  instrumentationPath = findInstrumentationFile(root, fileMatcher);
613
+ instrumentationClientPath = findInstrumentationClientFile(root, fileMatcher);
988
614
  middlewarePath = findMiddlewareFile(root, fileMatcher);
989
615
  const defines = getNextPublicEnvDefines();
990
616
  if (!config.define || typeof config.define !== "object" || !("process.env.NODE_ENV" in config.define)) defines["process.env.NODE_ENV"] = JSON.stringify(resolvedNodeEnv);
@@ -1072,8 +698,11 @@ function vinext(options = {}) {
1072
698
  "vinext/head-state": path.join(shimsDir, "head-state"),
1073
699
  "vinext/i18n-state": path.join(shimsDir, "i18n-state"),
1074
700
  "vinext/i18n-context": path.join(shimsDir, "i18n-context"),
701
+ "vinext/cache": path.resolve(__dirname, "cache"),
1075
702
  "vinext/instrumentation": path.resolve(__dirname, "server", "instrumentation"),
1076
- "vinext/html": path.resolve(__dirname, "server", "html")
703
+ "vinext/instrumentation-client": path.resolve(__dirname, "client", "instrumentation-client"),
704
+ "vinext/html": path.resolve(__dirname, "server", "html"),
705
+ "private-next-instrumentation-client": instrumentationClientPath ?? path.resolve(__dirname, "client", "empty-module")
1077
706
  }).flatMap(([k, v]) => k.startsWith("next/") ? [[k, v], [`${k}.js`, v]] : [[k, v]]));
1078
707
  const pluginsFlat = [];
1079
708
  function flattenPlugins(arr) {
@@ -1081,32 +710,19 @@ function vinext(options = {}) {
1081
710
  else if (p) pluginsFlat.push(p);
1082
711
  }
1083
712
  flattenPlugins(config.plugins ?? []);
1084
- hasCloudflarePlugin = pluginsFlat.some((p) => p && typeof p === "object" && typeof p.name === "string" && (p.name === "vite-plugin-cloudflare" || p.name.startsWith("vite-plugin-cloudflare:")));
1085
- hasNitroPlugin = pluginsFlat.some((p) => p && typeof p === "object" && typeof p.name === "string" && (p.name === "nitro" || p.name.startsWith("nitro:")));
713
+ hasCloudflarePlugin = pluginsFlat.some((p) => p && typeof p === "object" && "name" in p && typeof p.name === "string" && (p.name === "vite-plugin-cloudflare" || p.name.startsWith("vite-plugin-cloudflare:")));
714
+ hasNitroPlugin = pluginsFlat.some((p) => p && typeof p === "object" && "name" in p && typeof p.name === "string" && (p.name === "nitro" || p.name.startsWith("nitro:")));
1086
715
  let postcssOverride;
1087
716
  if (!config.css?.postcss || typeof config.css.postcss === "string") postcssOverride = await resolvePostcssStringPlugins(root);
1088
- if (!pluginsFlat.some((p) => p && typeof p === "object" && typeof p.name === "string" && (p.name === "@mdx-js/rollup" || p.name === "mdx")) && hasMdxFiles(root, hasAppDir ? appDir : null, hasPagesDir ? pagesDir : null)) try {
1089
- const mdxRollup = await import("@mdx-js/rollup");
1090
- const mdxFactory = mdxRollup.default ?? mdxRollup;
1091
- const mdxOpts = {};
1092
- if (nextConfig.mdx) {
1093
- if (nextConfig.mdx.remarkPlugins) mdxOpts.remarkPlugins = nextConfig.mdx.remarkPlugins;
1094
- if (nextConfig.mdx.rehypePlugins) mdxOpts.rehypePlugins = nextConfig.mdx.rehypePlugins;
1095
- if (nextConfig.mdx.recmaPlugins) mdxOpts.recmaPlugins = nextConfig.mdx.recmaPlugins;
1096
- }
1097
- mdxDelegate = mdxFactory(mdxOpts);
1098
- if (nextConfig.mdx) console.log("[vinext] Auto-injected @mdx-js/rollup with remark/rehype plugins from next.config");
1099
- else console.log("[vinext] Auto-injected @mdx-js/rollup for MDX support");
1100
- } catch {
1101
- console.warn("[vinext] MDX files detected but @mdx-js/rollup is not installed. Install it with: " + detectPackageManager(process.cwd()) + " @mdx-js/rollup");
1102
- }
717
+ hasUserMdxPlugin = pluginsFlat.some((p) => p && typeof p === "object" && "name" in p && typeof p.name === "string" && (p.name === "@mdx-js/rollup" || p.name === "mdx"));
718
+ if (!hasUserMdxPlugin && hasMdxFiles(root, hasAppDir ? appDir : null, hasPagesDir ? pagesDir : null)) await ensureMdxDelegate("detected");
1103
719
  const isSSR = !!config.build?.ssr;
1104
720
  const isMultiEnv = hasAppDir || hasCloudflarePlugin || hasNitroPlugin;
1105
721
  const viteConfig = {
1106
722
  appType: "custom",
1107
- build: { rollupOptions: {
723
+ build: { ...withBuildBundlerOptions(viteMajorVersion, {
1108
724
  onwarn: (() => {
1109
- const userOnwarn = config.build?.rollupOptions?.onwarn;
725
+ const userOnwarn = getBuildBundlerOptions(config.build)?.onwarn;
1110
726
  return (warning, defaultHandler) => {
1111
727
  if (warning.code === "MODULE_LEVEL_DIRECTIVE" && (warning.message?.includes("\"use client\"") || warning.message?.includes("\"use server\""))) return;
1112
728
  if (warning.code === "IMPORT_IS_UNDEFINED" && warning.message?.includes("generateStaticParams")) return;
@@ -1115,8 +731,8 @@ function vinext(options = {}) {
1115
731
  };
1116
732
  })(),
1117
733
  ...!isSSR && !isMultiEnv ? { treeshake: clientTreeshakeConfig } : {},
1118
- ...!isSSR && !isMultiEnv ? { output: clientOutputConfig } : {}
1119
- } },
734
+ ...!isSSR && !isMultiEnv ? { output: getClientOutputConfigForVite(viteMajorVersion) } : {}
735
+ }) },
1120
736
  server: { cors: {
1121
737
  preflightContinue: true,
1122
738
  origin: /^https?:\/\/(?:(?:[^:]+\.)?localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/
@@ -1160,8 +776,11 @@ function vinext(options = {}) {
1160
776
  ])],
1161
777
  ...incomingInclude.length > 0 ? { include: incomingInclude } : {}
1162
778
  };
779
+ const pagesOptimizeEntries = !hasAppDir ? [...hasPagesDir ? [toRelativeFileEntry(root, pagesDir) + "/**/*.{tsx,ts,jsx,js}"] : [], ...[instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : [])] : [];
1163
780
  if (hasAppDir) {
1164
781
  const appEntries = [`${path.relative(root, appDir)}/**/*.{tsx,ts,jsx,js}`];
782
+ const explicitInstrumentationEntries = [instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : []);
783
+ const optimizeEntries = [...new Set([...appEntries, ...explicitInstrumentationEntries])];
1165
784
  viteConfig.environments = {
1166
785
  rsc: {
1167
786
  ...hasCloudflarePlugin || hasNitroPlugin ? {} : { resolve: {
@@ -1179,11 +798,11 @@ function vinext(options = {}) {
1179
798
  "vinext",
1180
799
  "@vercel/og"
1181
800
  ])],
1182
- entries: appEntries
801
+ entries: optimizeEntries
1183
802
  },
1184
803
  build: {
1185
804
  outDir: options.rscOutDir ?? "dist/server",
1186
- rollupOptions: { input: { index: VIRTUAL_RSC_ENTRY } }
805
+ ...withBuildBundlerOptions(viteMajorVersion, { input: { index: VIRTUAL_RSC_ENTRY } })
1187
806
  }
1188
807
  },
1189
808
  ssr: {
@@ -1197,11 +816,11 @@ function vinext(options = {}) {
1197
816
  "vinext",
1198
817
  "@vercel/og"
1199
818
  ])],
1200
- entries: appEntries
819
+ entries: optimizeEntries
1201
820
  },
1202
821
  build: {
1203
822
  outDir: options.ssrOutDir ?? "dist/server/ssr",
1204
- rollupOptions: { input: { index: VIRTUAL_APP_SSR_ENTRY } }
823
+ ...withBuildBundlerOptions(viteMajorVersion, { input: { index: VIRTUAL_APP_SSR_ENTRY } })
1205
824
  }
1206
825
  },
1207
826
  client: {
@@ -1213,7 +832,7 @@ function vinext(options = {}) {
1213
832
  "@vercel/og",
1214
833
  ...nextServerExternal
1215
834
  ])],
1216
- entries: appEntries,
835
+ entries: optimizeEntries,
1217
836
  include: [...new Set([
1218
837
  ...incomingInclude,
1219
838
  "react",
@@ -1225,39 +844,77 @@ function vinext(options = {}) {
1225
844
  },
1226
845
  build: {
1227
846
  ...hasCloudflarePlugin ? { manifest: true } : {},
1228
- rollupOptions: {
847
+ ...withBuildBundlerOptions(viteMajorVersion, {
1229
848
  input: { index: VIRTUAL_APP_BROWSER_ENTRY },
1230
- output: clientOutputConfig,
849
+ output: getClientOutputConfigForVite(viteMajorVersion),
1231
850
  treeshake: clientTreeshakeConfig
1232
- }
851
+ })
1233
852
  }
1234
853
  }
1235
854
  };
1236
855
  } else if (hasCloudflarePlugin) viteConfig.environments = { client: {
1237
856
  consumer: "client",
857
+ optimizeDeps: pagesOptimizeEntries.length > 0 ? { entries: pagesOptimizeEntries } : void 0,
1238
858
  build: {
1239
859
  manifest: true,
1240
860
  ssrManifest: true,
1241
- rollupOptions: {
861
+ ...withBuildBundlerOptions(viteMajorVersion, {
1242
862
  input: { index: VIRTUAL_CLIENT_ENTRY },
1243
- output: clientOutputConfig,
863
+ output: getClientOutputConfigForVite(viteMajorVersion),
1244
864
  treeshake: clientTreeshakeConfig
1245
- }
865
+ })
1246
866
  }
1247
867
  } };
868
+ else if (!isSSR && !getBuildBundlerOptions(config.build)?.input) viteConfig.environments = {
869
+ client: {
870
+ consumer: "client",
871
+ optimizeDeps: pagesOptimizeEntries.length > 0 ? { entries: pagesOptimizeEntries } : void 0,
872
+ build: {
873
+ outDir: "dist/client",
874
+ manifest: true,
875
+ ssrManifest: true,
876
+ ...withBuildBundlerOptions(viteMajorVersion, {
877
+ input: { index: VIRTUAL_CLIENT_ENTRY },
878
+ output: getClientOutputConfigForVite(viteMajorVersion),
879
+ treeshake: clientTreeshakeConfig
880
+ })
881
+ }
882
+ },
883
+ ssr: {
884
+ resolve: {
885
+ external: [
886
+ "react",
887
+ "react-dom",
888
+ "react-dom/server"
889
+ ],
890
+ noExternal: true
891
+ },
892
+ build: {
893
+ outDir: "dist/server",
894
+ ...withBuildBundlerOptions(viteMajorVersion, {
895
+ input: { index: VIRTUAL_SERVER_ENTRY },
896
+ output: { entryFileNames: "entry.js" }
897
+ })
898
+ }
899
+ }
900
+ };
901
+ if (pagesOptimizeEntries.length > 0 && !hasCloudflarePlugin) viteConfig.optimizeDeps = {
902
+ ...viteConfig.optimizeDeps,
903
+ entries: pagesOptimizeEntries
904
+ };
1248
905
  return viteConfig;
1249
906
  },
1250
907
  configResolved(config) {
1251
908
  // @vitejs/plugin-react AND the user also registers it manually, the
1252
909
  if (reactPluginPromise) {
1253
- const reactRootPlugins = config.plugins.filter((p) => p && typeof p.name === "string" && p.name.startsWith("vite:react"));
910
+ const reactRootPlugins = config.plugins.filter((p) => p && typeof p === "object" && "name" in p && typeof p.name === "string" && p.name.startsWith("vite:react"));
1254
911
  const counts = /* @__PURE__ */ new Map();
1255
912
  for (const plugin of reactRootPlugins) counts.set(plugin.name, (counts.get(plugin.name) ?? 0) + 1);
1256
913
  if ([...counts.values()].some((count) => count > 1)) throw new Error("[vinext] Duplicate @vitejs/plugin-react detected.\n vinext auto-registers @vitejs/plugin-react by default.\n Your config also registers it manually, which duplicates React transforms.\n\n Fix: remove the explicit react() call from your plugins array.\n Or: pass react: false to vinext() if you want to configure react() yourself.");
1257
914
  }
1258
915
  // @vitejs/plugin-rsc AND the user also registers it manually, the
1259
916
  if (rscPluginPromise) {
1260
- if (config.plugins.filter((p) => p && p.name === "rsc").length > 1) throw new Error("[vinext] Duplicate @vitejs/plugin-rsc detected.\n vinext auto-registers @vitejs/plugin-rsc when app/ is detected.\n Your config also registers it manually, which doubles build time.\n\n Fix: remove the explicit rsc() call from your plugins array.\n Or: pass rsc: false to vinext() if you want to configure rsc() yourself.");
917
+ if (config.plugins.filter((p) => p && typeof p === "object" && "name" in p && p.name === "rsc").length > 1) throw new Error("[vinext] Duplicate @vitejs/plugin-rsc detected.\n vinext auto-registers @vitejs/plugin-rsc when app/ is detected.\n Your config also registers it manually, which doubles build time.\n\n Fix: remove the explicit rsc() call from your plugins array.\n Or: pass rsc: false to vinext() if you want to configure rsc() yourself.");
1261
918
  }
1262
919
  if (config.command === "build" && !hasCloudflarePlugin && !hasNitroPlugin && hasWranglerConfig(root) && !options.disableAppRouter) throw new Error(formatMissingCloudflarePluginError({
1263
920
  isAppRouter: hasAppDir,
@@ -1275,13 +932,13 @@ function vinext(options = {}) {
1275
932
  if (cleanId === VIRTUAL_RSC_ENTRY) return RESOLVED_RSC_ENTRY;
1276
933
  if (cleanId === VIRTUAL_APP_SSR_ENTRY) return RESOLVED_APP_SSR_ENTRY;
1277
934
  if (cleanId === VIRTUAL_APP_BROWSER_ENTRY) return RESOLVED_APP_BROWSER_ENTRY;
1278
- if (cleanId.startsWith(VIRTUAL_GOOGLE_FONTS + "?")) return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(27);
935
+ if (cleanId.startsWith("virtual:vinext-google-fonts?")) return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(VIRTUAL_GOOGLE_FONTS.length);
1279
936
  if (cleanId.endsWith("/" + VIRTUAL_RSC_ENTRY) || cleanId.endsWith("\\" + VIRTUAL_RSC_ENTRY)) return RESOLVED_RSC_ENTRY;
1280
937
  if (cleanId.endsWith("/" + VIRTUAL_APP_SSR_ENTRY) || cleanId.endsWith("\\" + VIRTUAL_APP_SSR_ENTRY)) return RESOLVED_APP_SSR_ENTRY;
1281
938
  if (cleanId.endsWith("/" + VIRTUAL_APP_BROWSER_ENTRY) || cleanId.endsWith("\\" + VIRTUAL_APP_BROWSER_ENTRY)) return RESOLVED_APP_BROWSER_ENTRY;
1282
- if (cleanId.includes("/" + VIRTUAL_GOOGLE_FONTS + "?") || cleanId.includes("\\" + VIRTUAL_GOOGLE_FONTS + "?")) {
939
+ if (cleanId.includes("/virtual:vinext-google-fonts?") || cleanId.includes("\\virtual:vinext-google-fonts?")) {
1283
940
  const queryIndex = cleanId.indexOf(VIRTUAL_GOOGLE_FONTS + "?");
1284
- return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(queryIndex + 27);
941
+ return RESOLVED_VIRTUAL_GOOGLE_FONTS + cleanId.slice(queryIndex + VIRTUAL_GOOGLE_FONTS.length);
1285
942
  }
1286
943
  }
1287
944
  },
@@ -1305,10 +962,11 @@ function vinext(options = {}) {
1305
962
  }
1306
963
  if (id === RESOLVED_APP_SSR_ENTRY && hasAppDir) return generateSsrEntry(hasPagesDir);
1307
964
  if (id === RESOLVED_APP_BROWSER_ENTRY && hasAppDir) return generateBrowserEntry();
1308
- if (id.startsWith(RESOLVED_VIRTUAL_GOOGLE_FONTS + "?")) return generateGoogleFontsVirtualModule(id);
965
+ if (id.startsWith("\0virtual:vinext-google-fonts?")) return generateGoogleFontsVirtualModule(id, _fontGoogleShimPath);
1309
966
  }
1310
967
  },
1311
968
  asyncHooksStubPlugin,
969
+ createInstrumentationClientTransformPlugin(() => instrumentationClientPath),
1312
970
  ...options.experimental?.clientReferenceDedup ? [clientReferenceDedupPlugin()] : [],
1313
971
  {
1314
972
  name: "vinext:mdx",
@@ -1318,11 +976,15 @@ function vinext(options = {}) {
1318
976
  const hook = mdxDelegate.config;
1319
977
  return (typeof hook === "function" ? hook : hook.handler).call(this, config, env);
1320
978
  },
1321
- transform(code, id, options) {
979
+ async transform(code, id, options) {
1322
980
  if (id.includes("?")) return;
1323
- if (!mdxDelegate?.transform) return;
1324
- const hook = mdxDelegate.transform;
1325
- return (typeof hook === "function" ? hook : hook.handler).call(this, code, id, options);
981
+ if (!id.toLowerCase().endsWith(".mdx")) return;
982
+ const delegate = mdxDelegate ?? await ensureMdxDelegate("on-demand");
983
+ if (delegate?.transform) {
984
+ const hook = delegate.transform;
985
+ return (typeof hook === "function" ? hook : hook.handler).call(this, code, id, options);
986
+ }
987
+ if (!hasUserMdxPlugin) throw new Error(`[vinext] Encountered MDX module ${id} but no MDX plugin is configured. Install @mdx-js/rollup or register an MDX plugin manually.`);
1326
988
  }
1327
989
  },
1328
990
  {
@@ -1522,7 +1184,7 @@ function vinext(options = {}) {
1522
1184
  return;
1523
1185
  }
1524
1186
  try {
1525
- pathname = normalizePath(normalizePathnameForRouteMatchStrict(pathname));
1187
+ pathname = normalizePath$1(normalizePathnameForRouteMatchStrict(pathname));
1526
1188
  } catch {
1527
1189
  res.writeHead(400);
1528
1190
  res.end("Bad Request");
@@ -1575,6 +1237,7 @@ function vinext(options = {}) {
1575
1237
  headers: nodeRequestHeaders
1576
1238
  });
1577
1239
  const result = await runMiddleware(getPagesRunner(), middlewarePath, middlewareRequest, nextConfig?.i18n, nextConfig?.basePath);
1240
+ if (result.waitUntilPromises?.length) Promise.allSettled(result.waitUntilPromises);
1578
1241
  if (!result.continue) {
1579
1242
  if (result.redirectUrl) {
1580
1243
  const redirectHeaders = { Location: result.redirectUrl };
@@ -1781,198 +1444,8 @@ function vinext(options = {}) {
1781
1444
  }
1782
1445
  }
1783
1446
  },
1784
- {
1785
- name: "vinext:google-fonts",
1786
- enforce: "pre",
1787
- _isBuild: false,
1788
- _fontCache: /* @__PURE__ */ new Map(),
1789
- _cacheDir: "",
1790
- configResolved(config) {
1791
- this._isBuild = config.command === "build";
1792
- this._cacheDir = path.join(config.root, ".vinext", "fonts");
1793
- },
1794
- transform: {
1795
- filter: {
1796
- id: { include: /\.(tsx?|jsx?|mjs)$/ },
1797
- code: "next/font/google"
1798
- },
1799
- async handler(code, id) {
1800
- if (id.startsWith("\0")) return null;
1801
- if (!id.match(/\.(tsx?|jsx?|mjs)$/)) return null;
1802
- if (!code.includes("next/font/google")) return null;
1803
- if (id.startsWith(_shimsDir)) return null;
1804
- const s = new MagicString(code);
1805
- let hasChanges = false;
1806
- let proxyImportCounter = 0;
1807
- const overwrittenRanges = [];
1808
- const fontLocals = /* @__PURE__ */ new Map();
1809
- const proxyObjectLocals = /* @__PURE__ */ new Set();
1810
- const importRe = /^[ \t]*import\s+([^;]+?)\s+from\s*(["'])next\/font\/google\2\s*;?/gm;
1811
- let importMatch;
1812
- while ((importMatch = importRe.exec(code)) !== null) {
1813
- const [fullMatch, clause] = importMatch;
1814
- const matchStart = importMatch.index;
1815
- const matchEnd = matchStart + fullMatch.length;
1816
- const parsed = parseGoogleFontImportClause(clause);
1817
- const utilityImports = parsed.named.filter((spec) => !spec.isType && GOOGLE_FONT_UTILITY_EXPORTS.has(spec.imported));
1818
- const fontImports = parsed.named.filter((spec) => !spec.isType && !GOOGLE_FONT_UTILITY_EXPORTS.has(spec.imported));
1819
- if (parsed.defaultLocal) proxyObjectLocals.add(parsed.defaultLocal);
1820
- for (const fontImport of fontImports) fontLocals.set(fontImport.local, fontImport.imported);
1821
- if (fontImports.length > 0) {
1822
- const virtualId = encodeGoogleFontsVirtualId({
1823
- hasDefault: Boolean(parsed.defaultLocal),
1824
- fonts: Array.from(new Set(fontImports.map((spec) => spec.imported))),
1825
- utilities: Array.from(new Set(utilityImports.map((spec) => spec.imported)))
1826
- });
1827
- s.overwrite(matchStart, matchEnd, `import ${clause} from ${JSON.stringify(virtualId)};`);
1828
- overwrittenRanges.push([matchStart, matchEnd]);
1829
- hasChanges = true;
1830
- continue;
1831
- }
1832
- if (parsed.namespaceLocal) {
1833
- const proxyImportName = `__vinext_google_fonts_proxy_${proxyImportCounter++}`;
1834
- const replacementLines = [`import ${proxyImportName} from ${JSON.stringify(_fontGoogleShimPath)};`];
1835
- if (parsed.defaultLocal) replacementLines.push(`var ${parsed.defaultLocal} = ${proxyImportName};`);
1836
- replacementLines.push(`var ${parsed.namespaceLocal} = ${proxyImportName};`);
1837
- s.overwrite(matchStart, matchEnd, replacementLines.join("\n"));
1838
- overwrittenRanges.push([matchStart, matchEnd]);
1839
- proxyObjectLocals.add(parsed.namespaceLocal);
1840
- hasChanges = true;
1841
- }
1842
- }
1843
- const exportRe = /^[ \t]*export\s*\{([^}]+)\}\s*from\s*(["'])next\/font\/google\2\s*;?/gm;
1844
- let exportMatch;
1845
- while ((exportMatch = exportRe.exec(code)) !== null) {
1846
- const [fullMatch, specifiers] = exportMatch;
1847
- const matchStart = exportMatch.index;
1848
- const matchEnd = matchStart + fullMatch.length;
1849
- const namedExports = parseGoogleFontNamedSpecifiers(specifiers);
1850
- const utilityExports = namedExports.filter((spec) => !spec.isType && GOOGLE_FONT_UTILITY_EXPORTS.has(spec.imported));
1851
- const fontExports = namedExports.filter((spec) => !spec.isType && !GOOGLE_FONT_UTILITY_EXPORTS.has(spec.imported));
1852
- if (fontExports.length === 0) continue;
1853
- const virtualId = encodeGoogleFontsVirtualId({
1854
- hasDefault: false,
1855
- fonts: Array.from(new Set(fontExports.map((spec) => spec.imported))),
1856
- utilities: Array.from(new Set(utilityExports.map((spec) => spec.imported)))
1857
- });
1858
- s.overwrite(matchStart, matchEnd, `export { ${specifiers.trim()} } from ${JSON.stringify(virtualId)};`);
1859
- overwrittenRanges.push([matchStart, matchEnd]);
1860
- hasChanges = true;
1861
- }
1862
- const cacheDir = this._cacheDir;
1863
- const fontCache = this._fontCache;
1864
- async function injectSelfHostedCss(callStart, callEnd, optionsStr, family, calleeSource) {
1865
- let options = {};
1866
- try {
1867
- const parsed = parseStaticObjectLiteral(optionsStr);
1868
- if (!parsed) return;
1869
- options = parsed;
1870
- } catch {
1871
- return;
1872
- }
1873
- const weights = options.weight ? Array.isArray(options.weight) ? options.weight : [options.weight] : [];
1874
- const styles = options.style ? Array.isArray(options.style) ? options.style : [options.style] : [];
1875
- const display = options.display ?? "swap";
1876
- let spec = family.replace(/\s+/g, "+");
1877
- if (weights.length > 0) if (styles.includes("italic")) {
1878
- const pairs = [];
1879
- for (const w of weights) {
1880
- pairs.push(`0,${w}`);
1881
- pairs.push(`1,${w}`);
1882
- }
1883
- spec += `:ital,wght@${pairs.join(";")}`;
1884
- } else spec += `:wght@${weights.join(";")}`;
1885
- else if (styles.length === 0) spec += `:wght@100..900`;
1886
- const params = new URLSearchParams();
1887
- params.set("family", spec);
1888
- params.set("display", display);
1889
- const cssUrl = `https://fonts.googleapis.com/css2?${params.toString()}`;
1890
- let localCSS = fontCache.get(cssUrl);
1891
- if (!localCSS) try {
1892
- localCSS = await fetchAndCacheFont(cssUrl, family, cacheDir);
1893
- fontCache.set(cssUrl, localCSS);
1894
- } catch {
1895
- return;
1896
- }
1897
- const escapedCSS = JSON.stringify(localCSS);
1898
- const closingBrace = optionsStr.lastIndexOf("}");
1899
- const replacement = `${calleeSource}(${optionsStr.slice(0, closingBrace) + (optionsStr.slice(0, closingBrace).trim().endsWith("{") ? "" : ", ") + `_selfHostedCSS: ${escapedCSS}` + optionsStr.slice(closingBrace)})`;
1900
- s.overwrite(callStart, callEnd, replacement);
1901
- hasChanges = true;
1902
- }
1903
- if (this._isBuild) {
1904
- const namedCallRe = /\b([A-Za-z_$][A-Za-z0-9_$]*)\s*\(\s*(\{[^}]*\})\s*\)/g;
1905
- let namedCallMatch;
1906
- while ((namedCallMatch = namedCallRe.exec(code)) !== null) {
1907
- const [fullMatch, localName, optionsStr] = namedCallMatch;
1908
- const importedName = fontLocals.get(localName);
1909
- if (!importedName) continue;
1910
- const callStart = namedCallMatch.index;
1911
- const callEnd = callStart + fullMatch.length;
1912
- if (overwrittenRanges.some(([start, end]) => callStart < end && callEnd > start)) continue;
1913
- await injectSelfHostedCss(callStart, callEnd, optionsStr, importedName.replace(/_/g, " "), localName);
1914
- }
1915
- const memberCallRe = /\b([A-Za-z_$][A-Za-z0-9_$]*)\.([A-Za-z_$][A-Za-z0-9_$]*)\s*\(\s*(\{[^}]*\})\s*\)/g;
1916
- let memberCallMatch;
1917
- while ((memberCallMatch = memberCallRe.exec(code)) !== null) {
1918
- const [fullMatch, objectName, propName, optionsStr] = memberCallMatch;
1919
- if (!proxyObjectLocals.has(objectName)) continue;
1920
- const callStart = memberCallMatch.index;
1921
- const callEnd = callStart + fullMatch.length;
1922
- if (overwrittenRanges.some(([start, end]) => callStart < end && callEnd > start)) continue;
1923
- await injectSelfHostedCss(callStart, callEnd, optionsStr, propertyNameToGoogleFontFamily(propName), `${objectName}.${propName}`);
1924
- }
1925
- }
1926
- if (!hasChanges) return null;
1927
- return {
1928
- code: s.toString(),
1929
- map: s.generateMap({ hires: "boundary" })
1930
- };
1931
- }
1932
- }
1933
- },
1934
- {
1935
- name: "vinext:local-fonts",
1936
- enforce: "pre",
1937
- transform: {
1938
- filter: {
1939
- id: {
1940
- include: /\.(tsx?|jsx?|mjs)$/,
1941
- exclude: /node_modules/
1942
- },
1943
- code: "next/font/local"
1944
- },
1945
- handler(code, id) {
1946
- if (id.includes("node_modules")) return null;
1947
- if (id.startsWith("\0")) return null;
1948
- if (!id.match(/\.(tsx?|jsx?|mjs)$/)) return null;
1949
- if (!code.includes("next/font/local")) return null;
1950
- if (id.includes("font-local")) return null;
1951
- if (!/import\s+\w+\s+from\s*['"]next\/font\/local['"]/.test(code)) return null;
1952
- const s = new MagicString(code);
1953
- let hasChanges = false;
1954
- let fontImportCounter = 0;
1955
- const imports = [];
1956
- const fontPathRe = /((?:path|src)\s*:\s*)(['"])([^'"]+\.(?:woff2?|ttf|otf|eot))\2/g;
1957
- let match;
1958
- while ((match = fontPathRe.exec(code)) !== null) {
1959
- const [fullMatch, prefix, _quote, fontPath] = match;
1960
- const varName = `__vinext_local_font_${fontImportCounter++}`;
1961
- imports.push(`import ${varName} from ${JSON.stringify(fontPath)};`);
1962
- const matchStart = match.index;
1963
- const matchEnd = matchStart + fullMatch.length;
1964
- s.overwrite(matchStart, matchEnd, `${prefix}${varName}`);
1965
- hasChanges = true;
1966
- }
1967
- if (!hasChanges) return null;
1968
- s.prepend(imports.join("\n") + "\n");
1969
- return {
1970
- code: s.toString(),
1971
- map: s.generateMap({ hires: "boundary" })
1972
- };
1973
- }
1974
- }
1975
- },
1447
+ createGoogleFontsPlugin(_fontGoogleShimPath, _shimsDir),
1448
+ createLocalFontsPlugin(),
1976
1449
  createOptimizeImportsPlugin(() => nextConfig, () => root),
1977
1450
  {
1978
1451
  name: "vinext:use-cache",
@@ -2071,94 +1544,9 @@ function vinext(options = {}) {
2071
1544
  }
2072
1545
  }
2073
1546
  },
2074
- {
2075
- name: "vinext:og-inline-fetch-assets",
2076
- enforce: "pre",
2077
- configResolved(config) {
2078
- _ogInlineIsBuild = config.command === "build";
2079
- },
2080
- buildStart() {
2081
- if (_ogInlineIsBuild) _ogInlineCache.clear();
2082
- },
2083
- async transform(code, id) {
2084
- if (!code.includes("import.meta.url")) return null;
2085
- const useCache = _ogInlineIsBuild;
2086
- const moduleDir = path.dirname(id);
2087
- let newCode = code;
2088
- let didReplace = false;
2089
- if (code.includes("fetch(")) for (const match of code.matchAll(/fetch\(\s*new URL\(\s*(["'])(\.\/[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)(?:\.then\(\s*(?:function\s*\([^)]*\)|\([^)]*\)\s*=>)\s*\{?\s*return\s+[^.]+\.arrayBuffer\(\)\s*\}?\s*\)|\.then\(\s*\([^)]*\)\s*=>\s*[^.]+\.arrayBuffer\(\)\s*\))/g)) {
2090
- const fullMatch = match[0];
2091
- const relPath = match[2];
2092
- const absPath = path.resolve(moduleDir, relPath);
2093
- let fileBase64 = useCache ? _ogInlineCache.get(absPath) : void 0;
2094
- if (fileBase64 === void 0) try {
2095
- fileBase64 = (await fs.promises.readFile(absPath)).toString("base64");
2096
- if (useCache) _ogInlineCache.set(absPath, fileBase64);
2097
- } catch {
2098
- continue;
2099
- }
2100
- const inlined = [
2101
- `(function(){`,
2102
- `var b=${JSON.stringify(fileBase64)};`,
2103
- `var r=atob(b);`,
2104
- `var a=new Uint8Array(r.length);`,
2105
- `for(var i=0;i<r.length;i++)a[i]=r.charCodeAt(i);`,
2106
- `return Promise.resolve(a.buffer);`,
2107
- `})()`
2108
- ].join("");
2109
- newCode = newCode.replaceAll(fullMatch, inlined);
2110
- didReplace = true;
2111
- }
2112
- if (code.includes("readFileSync(")) for (const match of newCode.matchAll(/[a-zA-Z_$][a-zA-Z0-9_$]*\.readFileSync\(\s*(?:[a-zA-Z_$][a-zA-Z0-9_$]*\.)?fileURLToPath\(\s*new URL\(\s*(["'])(\.\/[^"']+)\1\s*,\s*import\.meta\.url\s*\)\s*\)\s*\)/g)) {
2113
- const fullMatch = match[0];
2114
- const relPath = match[2];
2115
- const absPath = path.resolve(moduleDir, relPath);
2116
- let fileBase64 = useCache ? _ogInlineCache.get(absPath) : void 0;
2117
- if (fileBase64 === void 0) try {
2118
- fileBase64 = (await fs.promises.readFile(absPath)).toString("base64");
2119
- if (useCache) _ogInlineCache.set(absPath, fileBase64);
2120
- } catch {
2121
- continue;
2122
- }
2123
- const inlined = `Buffer.from(${JSON.stringify(fileBase64)},"base64")`;
2124
- newCode = newCode.replaceAll(fullMatch, inlined);
2125
- didReplace = true;
2126
- }
2127
- if (!didReplace) return null;
2128
- return {
2129
- code: newCode,
2130
- map: null
2131
- };
2132
- }
2133
- },
2134
- {
2135
- name: "vinext:og-assets",
2136
- apply: "build",
2137
- enforce: "post",
2138
- writeBundle: {
2139
- sequential: true,
2140
- order: "post",
2141
- async handler(options) {
2142
- if (this.environment?.name !== "rsc") return;
2143
- const outDir = options.dir;
2144
- if (!outDir) return;
2145
- const indexPath = path.join(outDir, "index.js");
2146
- if (!fs.existsSync(indexPath)) return;
2147
- const content = fs.readFileSync(indexPath, "utf-8");
2148
- const referencedAssets = ["resvg.wasm"].filter((asset) => content.includes(asset));
2149
- if (referencedAssets.length === 0) return;
2150
- try {
2151
- const ogPkgPath = createRequire(import.meta.url).resolve("@vercel/og/package.json");
2152
- const ogDistDir = path.join(path.dirname(ogPkgPath), "dist");
2153
- for (const asset of referencedAssets) {
2154
- const src = path.join(ogDistDir, asset);
2155
- const dest = path.join(outDir, asset);
2156
- if (fs.existsSync(src) && !fs.existsSync(dest)) fs.copyFileSync(src, dest);
2157
- }
2158
- } catch {}
2159
- }
2160
- }
2161
- },
1547
+ createOgInlineFetchAssetsPlugin(),
1548
+ ogAssetsPlugin,
1549
+ createServerExternalsManifestPlugin(),
2162
1550
  {
2163
1551
  name: "vinext:image-config",
2164
1552
  apply: "build",
@@ -2179,6 +1567,25 @@ function vinext(options = {}) {
2179
1567
  }
2180
1568
  }
2181
1569
  },
1570
+ (() => {
1571
+ let buildIdWritten = false;
1572
+ return {
1573
+ name: "vinext:build-id",
1574
+ apply: "build",
1575
+ enforce: "post",
1576
+ closeBundle: {
1577
+ sequential: true,
1578
+ order: "post",
1579
+ handler() {
1580
+ if (buildIdWritten) return;
1581
+ buildIdWritten = true;
1582
+ const outDir = path.join(root, "dist", "server");
1583
+ fs.mkdirSync(outDir, { recursive: true });
1584
+ fs.writeFileSync(path.join(outDir, "BUILD_ID"), nextConfig.buildId);
1585
+ }
1586
+ }
1587
+ };
1588
+ })(),
2182
1589
  (() => {
2183
1590
  const prerenderSecret = randomBytes(32).toString("hex");
2184
1591
  return {
@@ -2199,6 +1606,24 @@ function vinext(options = {}) {
2199
1606
  }
2200
1607
  };
2201
1608
  })(),
1609
+ {
1610
+ name: "vinext:nitro-route-rules",
1611
+ nitro: { setup: async (nitro) => {
1612
+ if (nitro.options.dev) return;
1613
+ if (!nextConfig) return;
1614
+ if (!hasAppDir && !hasPagesDir) return;
1615
+ const { collectNitroRouteRules, mergeNitroRouteRules } = await import("./build/nitro-route-rules.js");
1616
+ const generatedRouteRules = await collectNitroRouteRules({
1617
+ appDir: hasAppDir ? appDir : null,
1618
+ pagesDir: hasPagesDir ? pagesDir : null,
1619
+ pageExtensions: nextConfig.pageExtensions
1620
+ });
1621
+ if (Object.keys(generatedRouteRules).length === 0) return;
1622
+ const { routeRules, skippedRoutes } = mergeNitroRouteRules(nitro.options.routeRules, generatedRouteRules);
1623
+ nitro.options.routeRules = routeRules;
1624
+ if (skippedRoutes.length > 0) (nitro.logger?.warn ?? console.warn)(`[vinext] Skipping generated Nitro routeRules for routes with existing exact cache config: ${skippedRoutes.join(", ")}`);
1625
+ } }
1626
+ },
2202
1627
  {
2203
1628
  name: "vinext:ssr-manifest-backfill",
2204
1629
  apply: "build",
@@ -2221,6 +1646,67 @@ function vinext(options = {}) {
2221
1646
  }
2222
1647
  }
2223
1648
  },
1649
+ (() => {
1650
+ let pendingPrecompress = null;
1651
+ let pendingPrecompressError = null;
1652
+ return {
1653
+ name: "vinext:precompress",
1654
+ apply: "build",
1655
+ enforce: "post",
1656
+ writeBundle: {
1657
+ sequential: true,
1658
+ order: "post",
1659
+ handler(outputOptions) {
1660
+ if (this.environment?.name !== "client") return;
1661
+ if (!options.precompress && process.env.VINEXT_PRECOMPRESS !== "1") return;
1662
+ const outDir = outputOptions.dir;
1663
+ if (!outDir) return;
1664
+ const assetsDir = path.join(outDir, "assets");
1665
+ if (!fs.existsSync(assetsDir)) return;
1666
+ const isTTY = process.stderr.isTTY;
1667
+ let lastLineLen = 0;
1668
+ pendingPrecompressError = null;
1669
+ pendingPrecompress = (async () => {
1670
+ const result = await precompressAssets(outDir, (completed, total, file) => {
1671
+ if (!isTTY) return;
1672
+ const pct = total > 0 ? Math.floor(completed / total * 100) : 0;
1673
+ const bar = `[${"█".repeat(Math.floor(pct / 5))}${" ".repeat(20 - Math.floor(pct / 5))}]`;
1674
+ const maxFile = 30;
1675
+ const fileLabel = file.length > maxFile ? "…" + file.slice(-(maxFile - 1)) : file;
1676
+ const line = `Compressing assets... ${bar} ${String(completed).padStart(String(total).length)}/${total} ${fileLabel}`;
1677
+ const padded = line.padEnd(lastLineLen);
1678
+ lastLineLen = line.length;
1679
+ process.stderr.write(`\r${padded}`);
1680
+ });
1681
+ if (isTTY) process.stderr.write(`\r${" ".repeat(lastLineLen)}\r`);
1682
+ if (result.filesCompressed > 0) {
1683
+ const ratio = ((1 - result.totalBrotliBytes / result.totalOriginalBytes) * 100).toFixed(1);
1684
+ console.log(` Precompressed ${result.filesCompressed} assets (${ratio}% smaller with brotli)`);
1685
+ }
1686
+ })().catch((error) => {
1687
+ pendingPrecompressError = error;
1688
+ console.error("[vinext] Precompression failed:", error);
1689
+ });
1690
+ }
1691
+ },
1692
+ closeBundle: {
1693
+ sequential: true,
1694
+ order: "post",
1695
+ async handler() {
1696
+ if (this.environment?.name !== "ssr") return;
1697
+ if (!pendingPrecompress) return;
1698
+ const task = pendingPrecompress;
1699
+ pendingPrecompress = null;
1700
+ await task;
1701
+ if (pendingPrecompressError) {
1702
+ const error = pendingPrecompressError;
1703
+ pendingPrecompressError = null;
1704
+ throw error;
1705
+ }
1706
+ }
1707
+ }
1708
+ };
1709
+ })(),
2224
1710
  {
2225
1711
  name: "vinext:cloudflare-build",
2226
1712
  apply: "build",
@@ -2400,7 +1886,7 @@ function stripServerExports(code) {
2400
1886
  if (node.type !== "ExportNamedDeclaration") continue;
2401
1887
  if (node.declaration) {
2402
1888
  const decl = node.declaration;
2403
- if (decl.type === "FunctionDeclaration" && SERVER_EXPORTS.has(decl.id?.name)) {
1889
+ if (decl.type === "FunctionDeclaration" && decl.id && SERVER_EXPORTS.has(decl.id.name)) {
2404
1890
  s.overwrite(node.start, node.end, `export function ${decl.id.name}() { return { props: {} }; }`);
2405
1891
  changed = true;
2406
1892
  } else if (decl.type === "VariableDeclaration") {
@@ -2551,12 +2037,12 @@ function scanDirForMdx(dir) {
2551
2037
  const full = path.join(dir, entry.name);
2552
2038
  if (entry.isDirectory()) {
2553
2039
  if (scanDirForMdx(full)) return true;
2554
- } else if (entry.isFile() && entry.name.endsWith(".mdx")) return true;
2040
+ } else if (entry.isFile() && entry.name.toLowerCase().endsWith(".mdx")) return true;
2555
2041
  }
2556
2042
  } catch {}
2557
2043
  return false;
2558
2044
  }
2559
2045
  //#endregion
2560
- export { asyncHooksStubPlugin as _asyncHooksStubPlugin, augmentSsrManifestFromBundle as _augmentSsrManifestFromBundle, hasMdxFiles as _hasMdxFiles, _mdxScanCache, parseStaticObjectLiteral as _parseStaticObjectLiteral, _postcssCache, resolvePostcssStringPlugins as _resolvePostcssStringPlugins, stripServerExports as _stripServerExports, clientManualChunks, clientOutputConfig, clientTreeshakeConfig, computeLazyChunks, vinext as default, matchConfigPattern, staticExportApp, staticExportPages };
2046
+ export { asyncHooksStubPlugin as _asyncHooksStubPlugin, augmentSsrManifestFromBundle as _augmentSsrManifestFromBundle, _findBalancedObject, _findCallEnd, hasMdxFiles as _hasMdxFiles, _mdxScanCache, parseStaticObjectLiteral as _parseStaticObjectLiteral, _postcssCache, resolvePostcssStringPlugins as _resolvePostcssStringPlugins, stripServerExports as _stripServerExports, clientManualChunks, clientOutputConfig, clientTreeshakeConfig, computeLazyChunks, vinext as default, getClientOutputConfigForVite, matchConfigPattern, staticExportApp, staticExportPages };
2561
2047
 
2562
2048
  //# sourceMappingURL=index.js.map