vinext 0.1.2 → 0.1.4

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 (243) hide show
  1. package/dist/build/client-build-config.d.ts +11 -2
  2. package/dist/build/client-build-config.js +17 -6
  3. package/dist/build/prerender.d.ts +9 -1
  4. package/dist/build/prerender.js +42 -12
  5. package/dist/build/run-prerender.d.ts +10 -2
  6. package/dist/build/run-prerender.js +15 -1
  7. package/dist/client/app-nav-failure-handler.d.ts +8 -0
  8. package/dist/client/app-nav-failure-handler.js +44 -0
  9. package/dist/client/pages-router-link-navigation.d.ts +33 -7
  10. package/dist/client/pages-router-link-navigation.js +32 -2
  11. package/dist/client/vinext-next-data.d.ts +18 -1
  12. package/dist/client/vinext-next-data.js +2 -0
  13. package/dist/client/window-next.d.ts +2 -1
  14. package/dist/client/window-next.js +12 -1
  15. package/dist/cloudflare/src/cache/cdn-adapter.runtime.js +6 -1
  16. package/dist/config/config-matchers.d.ts +11 -1
  17. package/dist/config/config-matchers.js +87 -16
  18. package/dist/config/next-config.d.ts +46 -4
  19. package/dist/config/next-config.js +147 -48
  20. package/dist/config/tsconfig-paths.js +14 -1
  21. package/dist/deploy.d.ts +30 -11
  22. package/dist/deploy.js +200 -112
  23. package/dist/entries/app-browser-entry.d.ts +9 -3
  24. package/dist/entries/app-browser-entry.js +21 -3
  25. package/dist/entries/app-rsc-entry.d.ts +2 -0
  26. package/dist/entries/app-rsc-entry.js +65 -5
  27. package/dist/entries/app-rsc-manifest.js +2 -0
  28. package/dist/entries/app-ssr-entry.js +1 -1
  29. package/dist/entries/pages-client-entry.js +66 -20
  30. package/dist/entries/pages-server-entry.js +47 -31
  31. package/dist/index.js +417 -102
  32. package/dist/plugins/dynamic-preload-metadata.js +2 -4
  33. package/dist/plugins/extensionless-dynamic-import.d.ts +6 -0
  34. package/dist/plugins/extensionless-dynamic-import.js +152 -0
  35. package/dist/plugins/fonts.js +5 -4
  36. package/dist/plugins/optimize-imports.d.ts +2 -1
  37. package/dist/plugins/optimize-imports.js +11 -9
  38. package/dist/plugins/postcss.js +7 -7
  39. package/dist/plugins/strip-server-exports.d.ts +9 -7
  40. package/dist/plugins/strip-server-exports.js +493 -46
  41. package/dist/plugins/typeof-window.d.ts +14 -0
  42. package/dist/plugins/typeof-window.js +150 -0
  43. package/dist/routing/app-route-graph.d.ts +2 -1
  44. package/dist/routing/app-route-graph.js +46 -16
  45. package/dist/routing/file-matcher.d.ts +10 -1
  46. package/dist/routing/file-matcher.js +22 -1
  47. package/dist/routing/pages-router.js +3 -3
  48. package/dist/routing/utils.d.ts +35 -6
  49. package/dist/routing/utils.js +59 -7
  50. package/dist/server/api-handler.d.ts +6 -1
  51. package/dist/server/api-handler.js +21 -15
  52. package/dist/server/app-browser-action-result.d.ts +19 -6
  53. package/dist/server/app-browser-action-result.js +20 -11
  54. package/dist/server/app-browser-entry.js +175 -91
  55. package/dist/server/app-browser-error.d.ts +10 -6
  56. package/dist/server/app-browser-error.js +43 -8
  57. package/dist/server/app-browser-hydration.d.ts +2 -0
  58. package/dist/server/app-browser-hydration.js +1 -0
  59. package/dist/server/app-browser-navigation-controller.d.ts +5 -3
  60. package/dist/server/app-browser-navigation-controller.js +23 -2
  61. package/dist/server/app-browser-server-action-navigation.d.ts +6 -0
  62. package/dist/server/app-browser-server-action-navigation.js +9 -0
  63. package/dist/server/app-browser-state.d.ts +1 -1
  64. package/dist/server/app-browser-state.js +19 -11
  65. package/dist/server/app-browser-stream.js +86 -43
  66. package/dist/server/app-browser-visible-commit.d.ts +1 -1
  67. package/dist/server/app-elements-wire.d.ts +6 -1
  68. package/dist/server/app-elements-wire.js +14 -4
  69. package/dist/server/app-elements.d.ts +2 -2
  70. package/dist/server/app-elements.js +2 -2
  71. package/dist/server/app-fallback-renderer.d.ts +1 -0
  72. package/dist/server/app-fallback-renderer.js +3 -1
  73. package/dist/server/app-optimistic-routing.js +2 -2
  74. package/dist/server/app-page-boundary-render.d.ts +1 -0
  75. package/dist/server/app-page-boundary-render.js +27 -14
  76. package/dist/server/app-page-cache-render.d.ts +53 -0
  77. package/dist/server/app-page-cache-render.js +91 -0
  78. package/dist/server/app-page-cache.d.ts +16 -2
  79. package/dist/server/app-page-cache.js +62 -1
  80. package/dist/server/app-page-dispatch.d.ts +26 -0
  81. package/dist/server/app-page-dispatch.js +149 -92
  82. package/dist/server/app-page-element-builder.d.ts +1 -0
  83. package/dist/server/app-page-element-builder.js +5 -2
  84. package/dist/server/app-page-execution.d.ts +6 -1
  85. package/dist/server/app-page-execution.js +21 -1
  86. package/dist/server/app-page-probe.d.ts +1 -0
  87. package/dist/server/app-page-probe.js +4 -0
  88. package/dist/server/app-page-render-observation.d.ts +3 -1
  89. package/dist/server/app-page-render-observation.js +17 -1
  90. package/dist/server/app-page-render.d.ts +12 -1
  91. package/dist/server/app-page-render.js +42 -4
  92. package/dist/server/app-page-request.d.ts +2 -0
  93. package/dist/server/app-page-request.js +2 -1
  94. package/dist/server/app-page-route-wiring.d.ts +3 -1
  95. package/dist/server/app-page-route-wiring.js +14 -5
  96. package/dist/server/app-page-stream.d.ts +15 -3
  97. package/dist/server/app-page-stream.js +11 -5
  98. package/dist/server/app-pages-bridge.d.ts +23 -1
  99. package/dist/server/app-pages-bridge.js +26 -17
  100. package/dist/server/app-ppr-fallback-shell-render.d.ts +17 -0
  101. package/dist/server/app-ppr-fallback-shell-render.js +26 -0
  102. package/dist/server/app-ppr-fallback-shell.d.ts +13 -1
  103. package/dist/server/app-ppr-fallback-shell.js +8 -1
  104. package/dist/server/app-route-handler-dispatch.js +9 -2
  105. package/dist/server/app-route-handler-policy.d.ts +1 -0
  106. package/dist/server/app-router-entry.js +5 -0
  107. package/dist/server/app-rsc-cache-busting.js +2 -0
  108. package/dist/server/app-rsc-handler.d.ts +28 -0
  109. package/dist/server/app-rsc-handler.js +195 -59
  110. package/dist/server/app-rsc-route-matching.d.ts +3 -0
  111. package/dist/server/app-rsc-route-matching.js +8 -2
  112. package/dist/server/app-segment-config.d.ts +9 -1
  113. package/dist/server/app-segment-config.js +12 -3
  114. package/dist/server/app-server-action-execution.d.ts +1 -0
  115. package/dist/server/app-server-action-execution.js +47 -15
  116. package/dist/server/app-ssr-entry.d.ts +2 -0
  117. package/dist/server/app-ssr-entry.js +84 -39
  118. package/dist/server/before-interactive-head.d.ts +17 -0
  119. package/dist/server/before-interactive-head.js +35 -0
  120. package/dist/server/cache-control.js +4 -0
  121. package/dist/server/csp.js +1 -4
  122. package/dist/server/dev-server.d.ts +2 -2
  123. package/dist/server/dev-server.js +321 -83
  124. package/dist/server/hybrid-route-priority.d.ts +22 -0
  125. package/dist/server/hybrid-route-priority.js +33 -0
  126. package/dist/server/image-optimization.d.ts +18 -9
  127. package/dist/server/image-optimization.js +37 -23
  128. package/dist/server/implicit-tags.d.ts +2 -1
  129. package/dist/server/implicit-tags.js +4 -1
  130. package/dist/server/middleware-matcher.js +12 -3
  131. package/dist/server/middleware-runtime.d.ts +3 -4
  132. package/dist/server/middleware-runtime.js +2 -0
  133. package/dist/server/navigation-planner.d.ts +135 -41
  134. package/dist/server/navigation-planner.js +138 -0
  135. package/dist/server/navigation-trace.d.ts +9 -1
  136. package/dist/server/navigation-trace.js +9 -1
  137. package/dist/server/operation-token.d.ts +40 -0
  138. package/dist/server/operation-token.js +85 -0
  139. package/dist/server/pages-api-route.d.ts +6 -0
  140. package/dist/server/pages-api-route.js +13 -2
  141. package/dist/server/pages-asset-tags.d.ts +2 -1
  142. package/dist/server/pages-asset-tags.js +6 -2
  143. package/dist/server/pages-data-route.d.ts +9 -2
  144. package/dist/server/pages-data-route.js +18 -6
  145. package/dist/server/pages-dev-module-url.d.ts +4 -0
  146. package/dist/server/pages-dev-module-url.js +15 -0
  147. package/dist/server/pages-document-initial-props.d.ts +4 -15
  148. package/dist/server/pages-document-initial-props.js +27 -56
  149. package/dist/server/pages-get-initial-props.d.ts +54 -4
  150. package/dist/server/pages-get-initial-props.js +43 -1
  151. package/dist/server/pages-i18n.js +2 -2
  152. package/dist/server/pages-node-compat.js +2 -2
  153. package/dist/server/pages-page-data.d.ts +11 -2
  154. package/dist/server/pages-page-data.js +207 -34
  155. package/dist/server/pages-page-handler.d.ts +4 -2
  156. package/dist/server/pages-page-handler.js +62 -23
  157. package/dist/server/pages-page-response.d.ts +4 -1
  158. package/dist/server/pages-page-response.js +11 -8
  159. package/dist/server/pages-readiness.js +1 -1
  160. package/dist/server/pages-request-pipeline.d.ts +8 -7
  161. package/dist/server/pages-request-pipeline.js +126 -47
  162. package/dist/server/pregenerated-concrete-paths.d.ts +1 -17
  163. package/dist/server/pregenerated-concrete-paths.js +2 -19
  164. package/dist/server/prerender-manifest.d.ts +33 -0
  165. package/dist/server/prerender-manifest.js +54 -0
  166. package/dist/server/prerender-route-params.d.ts +1 -2
  167. package/dist/server/prod-server.d.ts +3 -1
  168. package/dist/server/prod-server.js +50 -13
  169. package/dist/server/request-pipeline.d.ts +3 -15
  170. package/dist/server/request-pipeline.js +58 -47
  171. package/dist/server/rsc-stream-hints.d.ts +5 -1
  172. package/dist/server/rsc-stream-hints.js +6 -1
  173. package/dist/server/seed-cache.js +10 -18
  174. package/dist/server/static-file-cache.js +16 -4
  175. package/dist/shims/app-router-scroll-state.d.ts +3 -1
  176. package/dist/shims/app-router-scroll-state.js +14 -2
  177. package/dist/shims/app-router-scroll.d.ts +3 -0
  178. package/dist/shims/app-router-scroll.js +28 -18
  179. package/dist/shims/before-interactive-context.d.ts +14 -3
  180. package/dist/shims/cache-runtime.js +3 -2
  181. package/dist/shims/cache.d.ts +1 -0
  182. package/dist/shims/cache.js +1 -1
  183. package/dist/shims/cdn-cache.d.ts +5 -5
  184. package/dist/shims/document.d.ts +15 -20
  185. package/dist/shims/document.js +5 -8
  186. package/dist/shims/dynamic-preload-chunks.js +6 -4
  187. package/dist/shims/error-boundary.d.ts +2 -0
  188. package/dist/shims/error-boundary.js +7 -0
  189. package/dist/shims/error.js +3 -2
  190. package/dist/shims/error.react-server.d.ts +9 -0
  191. package/dist/shims/error.react-server.js +6 -0
  192. package/dist/shims/fetch-cache.d.ts +3 -1
  193. package/dist/shims/fetch-cache.js +45 -20
  194. package/dist/shims/hash-scroll.js +6 -1
  195. package/dist/shims/headers.js +29 -4
  196. package/dist/shims/image.js +9 -2
  197. package/dist/shims/internal/als-registry.js +28 -1
  198. package/dist/shims/internal/app-route-detection.js +8 -17
  199. package/dist/shims/internal/hybrid-client-route-owner.d.ts +31 -0
  200. package/dist/shims/internal/hybrid-client-route-owner.js +143 -0
  201. package/dist/shims/internal/navigation-untracked.d.ts +35 -0
  202. package/dist/shims/internal/navigation-untracked.js +55 -0
  203. package/dist/shims/internal/pages-data-fetch-dedup.d.ts +6 -7
  204. package/dist/shims/internal/pages-data-fetch-dedup.js +67 -14
  205. package/dist/shims/internal/pages-data-target.d.ts +7 -2
  206. package/dist/shims/internal/pages-data-target.js +17 -8
  207. package/dist/shims/internal/pages-router-accessor.d.ts +19 -0
  208. package/dist/shims/internal/pages-router-accessor.js +13 -0
  209. package/dist/shims/internal/router-context.d.ts +2 -1
  210. package/dist/shims/internal/router-context.js +3 -1
  211. package/dist/shims/link.js +47 -19
  212. package/dist/shims/metadata.js +4 -4
  213. package/dist/shims/navigation.d.ts +8 -2
  214. package/dist/shims/navigation.js +63 -31
  215. package/dist/shims/ppr-fallback-shell.d.ts +5 -1
  216. package/dist/shims/ppr-fallback-shell.js +28 -7
  217. package/dist/shims/router.d.ts +18 -3
  218. package/dist/shims/router.js +512 -142
  219. package/dist/shims/script.js +8 -4
  220. package/dist/shims/server.d.ts +16 -1
  221. package/dist/shims/server.js +44 -12
  222. package/dist/shims/unified-request-context.js +1 -0
  223. package/dist/utils/built-asset-url.d.ts +4 -0
  224. package/dist/utils/built-asset-url.js +11 -0
  225. package/dist/utils/commonjs-loader.d.ts +16 -0
  226. package/dist/utils/commonjs-loader.js +100 -0
  227. package/dist/utils/deployment-id.d.ts +8 -0
  228. package/dist/utils/deployment-id.js +22 -0
  229. package/dist/utils/has-trailing-comma.d.ts +24 -0
  230. package/dist/utils/has-trailing-comma.js +62 -0
  231. package/dist/utils/html-limited-bots.d.ts +18 -1
  232. package/dist/utils/html-limited-bots.js +23 -1
  233. package/dist/utils/parse-cookie.d.ts +13 -0
  234. package/dist/utils/parse-cookie.js +52 -0
  235. package/dist/utils/path.d.ts +7 -1
  236. package/dist/utils/path.js +9 -1
  237. package/dist/utils/text-stream.d.ts +1 -1
  238. package/dist/utils/text-stream.js +2 -2
  239. package/dist/utils/vite-version.d.ts +12 -1
  240. package/dist/utils/vite-version.js +9 -1
  241. package/package.json +2 -2
  242. package/dist/shims/internal/parse-cookie-header.d.ts +0 -14
  243. package/dist/shims/internal/parse-cookie-header.js +0 -30
package/dist/index.js CHANGED
@@ -1,22 +1,22 @@
1
1
  import { detectPackageManager } from "./utils/project.js";
2
- import { normalizePathSeparators, stripViteModuleQuery } from "./utils/path.js";
2
+ import { normalizePathSeparators, stripJsExtension, stripViteModuleQuery } from "./utils/path.js";
3
3
  import { normalizePathnameForRouteMatchStrict } from "./routing/utils.js";
4
- import { buildViteResolveExtensions, createValidFileMatcher, findFileWithExts } from "./routing/file-matcher.js";
4
+ import { buildViteResolveExtensions, createValidFileMatcher, findFileWithExts, normalizeViteResolveExtensions } from "./routing/file-matcher.js";
5
5
  import { apiRouter, invalidateRouteCache, matchRoute, pagesRouter } from "./routing/pages-router.js";
6
6
  import { INTERNAL_HEADERS, NEXTJS_DEPLOYMENT_ID_HEADER, VINEXT_INTERNAL_HEADERS, VINEXT_MW_CTX_HEADER, VINEXT_TIMING_HEADER } from "./server/headers.js";
7
7
  import { normalizePath as normalizePath$1 } from "./server/normalize-path.js";
8
- import { proxyExternalRequest } from "./config/config-matchers.js";
8
+ import { matchesRewriteSource, proxyExternalRequest } from "./config/config-matchers.js";
9
9
  import { filterInternalHeaders, isOpenRedirectShaped, normalizeTrailingSlash } from "./server/request-pipeline.js";
10
10
  import { findMiddlewareFile, runMiddleware } from "./server/middleware.js";
11
11
  import { generateServerEntry } from "./entries/pages-server-entry.js";
12
12
  import { generateClientEntry } from "./entries/pages-client-entry.js";
13
- import { appRouteGraph, appRouter, invalidateAppRouteCache } from "./routing/app-router.js";
13
+ import { appRouteGraph, appRouter, invalidateAppRouteCache, matchAppRoute } from "./routing/app-router.js";
14
14
  import { findInstrumentationClientFile, findInstrumentationFile, runInstrumentation } from "./server/instrumentation.js";
15
15
  import { isUnknownRecord } from "./utils/record.js";
16
16
  import { logRequest, now } from "./server/request-log.js";
17
17
  import { createSSRHandler } from "./server/dev-server.js";
18
18
  import { handleApiRoute } from "./server/api-handler.js";
19
- import { isImageOptimizationPath } from "./server/image-optimization.js";
19
+ import { DEFAULT_DEVICE_SIZES, DEFAULT_IMAGE_SIZES, isImageOptimizationPath, resolveDevImageRedirect } from "./server/image-optimization.js";
20
20
  import { installSocketErrorBackstop } from "./server/socket-error-backstop.js";
21
21
  import { scanMetadataFiles } from "./server/metadata-routes.js";
22
22
  import { shouldInvalidateAppRouteFile } from "./server/dev-route-files.js";
@@ -25,13 +25,13 @@ import { validateDevRequest } from "./server/dev-origin-check.js";
25
25
  import { generateRscEntry } from "./entries/app-rsc-entry.js";
26
26
  import { generateSsrEntry } from "./entries/app-ssr-entry.js";
27
27
  import { VIRTUAL_CACHE_ADAPTERS, generateCacheAdaptersModule } from "./cache/cache-adapters-virtual.js";
28
- import { generateBrowserEntry, isLinkPrefetchRoute, toLinkPrefetchRoute } from "./entries/app-browser-entry.js";
28
+ import { generateBrowserEntry, isLinkPrefetchRoute, toDocumentOnlyAppRoute, toLinkPrefetchRoute } from "./entries/app-browser-entry.js";
29
29
  import { collectRouteClassificationManifest } from "./build/route-classification-manifest.js";
30
30
  import { planRouteClassificationInjection } from "./build/route-classification-injector.js";
31
31
  import { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } from "./shims/constants.js";
32
- import { ASSET_PREFIX_URL_DIR, resolveAssetUrlPrefix, resolveAssetsDir } from "./utils/asset-prefix.js";
32
+ import { resolveAssetsDir } from "./utils/asset-prefix.js";
33
33
  import { RESOLVED_VIRTUAL_GOOGLE_FONTS, VIRTUAL_GOOGLE_FONTS, createGoogleFontsPlugin, createLocalFontsPlugin, generateGoogleFontsVirtualModule, parseStaticObjectLiteral } from "./plugins/fonts.js";
34
- import { getViteMajorVersion } from "./utils/vite-version.js";
34
+ import { getDepOptimizeNodeEnvOptions, getViteMajorVersion, serializeViteDefine } from "./utils/vite-version.js";
35
35
  import { createRscCompatibilityId, findNextConfigPath, loadNextConfig, resolveNextConfig, resolveNextConfigInput } from "./config/next-config.js";
36
36
  import { isNextDataPathname, parseNextDataPathname } from "./server/pages-data-route.js";
37
37
  import { precompressAssets } from "./build/precompress.js";
@@ -40,6 +40,8 @@ import { emitNextClientRuntimeManifests } from "./build/next-client-runtime-mani
40
40
  import { collectInlineCssManifest, injectInlineCssManifestGlobal } from "./build/inline-css.js";
41
41
  import { installDevStackSourcemapMiddleware } from "./server/dev-stack-sourcemap.js";
42
42
  import { runPagesRequest } from "./server/pages-request-pipeline.js";
43
+ import { pagesRouteHasPriorityOverAppRoute, validateHybridRouteConflicts } from "./server/hybrid-route-priority.js";
44
+ import { renderVinextBuiltUrl } from "./utils/built-asset-url.js";
43
45
  import { asyncHooksStubPlugin } from "./plugins/async-hooks-stub.js";
44
46
  import { clientReferenceDedupPlugin } from "./plugins/client-reference-dedup.js";
45
47
  import { dataUrlCssPlugin } from "./plugins/css-data-url.js";
@@ -61,11 +63,13 @@ import { resolvePostcssStringPlugins } from "./plugins/postcss.js";
61
63
  import { buildSassPreprocessorOptions, createSassAwareFileSystemLoader, createSassTildeImporter } from "./plugins/sass.js";
62
64
  import { createClientAssetFileNames, createClientCodeSplittingConfig, createClientFileNameConfig, createClientManualChunks, createClientOutputConfig, createRscFrameworkChunkOutputConfig, getBuildBundlerOptions, getClientTreeshakeConfigForVite, withBuildBundlerOptions } from "./build/client-build-config.js";
63
65
  import { markCssUrlAssetReferences, restoreDedupedCssAssetReferences } from "./build/css-url-assets.js";
64
- import { stripServerExports } from "./plugins/strip-server-exports.js";
66
+ import { hasExportAllCandidate, hasServerExportCandidate, stripServerExports, validatePageExports } from "./plugins/strip-server-exports.js";
65
67
  import { removeConsoleCalls } from "./plugins/remove-console.js";
66
68
  import { createImportMetaUrlPlugin } from "./plugins/import-meta-url.js";
67
69
  import { createRequireContextPlugin } from "./plugins/require-context.js";
70
+ import { createExtensionlessDynamicImportPlugin } from "./plugins/extensionless-dynamic-import.js";
68
71
  import { createWasmModuleImportPlugin } from "./plugins/wasm-module-import.js";
72
+ import { getTypeofWindowReplacement, replaceTypeofWindow } from "./plugins/typeof-window.js";
69
73
  import { hasMdxFiles } from "./utils/mdx-scan.js";
70
74
  import { scanPublicFileRoutes } from "./utils/public-routes.js";
71
75
  import { staticExportApp, staticExportPages } from "./build/static-export.js";
@@ -74,7 +78,7 @@ import fs from "node:fs";
74
78
  import path from "node:path";
75
79
  import { loadEnv, parseAst, transformWithOxc } from "vite";
76
80
  import { pathToFileURL } from "node:url";
77
- import { randomBytes, randomUUID } from "node:crypto";
81
+ import { createHash, randomBytes, randomUUID } from "node:crypto";
78
82
  import commonjs from "vite-plugin-commonjs";
79
83
  import MagicString from "magic-string";
80
84
  import tsconfigPaths from "vite-tsconfig-paths";
@@ -84,17 +88,6 @@ function isInsideDirectory(dir, filePath) {
84
88
  const relativePath = path.relative(dir, filePath);
85
89
  return relativePath !== "" && !relativePath.startsWith("..") && !path.isAbsolute(relativePath);
86
90
  }
87
- function hasModuleLevelUseServerDirective(body) {
88
- for (const node of body) {
89
- if (node.type !== "ExpressionStatement") break;
90
- const directive = node.directive;
91
- const expression = node.expression;
92
- const value = typeof directive === "string" ? directive : expression?.type === "Literal" ? expression.value : void 0;
93
- if (value === "use server") return true;
94
- if (typeof value !== "string") break;
95
- }
96
- return false;
97
- }
98
91
  function hasServerOnlyMarkerImport(code) {
99
92
  if (!code.includes("server-only")) return false;
100
93
  let ast;
@@ -103,7 +96,6 @@ function hasServerOnlyMarkerImport(code) {
103
96
  } catch {
104
97
  return false;
105
98
  }
106
- if (hasModuleLevelUseServerDirective(ast.body)) return false;
107
99
  function walk(node) {
108
100
  if (!node) return false;
109
101
  if (Array.isArray(node)) return node.some((child) => walk(child));
@@ -170,6 +162,19 @@ function resolveTsconfigPathCandidate(candidate) {
170
162
  for (const item of candidates) if (fs.existsSync(item) && fs.statSync(item).isFile()) return item;
171
163
  return null;
172
164
  }
165
+ /**
166
+ * Normalize a tsconfig `extends` field into a list of specifier strings.
167
+ *
168
+ * TypeScript 5.0+ allows `extends` to be either a string or an array of
169
+ * strings. Matches Next.js's handling in
170
+ * packages/next/src/build/next-config-ts/transpile-config.ts, where parents
171
+ * are iterated in order and later entries override earlier ones.
172
+ */
173
+ function normalizeTsconfigExtends(extendsField) {
174
+ if (typeof extendsField === "string") return [extendsField];
175
+ if (Array.isArray(extendsField)) return extendsField.filter((value) => typeof value === "string");
176
+ return [];
177
+ }
173
178
  function resolveTsconfigExtends(configPath, specifier) {
174
179
  const fromDir = path.dirname(configPath);
175
180
  if (specifier.startsWith(".") || specifier.startsWith("/") || specifier.startsWith("\\")) return resolveTsconfigPathCandidate(path.resolve(fromDir, specifier));
@@ -229,9 +234,12 @@ function loadTsconfigPathAliases(configPath, projectRoot, seen = /* @__PURE__ */
229
234
  }
230
235
  if (!parsed) return {};
231
236
  let aliases = {};
232
- if (typeof parsed.extends === "string") {
233
- const extendedPath = resolveTsconfigExtends(normalizedPath, parsed.extends);
234
- if (extendedPath) aliases = loadTsconfigPathAliases(extendedPath, projectRoot, seen);
237
+ for (const extendsSpecifier of normalizeTsconfigExtends(parsed.extends)) {
238
+ const extendedPath = resolveTsconfigExtends(normalizedPath, extendsSpecifier);
239
+ if (extendedPath) aliases = {
240
+ ...aliases,
241
+ ...loadTsconfigPathAliases(extendedPath, projectRoot, seen)
242
+ };
235
243
  }
236
244
  const compilerOptions = isUnknownRecord(parsed.compilerOptions) ? parsed.compilerOptions : null;
237
245
  const pathsConfig = compilerOptions && isUnknownRecord(compilerOptions.paths) ? compilerOptions.paths : null;
@@ -296,6 +304,14 @@ const RESOLVED_INSTRUMENTATION_CLIENT = `\0${VIRTUAL_INSTRUMENTATION_CLIENT}.mjs
296
304
  /** Image file extensions handled by the vinext:image-imports plugin.
297
305
  * Shared between the Rolldown hook filter and the transform handler regex. */
298
306
  const IMAGE_EXTS = "png|jpe?g|gif|webp|avif|svg|ico|bmp|tiff?";
307
+ function createStaticImageAsset(imagePath) {
308
+ const source = fs.readFileSync(imagePath);
309
+ const extension = path.extname(imagePath);
310
+ return {
311
+ fileName: `media/${path.basename(imagePath, extension)}.${createHash("sha256").update(source).digest("hex").slice(0, 8)}${extension}`,
312
+ source
313
+ };
314
+ }
299
315
  /**
300
316
  * Absolute path to vinext's shims directory, with a trailing slash. Normalized
301
317
  * to forward slashes because it is prefix-matched against Vite module ids (which
@@ -314,49 +330,52 @@ function isVirtualEntryFacade(id, virtualId) {
314
330
  return cleanId === virtualId || cleanId.endsWith("/" + virtualId) || cleanId.endsWith("\\" + virtualId);
315
331
  }
316
332
  /**
317
- * Returns true when `code` starts with a React `"use client"` or `"use server"`
318
- * directive (after stripping leading comments, hashbang, and whitespace).
333
+ * Returns the leading React `"use client"` or `"use server"` directive after
334
+ * stripping leading comments, hashbang, and whitespace.
319
335
  *
320
336
  * Used by `vinext:jsx-in-js` to opt `.js` files inside `node_modules` into the
321
337
  * JSX transform. We mirror `@vitejs/plugin-rsc`'s detection by looking at the
322
338
  * directive prologue rather than scanning the whole file — `code.includes`
323
339
  * alone would match incidental occurrences in template literals or comments.
324
340
  */
325
- function hasReactDirective(code) {
341
+ function getLeadingReactDirective(code) {
326
342
  let i = 0;
327
343
  const len = code.length;
328
344
  if (code.charCodeAt(0) === 65279) i = 1;
329
345
  if (code[i] === "#" && code[i + 1] === "!") {
330
346
  const nl = code.indexOf("\n", i);
331
- if (nl === -1) return false;
347
+ if (nl === -1) return null;
332
348
  i = nl + 1;
333
349
  }
334
350
  while (i < len) {
335
351
  while (i < len && /\s/.test(code[i] ?? "")) i++;
336
- if (i >= len) return false;
352
+ if (i >= len) return null;
337
353
  if (code[i] === "/" && code[i + 1] === "/") {
338
354
  const nl = code.indexOf("\n", i + 2);
339
- if (nl === -1) return false;
355
+ if (nl === -1) return null;
340
356
  i = nl + 1;
341
357
  continue;
342
358
  }
343
359
  if (code[i] === "/" && code[i + 1] === "*") {
344
360
  const end = code.indexOf("*/", i + 2);
345
- if (end === -1) return false;
361
+ if (end === -1) return null;
346
362
  i = end + 2;
347
363
  continue;
348
364
  }
349
365
  const quote = code[i];
350
- if (quote !== "\"" && quote !== "'") return false;
366
+ if (quote !== "\"" && quote !== "'") return null;
351
367
  const closing = code.indexOf(quote, i + 1);
352
- if (closing === -1) return false;
368
+ if (closing === -1) return null;
353
369
  const directive = code.slice(i + 1, closing);
354
- if (directive === "use client" || directive === "use server") return true;
370
+ if (directive === "use client" || directive === "use server") return directive;
355
371
  i = closing + 1;
356
372
  while (i < len && (code[i] === ";" || code[i] === " " || code[i] === " ")) i++;
357
373
  if (code[i] === "\n") i++;
358
374
  }
359
- return false;
375
+ return null;
376
+ }
377
+ function hasReactDirective(code) {
378
+ return getLeadingReactDirective(code) !== null;
360
379
  }
361
380
  function generateRootParamsModule(rootParamNames) {
362
381
  const names = Array.from(new Set(rootParamNames)).filter(isValidExportIdentifier).sort();
@@ -382,7 +401,9 @@ function generateRootParamsModule(rootParamNames) {
382
401
  const _reactServerShims = new Map([
383
402
  ["next/navigation", "navigation"],
384
403
  ["next/navigation.js", "navigation"],
385
- ["next/dist/client/components/navigation", "navigation"]
404
+ ["next/dist/client/components/navigation", "navigation"],
405
+ ["next/error", "error"],
406
+ ["next/error.js", "error"]
386
407
  ]);
387
408
  const clientManualChunks = createClientManualChunks(_shimsDir);
388
409
  const clientCodeSplittingConfig = createClientCodeSplittingConfig(clientManualChunks);
@@ -397,6 +418,7 @@ function vinext(options = {}) {
397
418
  const viteMajorVersion = getViteMajorVersion();
398
419
  let root;
399
420
  let pagesDir;
421
+ let canonicalPagesDir;
400
422
  let appDir;
401
423
  let hasAppDir = false;
402
424
  let hasPagesDir = false;
@@ -416,6 +438,19 @@ function vinext(options = {}) {
416
438
  let rscClassificationManifest = null;
417
439
  const shimsDir = path.resolve(__dirname, "shims");
418
440
  const canonicalize = (p) => tryRealpathSync(p) ?? p;
441
+ const pageTransformCanonicalPaths = /* @__PURE__ */ new Map();
442
+ const canonicalizePageTransformPath = (modulePath) => {
443
+ const cached = pageTransformCanonicalPaths.get(modulePath);
444
+ if (cached) return cached;
445
+ const canonicalPath = canonicalize(modulePath);
446
+ pageTransformCanonicalPaths.set(modulePath, canonicalPath);
447
+ return canonicalPath;
448
+ };
449
+ const isWithinPagesDirectory = (modulePath) => modulePath === pagesDir || modulePath.startsWith(`${pagesDir}/`) || modulePath === canonicalPagesDir || modulePath.startsWith(`${canonicalPagesDir}/`);
450
+ const isApiPage = (canonicalId) => {
451
+ const relativePath = fileMatcher.stripExtension(canonicalId.slice(canonicalPagesDir.length));
452
+ return relativePath === "/api" || relativePath.startsWith("/api/");
453
+ };
419
454
  const dynamicShimPaths = new Set([
420
455
  resolveShimModulePath(shimsDir, "headers"),
421
456
  resolveShimModulePath(shimsDir, "server"),
@@ -438,7 +473,7 @@ function vinext(options = {}) {
438
473
  * __NEXT_DATA__ to determine which page to hydrate.
439
474
  */
440
475
  async function generateClientEntry$1() {
441
- const appPrefetchRoutes = hasAppDir ? (await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher)).filter(isLinkPrefetchRoute).map(toLinkPrefetchRoute) : [];
476
+ const appPrefetchRoutes = hasAppDir ? (await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher)).map((route) => isLinkPrefetchRoute(route) ? toLinkPrefetchRoute(route) : toDocumentOnlyAppRoute(route)) : [];
442
477
  return generateClientEntry(pagesDir, nextConfig, fileMatcher, {
443
478
  appPrefetchRoutes,
444
479
  instrumentationClientPath
@@ -484,6 +519,9 @@ function vinext(options = {}) {
484
519
  });
485
520
  }
486
521
  const imageImportDimCache = /* @__PURE__ */ new Map();
522
+ const staticImageAssets = /* @__PURE__ */ new Map();
523
+ const staticImageImportsByModule = /* @__PURE__ */ new Map();
524
+ const writtenStaticImageFiles = /* @__PURE__ */ new Set();
487
525
  let mdxDelegate = null;
488
526
  let mdxDelegatePromise = null;
489
527
  let hasUserMdxPlugin = false;
@@ -560,7 +598,7 @@ function vinext(options = {}) {
560
598
  for (const [key, value] of Object.entries(dotenvVars)) if (process.env[key] === void 0) process.env[key] = value;
561
599
  let resolvedNodeEnv;
562
600
  if (mode === "test") resolvedNodeEnv = "test";
563
- else if (env?.command === "build") resolvedNodeEnv = "production";
601
+ else if (env?.command === "build" || env?.isPreview === true) resolvedNodeEnv = "production";
564
602
  else resolvedNodeEnv = "development";
565
603
  if (process.env.NODE_ENV !== resolvedNodeEnv) process.env.NODE_ENV = resolvedNodeEnv;
566
604
  let baseDir;
@@ -575,6 +613,7 @@ function vinext(options = {}) {
575
613
  else baseDir = root;
576
614
  }
577
615
  pagesDir = path.posix.join(baseDir, "pages");
616
+ canonicalPagesDir = canonicalize(pagesDir);
578
617
  appDir = path.posix.join(baseDir, "app");
579
618
  hasPagesDir = fs.existsSync(pagesDir);
580
619
  hasAppDir = !options.disableAppRouter && fs.existsSync(appDir);
@@ -589,7 +628,7 @@ function vinext(options = {}) {
589
628
  }
590
629
  rawConfig = await resolveNextConfigInput(options.nextConfig, phase);
591
630
  } else rawConfig = await loadNextConfig(root, phase);
592
- nextConfig = await resolveNextConfig(rawConfig, root);
631
+ nextConfig = await resolveNextConfig(rawConfig, root, { dev: env?.command === "serve" && env?.isPreview !== true });
593
632
  const sharedBuildId = process.env.__VINEXT_SHARED_BUILD_ID;
594
633
  if (sharedBuildId && sharedBuildId.length > 0) nextConfig = {
595
634
  ...nextConfig,
@@ -608,7 +647,10 @@ function vinext(options = {}) {
608
647
  clientInjectModule = instrumentationClientInjects.length ? generateInstrumentationClientInjectModule(instrumentationClientInjects, instrumentationClientPath, INSTRUMENTATION_CLIENT_EMPTY_MODULE) : null;
609
648
  if (env?.command === "build") await writeRouteTypes();
610
649
  const defines = getNextPublicEnvDefines();
611
- if (!config.define || typeof config.define !== "object" || !("process.env.NODE_ENV" in config.define)) defines["process.env.NODE_ENV"] = JSON.stringify(resolvedNodeEnv);
650
+ const userNodeEnvDefine = config.define?.["process.env.NODE_ENV"];
651
+ const hasUserNodeEnvDefine = Object.hasOwn(config.define ?? {}, "process.env.NODE_ENV");
652
+ const nodeEnvDefine = hasUserNodeEnvDefine ? serializeViteDefine(userNodeEnvDefine) : JSON.stringify(resolvedNodeEnv);
653
+ if (!hasUserNodeEnvDefine) defines["process.env.NODE_ENV"] = nodeEnvDefine;
612
654
  for (const [key, value] of Object.entries(nextConfig.env)) {
613
655
  if (key === "NODE_ENV") continue;
614
656
  defines[`process.env.${key}`] = JSON.stringify(value);
@@ -617,6 +659,8 @@ function vinext(options = {}) {
617
659
  defines["process.env.__NEXT_CLIENT_ROUTER_STATIC_STALETIME"] = JSON.stringify(String(nextConfig.staleTimes.static));
618
660
  defines["process.env.__VINEXT_PREFETCH_INLINING"] = JSON.stringify(nextConfig.prefetchInlining ? "true" : "false");
619
661
  defines["process.env.__NEXT_GESTURE_TRANSITION"] = JSON.stringify(nextConfig.gestureTransition);
662
+ defines["process.env.__NEXT_APP_NAV_FAIL_HANDLING"] = JSON.stringify(nextConfig.appNavFailHandling);
663
+ defines["process.env.__NEXT_SCROLL_RESTORATION"] = JSON.stringify(nextConfig.scrollRestoration ? "true" : "false");
620
664
  defines["process.env.__VINEXT_TRAILING_SLASH"] = JSON.stringify(nextConfig.trailingSlash ? "true" : "false");
621
665
  defines["process.env.__VINEXT_IMAGE_REMOTE_PATTERNS"] = JSON.stringify(JSON.stringify(nextConfig.images?.remotePatterns ?? []));
622
666
  defines["process.env.__VINEXT_IMAGE_DOMAINS"] = JSON.stringify(JSON.stringify(nextConfig.images?.domains ?? []));
@@ -643,6 +687,7 @@ function vinext(options = {}) {
643
687
  ];
644
688
  defines["process.env.__VINEXT_IMAGE_DEVICE_SIZES"] = JSON.stringify(JSON.stringify(deviceSizes));
645
689
  defines["process.env.__VINEXT_IMAGE_SIZES"] = JSON.stringify(JSON.stringify(imageSizes));
690
+ defines["process.env.__VINEXT_IMAGE_QUALITIES"] = JSON.stringify(JSON.stringify(nextConfig.images?.qualities ?? null));
646
691
  }
647
692
  defines["process.env.__VINEXT_IMAGE_DANGEROUSLY_ALLOW_SVG"] = JSON.stringify(String(nextConfig.images?.dangerouslyAllowSVG ?? false));
648
693
  defines["process.env.__VINEXT_IMAGE_DANGEROUSLY_ALLOW_LOCAL_IP"] = JSON.stringify(String(nextConfig.images?.dangerouslyAllowLocalIP ?? false));
@@ -681,7 +726,6 @@ function vinext(options = {}) {
681
726
  "next/web-vitals": path.join(shimsDir, "web-vitals"),
682
727
  "next/amp": path.join(shimsDir, "amp"),
683
728
  "next/offline": path.join(shimsDir, "offline"),
684
- "next/error": path.join(shimsDir, "error"),
685
729
  "next/constants": path.join(shimsDir, "constants"),
686
730
  "next/dist/shared/lib/app-router-context.shared-runtime": path.join(shimsDir, "internal", "app-router-context"),
687
731
  "next/dist/shared/lib/app-router-context": path.join(shimsDir, "internal", "app-router-context"),
@@ -791,7 +835,6 @@ function vinext(options = {}) {
791
835
  ...nextConfig.aliases,
792
836
  ...nextShimMap
793
837
  },
794
- extensions: buildViteResolveExtensions(nextConfig.pageExtensions),
795
838
  dedupe: [
796
839
  "react",
797
840
  "react-dom",
@@ -803,12 +846,15 @@ function vinext(options = {}) {
803
846
  ...viteMajorVersion >= 8 ? { oxc: { jsx: { runtime: "automatic" } } } : { esbuild: { jsx: "automatic" } },
804
847
  define: defines,
805
848
  ...nextConfig.basePath ? { base: nextConfig.basePath + "/" } : {},
806
- ...nextConfig.assetPrefix ? { experimental: { renderBuiltUrl: (filename) => {
807
- const urlPrefix = resolveAssetUrlPrefix(nextConfig.assetPrefix);
808
- const dirPrefix = resolveAssetsDir(nextConfig.assetPrefix) + "/";
809
- return urlPrefix + (filename.startsWith(dirPrefix) ? filename.slice(dirPrefix.length) : filename.startsWith(`_next/static/`) ? filename.slice(ASSET_PREFIX_URL_DIR.length + 1) : filename);
810
- } } } : {},
849
+ ...nextConfig.assetPrefix || nextConfig.deploymentId ? { experimental: { renderBuiltUrl: (filename, context) => renderVinextBuiltUrl(filename, nextConfig.assetPrefix, nextConfig.deploymentId, context.hostType) } } : {},
811
850
  css: {
851
+ ...nextConfig.useLightningcss ? {
852
+ transformer: "lightningcss",
853
+ lightningcss: {
854
+ ...nextConfig.lightningCssFeatures.include ? { include: nextConfig.lightningCssFeatures.include } : {},
855
+ ...nextConfig.lightningCssFeatures.exclude ? { exclude: nextConfig.lightningCssFeatures.exclude } : {}
856
+ }
857
+ } : {},
812
858
  ...postcssOverride ? { postcss: postcssOverride } : {},
813
859
  preprocessorOptions: (() => {
814
860
  const tildeImporter = createSassTildeImporter(root);
@@ -835,10 +881,15 @@ function vinext(options = {}) {
835
881
  if (shimBase !== void 0) return resolveShimModulePath(shimsDir, shimBase);
836
882
  }
837
883
  };
884
+ const depOptimizeNodeEnvOptions = getDepOptimizeNodeEnvOptions(viteMajorVersion, nodeEnvDefine);
838
885
  viteConfig.optimizeDeps = {
839
886
  exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE, ["@tailwindcss/oxide"]),
840
887
  ...incomingInclude.length > 0 ? { include: incomingInclude } : {},
841
- rolldownOptions: { plugins: [depOptimizeAliasPlugin] }
888
+ ...depOptimizeNodeEnvOptions,
889
+ rolldownOptions: {
890
+ ...depOptimizeNodeEnvOptions.rolldownOptions,
891
+ plugins: [depOptimizeAliasPlugin]
892
+ }
842
893
  };
843
894
  const pagesOptimizeEntries = !hasAppDir ? [...hasPagesDir ? [toRelativeFileEntry(root, pagesDir) + "/**/*.{tsx,ts,jsx,js}"] : [], ...[instrumentationPath, instrumentationClientPath].flatMap((entry) => entry ? [toRelativeFileEntry(root, entry)] : [])] : [];
844
895
  if (hasAppDir) {
@@ -860,7 +911,9 @@ function vinext(options = {}) {
860
911
  } },
861
912
  optimizeDeps: {
862
913
  exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE),
863
- entries: optimizeEntries
914
+ entries: optimizeEntries,
915
+ include: [...new Set([...incomingInclude, "react-server-dom-webpack/static.edge"])],
916
+ ...depOptimizeNodeEnvOptions
864
917
  },
865
918
  build: {
866
919
  outDir: options.rscOutDir ?? "dist/server",
@@ -877,7 +930,8 @@ function vinext(options = {}) {
877
930
  } },
878
931
  optimizeDeps: {
879
932
  exclude: mergeOptimizeDepsExclude(incomingExclude, VINEXT_OPTIMIZE_DEPS_EXCLUDE, ["ipaddr.js"], userSsrExternal === true ? SSR_EXTERNAL_REACT_ENTRIES : []),
880
- entries: optimizeEntries
933
+ entries: optimizeEntries,
934
+ ...depOptimizeNodeEnvOptions
881
935
  },
882
936
  build: {
883
937
  outDir: options.ssrOutDir ?? "dist/server/ssr",
@@ -950,7 +1004,10 @@ function vinext(options = {}) {
950
1004
  ],
951
1005
  noExternal: true
952
1006
  },
953
- optimizeDeps: { exclude: ["ipaddr.js"] },
1007
+ optimizeDeps: {
1008
+ exclude: ["ipaddr.js"],
1009
+ ...depOptimizeNodeEnvOptions
1010
+ },
954
1011
  build: {
955
1012
  outDir: "dist/server",
956
1013
  ...withBuildBundlerOptions(viteMajorVersion, {
@@ -966,8 +1023,29 @@ function vinext(options = {}) {
966
1023
  };
967
1024
  return viteConfig;
968
1025
  },
969
- configResolved(config) {
1026
+ configEnvironment(name, config) {
1027
+ const configuredExtensions = name === "client" ? nextConfig.resolveExtensions : nextConfig.serverResolveExtensions;
1028
+ const extensions = configuredExtensions === null ? buildViteResolveExtensions(nextConfig.pageExtensions, config.resolve?.extensions) : normalizeViteResolveExtensions(configuredExtensions);
1029
+ config.resolve ??= {};
1030
+ config.resolve.extensions = extensions;
1031
+ return null;
1032
+ },
1033
+ async configResolved(config) {
970
1034
  sassComposesLoader.setResolvedConfig(config);
1035
+ if (config.command === "build" && hasAppDir && hasPagesDir) {
1036
+ const [appRoutes, pageRoutes, apiRoutes] = await Promise.all([
1037
+ appRouter(appDir, nextConfig?.pageExtensions, fileMatcher),
1038
+ pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher),
1039
+ apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher)
1040
+ ]);
1041
+ validateHybridRouteConflicts([...pageRoutes, ...apiRoutes].map((route) => ({
1042
+ ...route,
1043
+ sourcePath: path.relative(root, route.filePath)
1044
+ })), appRoutes.filter((route) => route.pagePath !== null || route.routePath !== null).map((route) => ({
1045
+ ...route,
1046
+ sourcePath: path.relative(root, route.pagePath ?? route.routePath)
1047
+ })));
1048
+ }
971
1049
  if (hasAppDir) {
972
1050
  const ssrEnv = config.environments?.ssr;
973
1051
  if (ssrEnv?.resolve?.external === true && Array.isArray(ssrEnv.resolve.noExternal)) ssrEnv.resolve.noExternal = ssrEnv.resolve.noExternal.filter((entry) => typeof entry !== "string" || !SSR_EXTERNAL_REACT_ENTRIES.includes(entry));
@@ -989,10 +1067,11 @@ function vinext(options = {}) {
989
1067
  }));
990
1068
  },
991
1069
  resolveId: {
992
- filter: { id: /(?:next\/|virtual:vinext-|^@vercel\/og(?:\.js)?$)/ },
1070
+ filter: { id: /(?:next\/|vinext\/shims\/|virtual:vinext-|@vercel\/og(?:\.js)?$)/ },
993
1071
  handler(id, importer) {
994
1072
  const cleanId = id.startsWith("\0") ? id.slice(1) : id;
995
1073
  if (isVercelOgImport(cleanId) && !isVinextOgShimImporter(importer)) return resolveShimModulePath(_shimsDir, "og");
1074
+ if (cleanId.startsWith("vinext/shims/")) return resolveShimModulePath(_shimsDir, stripJsExtension(stripViteModuleQuery(cleanId.slice(13))));
996
1075
  if (cleanId === VIRTUAL_SERVER_ENTRY) return RESOLVED_SERVER_ENTRY;
997
1076
  if (cleanId === VIRTUAL_CLIENT_ENTRY) return RESOLVED_CLIENT_ENTRY;
998
1077
  if (cleanId.endsWith("/virtual:vinext-server-entry") || cleanId.endsWith("\\virtual:vinext-server-entry")) return RESOLVED_SERVER_ENTRY;
@@ -1038,7 +1117,13 @@ function vinext(options = {}) {
1038
1117
  reactMaxHeadersLength: nextConfig?.reactMaxHeadersLength,
1039
1118
  cacheMaxMemorySize: nextConfig?.cacheMaxMemorySize,
1040
1119
  inlineCss: nextConfig?.inlineCss,
1120
+ cacheComponents: nextConfig?.cacheComponents,
1041
1121
  i18n: nextConfig?.i18n,
1122
+ imageConfig: {
1123
+ deviceSizes: nextConfig?.images?.deviceSizes,
1124
+ imageSizes: nextConfig?.images?.imageSizes,
1125
+ qualities: nextConfig?.images?.qualities
1126
+ },
1042
1127
  hasPagesDir,
1043
1128
  publicFiles: scanPublicFileRoutes(root),
1044
1129
  globalNotFoundPath,
@@ -1050,7 +1135,17 @@ function vinext(options = {}) {
1050
1135
  if (id === RESOLVED_APP_SSR_ENTRY && hasAppDir) return generateSsrEntry(hasPagesDir);
1051
1136
  if (id === RESOLVED_APP_BROWSER_ENTRY && hasAppDir) {
1052
1137
  const graph = await appRouteGraph(appDir, nextConfig?.pageExtensions, fileMatcher);
1053
- return generateBrowserEntry(graph.routes, graph.routeManifest);
1138
+ const pagesPrefetchRoutes = hasPagesDir ? [...(await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher)).map((route) => ({
1139
+ canPrefetchLoadingShell: false,
1140
+ isDynamic: route.isDynamic,
1141
+ patternParts: [...route.patternParts]
1142
+ })), ...(await apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher)).map((route) => ({
1143
+ canPrefetchLoadingShell: false,
1144
+ documentOnly: true,
1145
+ isDynamic: route.isDynamic,
1146
+ patternParts: [...route.patternParts]
1147
+ }))] : [];
1148
+ return generateBrowserEntry(graph.routes, graph.routeManifest, pagesPrefetchRoutes, nextConfig.rewrites);
1054
1149
  }
1055
1150
  if (id.startsWith("\0virtual:vinext-google-fonts?")) return generateGoogleFontsVirtualModule(id, _fontGoogleShimPath);
1056
1151
  },
@@ -1257,11 +1352,65 @@ function vinext(options = {}) {
1257
1352
  if (mod) env.moduleGraph.invalidateModule(mod);
1258
1353
  }
1259
1354
  }
1355
+ function invalidateHybridClientEntries() {
1356
+ if (!hasAppDir || !hasPagesDir) return;
1357
+ for (const env of Object.values(server.environments)) for (const id of [RESOLVED_CLIENT_ENTRY, RESOLVED_APP_BROWSER_ENTRY]) {
1358
+ const mod = env.moduleGraph.getModuleById(id);
1359
+ if (mod) env.moduleGraph.invalidateModule(mod);
1360
+ }
1361
+ server.ws.send({ type: "full-reload" });
1362
+ }
1363
+ function invalidatePagesServerEntry() {
1364
+ for (const env of Object.values(server.environments)) {
1365
+ const mod = env.moduleGraph.getModuleById(RESOLVED_SERVER_ENTRY);
1366
+ if (mod) env.moduleGraph.invalidateModule(mod);
1367
+ }
1368
+ pagesRunner?.clearCache();
1369
+ }
1260
1370
  function invalidateAppRoutingModules() {
1261
1371
  invalidateAppRouteCache();
1262
1372
  invalidateRscEntryModule();
1263
1373
  invalidateRootParamsModule();
1264
1374
  }
1375
+ let hybridRouteValidation = Promise.resolve();
1376
+ let hybridRouteValidationError = null;
1377
+ function sendHybridRouteValidationError(error) {
1378
+ server.ws.send({
1379
+ type: "error",
1380
+ err: {
1381
+ message: error.message,
1382
+ stack: error.stack ?? error.message
1383
+ }
1384
+ });
1385
+ }
1386
+ server.ws.on("connection", () => {
1387
+ if (hybridRouteValidationError) sendHybridRouteValidationError(hybridRouteValidationError);
1388
+ });
1389
+ function revalidateHybridRoutes() {
1390
+ if (!hasAppDir || !hasPagesDir) return;
1391
+ hybridRouteValidation = hybridRouteValidation.catch(() => {}).then(async () => {
1392
+ const [appRoutes, pageRoutes, apiRoutes] = await Promise.all([
1393
+ appRouter(appDir, nextConfig?.pageExtensions, fileMatcher),
1394
+ pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher),
1395
+ apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher)
1396
+ ]);
1397
+ validateHybridRouteConflicts([...pageRoutes, ...apiRoutes].map((route) => ({
1398
+ ...route,
1399
+ sourcePath: path.relative(root, route.filePath)
1400
+ })), appRoutes.filter((route) => route.pagePath !== null || route.routePath !== null).map((route) => ({
1401
+ ...route,
1402
+ sourcePath: path.relative(root, route.pagePath ?? route.routePath)
1403
+ })));
1404
+ if (hybridRouteValidationError) {
1405
+ hybridRouteValidationError = null;
1406
+ server.ws.send({ type: "full-reload" });
1407
+ }
1408
+ }).catch((error) => {
1409
+ const err = error instanceof Error ? error : new Error(String(error));
1410
+ hybridRouteValidationError = err;
1411
+ sendHybridRouteValidationError(err);
1412
+ });
1413
+ }
1265
1414
  let appRouteTypeGeneration = null;
1266
1415
  let appRouteTypeGenerationPending = false;
1267
1416
  function warnRouteTypeGenerationFailure(error) {
@@ -1286,21 +1435,42 @@ function vinext(options = {}) {
1286
1435
  });
1287
1436
  }
1288
1437
  regenerateAppRouteTypes();
1438
+ revalidateHybridRoutes();
1289
1439
  server.httpServer?.on("connection", (socket) => {
1290
1440
  socket.on("error", () => {});
1291
1441
  });
1292
1442
  server.watcher.on("add", (filePath) => {
1293
- if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) invalidateRouteCache(pagesDir);
1443
+ let routeChanged = false;
1444
+ if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) {
1445
+ invalidateRouteCache(pagesDir);
1446
+ routeChanged = true;
1447
+ }
1294
1448
  if (hasAppDir && shouldInvalidateAppRouteFile(appDir, filePath, fileMatcher)) {
1295
1449
  invalidateAppRoutingModules();
1296
1450
  regenerateAppRouteTypes();
1451
+ routeChanged = true;
1452
+ }
1453
+ if (routeChanged) {
1454
+ invalidatePagesServerEntry();
1455
+ invalidateHybridClientEntries();
1456
+ revalidateHybridRoutes();
1297
1457
  }
1298
1458
  });
1299
1459
  server.watcher.on("unlink", (filePath) => {
1300
- if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) invalidateRouteCache(pagesDir);
1460
+ let routeChanged = false;
1461
+ if (hasPagesDir && filePath.startsWith(pagesDir) && pageExtensions.test(filePath)) {
1462
+ invalidateRouteCache(pagesDir);
1463
+ routeChanged = true;
1464
+ }
1301
1465
  if (hasAppDir && shouldInvalidateAppRouteFile(appDir, filePath, fileMatcher)) {
1302
1466
  invalidateAppRoutingModules();
1303
1467
  regenerateAppRouteTypes();
1468
+ routeChanged = true;
1469
+ }
1470
+ if (routeChanged) {
1471
+ invalidatePagesServerEntry();
1472
+ invalidateHybridClientEntries();
1473
+ revalidateHybridRoutes();
1304
1474
  }
1305
1475
  });
1306
1476
  server.middlewares.use((req, res, next) => {
@@ -1321,6 +1491,51 @@ function vinext(options = {}) {
1321
1491
  });
1322
1492
  installDevStackSourcemapMiddleware(server);
1323
1493
  return () => {
1494
+ const viteFilesystemMiddlewares = server.middlewares.stack.filter(({ handle }) => {
1495
+ const name = typeof handle === "function" ? handle.name : "";
1496
+ return name === "viteServePublicMiddleware" || name === "viteServeStaticMiddleware";
1497
+ }).map(({ handle }) => handle).filter((handle) => typeof handle === "function");
1498
+ const serveRewrittenViteFilesystemRoute = async (req, res, requestPathname, stagedHeaders) => {
1499
+ const originalUrl = req.url;
1500
+ const originalStatusCode = res.statusCode;
1501
+ const originalStatusMessage = res.statusMessage;
1502
+ const originalHeaders = res.getHeaders();
1503
+ req.url = requestPathname;
1504
+ for (const [key, value] of Object.entries(stagedHeaders)) res.setHeader(key, value);
1505
+ const restore = () => {
1506
+ req.url = originalUrl;
1507
+ res.statusCode = originalStatusCode;
1508
+ res.statusMessage = originalStatusMessage;
1509
+ for (const key of Object.keys(res.getHeaders())) res.removeHeader(key);
1510
+ for (const [key, value] of Object.entries(originalHeaders)) if (value !== void 0) res.setHeader(key, value);
1511
+ };
1512
+ try {
1513
+ for (const middleware of viteFilesystemMiddlewares) if (await new Promise((resolve, reject) => {
1514
+ let settled = false;
1515
+ const settle = (value, error) => {
1516
+ if (settled) return;
1517
+ settled = true;
1518
+ res.off("finish", onServed);
1519
+ res.off("close", onServed);
1520
+ if (error) reject(error);
1521
+ else resolve(value);
1522
+ };
1523
+ const onServed = () => settle("served");
1524
+ res.once("finish", onServed);
1525
+ res.once("close", onServed);
1526
+ middleware(req, res, (error) => settle("next", error));
1527
+ if (res.writableEnded) settle("served");
1528
+ }) === "served") {
1529
+ req.url = originalUrl;
1530
+ return true;
1531
+ }
1532
+ } catch (error) {
1533
+ restore();
1534
+ throw error;
1535
+ }
1536
+ restore();
1537
+ return false;
1538
+ };
1324
1539
  if (instrumentationPath && !hasAppDir) runInstrumentation(getPagesRunner(), instrumentationPath).catch((err) => {
1325
1540
  console.error("[vinext] Instrumentation error:", err);
1326
1541
  });
@@ -1377,6 +1592,7 @@ function vinext(options = {}) {
1377
1592
  const handlePagesMiddleware = async (req, res, next) => {
1378
1593
  try {
1379
1594
  let url = req.url ?? "/";
1595
+ const originalRequestUrl = url;
1380
1596
  if (!hasPagesDir) return next();
1381
1597
  if (url.startsWith("/@") || url.startsWith("/__vite") || url.startsWith("/node_modules")) return next();
1382
1598
  if (url.split("?")[0].endsWith(".rsc")) return next();
@@ -1394,20 +1610,12 @@ function vinext(options = {}) {
1394
1610
  return;
1395
1611
  }
1396
1612
  if (isImageOptimizationPath(url.split("?")[0])) {
1397
- const rawImgUrl = new URLSearchParams(url.split("?")[1] ?? "").get("url");
1398
- const imgUrl = rawImgUrl?.replaceAll("\\", "/") ?? null;
1399
- if (!imgUrl || !imgUrl.startsWith("/") || imgUrl.startsWith("//") || imgUrl.startsWith("/@") || imgUrl.startsWith("/__vite") || imgUrl.startsWith("/node_modules")) {
1400
- res.writeHead(400);
1401
- res.end(!rawImgUrl ? "Missing url parameter" : "Only relative URLs allowed");
1402
- return;
1403
- }
1404
- const resolvedImg = new URL(imgUrl, `http://${req.headers.host || "localhost"}`);
1405
- if (resolvedImg.origin !== `http://${req.headers.host || "localhost"}`) {
1613
+ const encodedLocation = resolveDevImageRedirect(new URL(url, `http://${req.headers.host || "localhost"}`), [...nextConfig.images?.deviceSizes ?? DEFAULT_DEVICE_SIZES, ...nextConfig.images?.imageSizes ?? DEFAULT_IMAGE_SIZES], nextConfig.images?.qualities);
1614
+ if (!encodedLocation) {
1406
1615
  res.writeHead(400);
1407
- res.end("Only relative URLs allowed");
1616
+ res.end("Invalid image optimization parameters");
1408
1617
  return;
1409
1618
  }
1410
- const encodedLocation = resolvedImg.pathname + resolvedImg.search;
1411
1619
  res.writeHead(302, { Location: encodedLocation });
1412
1620
  res.end();
1413
1621
  return;
@@ -1449,6 +1657,7 @@ function vinext(options = {}) {
1449
1657
  return;
1450
1658
  }
1451
1659
  }
1660
+ if (hasCloudflarePlugin) return next();
1452
1661
  let isDataReq = false;
1453
1662
  if (isNextDataPathname(pathname)) {
1454
1663
  const devBuildId = nextConfig?.buildId ?? process.env.__VINEXT_BUILD_ID ?? "development";
@@ -1468,10 +1677,17 @@ function vinext(options = {}) {
1468
1677
  return;
1469
1678
  }
1470
1679
  }
1471
- if (pathname.includes(".") && !pathname.endsWith(".html")) return next();
1472
- if (hasCloudflarePlugin) return next();
1473
- const rawHeaders = new Headers(Object.fromEntries(Object.entries(req.headers).filter(([, v]) => v !== void 0).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
1474
- const isDataRequest = rawHeaders.get("x-nextjs-data") === "1";
1680
+ const filePathMatchesRewrite = [
1681
+ ...nextConfig?.rewrites.beforeFiles ?? [],
1682
+ ...nextConfig?.rewrites.afterFiles ?? [],
1683
+ ...nextConfig?.rewrites.fallback ?? []
1684
+ ].some((rewrite) => matchesRewriteSource(pathname, rewrite, {
1685
+ basePath: bp,
1686
+ hadBasePath: true
1687
+ }));
1688
+ if (pathname.includes(".") && !pathname.endsWith(".html") && !filePathMatchesRewrite) return next();
1689
+ const rawHeaders = new Headers(Object.fromEntries(Object.entries(req.headers).filter(([k, v]) => v !== void 0 && !k.startsWith(":")).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : String(v)])));
1690
+ const isDataRequest = isDataReq;
1475
1691
  const nodeRequestHeaders = filterInternalHeaders(rawHeaders);
1476
1692
  for (const header of INTERNAL_HEADERS) delete req.headers[header];
1477
1693
  for (const header of VINEXT_INTERNAL_HEADERS) delete req.headers[header];
@@ -1542,6 +1758,10 @@ function vinext(options = {}) {
1542
1758
  externalInit.duplex = "half";
1543
1759
  }
1544
1760
  return proxyExternalRequest(new Request(new URL(url, requestOrigin), externalInit), externalUrl);
1761
+ },
1762
+ serveFilesystemRoute: async (requestPathname, stagedHeaders, phase) => {
1763
+ if (phase === "direct" || req.method !== "GET" && req.method !== "HEAD" || requestPathname === "/" || requestPathname === "/api" || requestPathname.startsWith("/api/")) return false;
1764
+ return serveRewrittenViteFilesystemRoute(req, res, requestPathname, stagedHeaders);
1545
1765
  }
1546
1766
  });
1547
1767
  if (pipelineResult.type === "response") {
@@ -1559,12 +1779,22 @@ function vinext(options = {}) {
1559
1779
  };
1560
1780
  if (pipelineResult.type === "api") {
1561
1781
  const apiRoutes = await apiRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
1562
- if (matchRoute(pipelineResult.apiUrl, apiRoutes)) {
1782
+ const apiMatch = matchRoute(pipelineResult.apiUrl, apiRoutes);
1783
+ if (apiMatch && hasAppDir && appDir) {
1784
+ const appRoutes = await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher);
1785
+ const appMatch = matchAppRoute(pipelineResult.apiUrl, appRoutes);
1786
+ if (appMatch && !pagesRouteHasPriorityOverAppRoute(apiMatch.route, appMatch.route)) return next();
1787
+ }
1788
+ if (apiMatch) {
1563
1789
  flushStagedHeaders();
1564
1790
  flushRequestHeaders();
1565
1791
  if (pipelineResult.middlewareStatus !== void 0) req.__vinextMiddlewareStatus = pipelineResult.middlewareStatus;
1566
1792
  }
1567
- if (await handleApiRoute(getPagesRunner(), req, res, pipelineResult.apiUrl, apiRoutes)) return;
1793
+ if (await handleApiRoute(getPagesRunner(), req, res, pipelineResult.apiUrl, apiRoutes, {
1794
+ basePath: nextConfig?.basePath,
1795
+ i18n: nextConfig?.i18n,
1796
+ trailingSlash: nextConfig?.trailingSlash
1797
+ })) return;
1568
1798
  if (hasAppDir) return next();
1569
1799
  res.statusCode = 404;
1570
1800
  res.end("404 - API route not found");
@@ -1572,13 +1802,19 @@ function vinext(options = {}) {
1572
1802
  }
1573
1803
  {
1574
1804
  const routes = await pagesRouter(pagesDir, nextConfig?.pageExtensions, fileMatcher);
1575
- if (!matchRoute(pipelineResult.resolvedUrl.split("?")[0], routes) && hasAppDir) return next();
1576
- const handler = createSSRHandler(server, getPagesRunner(), routes, pagesDir, nextConfig?.i18n, fileMatcher, nextConfig?.basePath ?? "", nextConfig?.trailingSlash ?? false, middlewarePath !== null, (nextConfig?.rewrites.beforeFiles.length ?? 0) > 0 || (nextConfig?.rewrites.afterFiles.length ?? 0) > 0 || (nextConfig?.rewrites.fallback.length ?? 0) > 0, nextConfig?.clientTraceMetadata);
1805
+ const resolvedPathname = pipelineResult.resolvedUrl.split("#", 1)[0].split("?", 1)[0];
1806
+ const renderMatch = matchRoute(resolvedPathname, routes);
1807
+ if (hasAppDir && appDir) {
1808
+ if (!renderMatch) return next();
1809
+ const appMatch = matchAppRoute(resolvedPathname, await appRouter(appDir, nextConfig?.pageExtensions, fileMatcher));
1810
+ if (appMatch && !pagesRouteHasPriorityOverAppRoute(renderMatch.route, appMatch.route)) return next();
1811
+ }
1812
+ const handler = createSSRHandler(server, getPagesRunner(), routes, pagesDir, nextConfig?.i18n, fileMatcher, nextConfig?.basePath ?? "", nextConfig?.trailingSlash ?? false, middlewarePath !== null, (nextConfig?.rewrites.beforeFiles.length ?? 0) > 0 || (nextConfig?.rewrites.afterFiles.length ?? 0) > 0 || (nextConfig?.rewrites.fallback.length ?? 0) > 0, nextConfig?.clientTraceMetadata, nextConfig?.htmlLimitedBots);
1577
1813
  flushStagedHeaders();
1578
1814
  flushRequestHeaders();
1579
1815
  if (pipelineResult.middlewareStatus !== void 0) req.__vinextMiddlewareStatus = pipelineResult.middlewareStatus;
1580
1816
  req.url = pipelineResult.resolvedUrl;
1581
- await handler(req, res, pipelineResult.resolvedUrl, req.__vinextMiddlewareStatus, pipelineResult.isDataReq);
1817
+ await handler(req, res, pipelineResult.resolvedUrl, req.__vinextMiddlewareStatus, pipelineResult.isDataReq, originalRequestUrl);
1582
1818
  }
1583
1819
  } catch (e) {
1584
1820
  next(e);
@@ -1590,6 +1826,42 @@ function vinext(options = {}) {
1590
1826
  };
1591
1827
  }
1592
1828
  },
1829
+ {
1830
+ name: "vinext:validate-page-exports",
1831
+ transform: { handler(code, id) {
1832
+ if (this.environment?.name !== "client") return null;
1833
+ if (!hasPagesDir || id.startsWith("\0") || !hasExportAllCandidate(code)) return null;
1834
+ const modulePath = stripViteModuleQuery(id);
1835
+ if (!isWithinPagesDirectory(modulePath)) return null;
1836
+ const canonicalId = canonicalizePageTransformPath(modulePath);
1837
+ if (!isWithinPagesDirectory(canonicalId)) return null;
1838
+ if (!fileMatcher.isPageFile(canonicalId)) return null;
1839
+ if (isApiPage(canonicalId)) return null;
1840
+ validatePageExports(code);
1841
+ return null;
1842
+ } }
1843
+ },
1844
+ {
1845
+ name: "vinext:strip-server-exports",
1846
+ transform: { handler(code, id) {
1847
+ if (this.environment?.name !== "client") return null;
1848
+ if (!hasPagesDir || id.startsWith("\0") || !hasServerExportCandidate(code)) return null;
1849
+ const modulePath = stripViteModuleQuery(id);
1850
+ if (!isWithinPagesDirectory(modulePath)) return null;
1851
+ const canonicalId = canonicalizePageTransformPath(modulePath);
1852
+ if (!isWithinPagesDirectory(canonicalId)) return null;
1853
+ if (!fileMatcher.isPageFile(canonicalId)) return null;
1854
+ const relativePath = canonicalId.slice(canonicalPagesDir.length);
1855
+ if (isApiPage(canonicalId)) return null;
1856
+ if (/^\/(?:_app|_document|_error)(?:\.[^/]*)?$/.test(relativePath)) return null;
1857
+ const result = stripServerExports(code);
1858
+ if (!result) return null;
1859
+ return {
1860
+ code: result,
1861
+ map: null
1862
+ };
1863
+ } }
1864
+ },
1593
1865
  {
1594
1866
  name: "vinext:validate-server-only-client-imports",
1595
1867
  transform: {
@@ -1600,31 +1872,12 @@ function vinext(options = {}) {
1600
1872
  handler(code, id) {
1601
1873
  if (this.environment?.name !== "client") return null;
1602
1874
  if (id.startsWith("\0")) return null;
1875
+ if (getLeadingReactDirective(code) === "use server") return null;
1603
1876
  if (!hasServerOnlyMarkerImport(code)) return null;
1604
1877
  throw new Error(`You're importing a module that depends on "server-only". This API is only available in Server Components in the App Router, but this module is reachable from a client bundle.`);
1605
1878
  }
1606
1879
  }
1607
1880
  },
1608
- {
1609
- name: "vinext:strip-server-exports",
1610
- transform: {
1611
- filter: { id: /\.(tsx?|jsx?|mjs)$/ },
1612
- handler(code, id) {
1613
- if (this.environment?.name !== "client") return null;
1614
- if (!hasPagesDir) return null;
1615
- if (!id.startsWith(pagesDir)) return null;
1616
- const relativePath = id.slice(pagesDir.length);
1617
- if (relativePath.startsWith("/api/") || relativePath === "/api") return null;
1618
- if (/\/_(?:app|document|error)\b/.test(relativePath)) return null;
1619
- const result = stripServerExports(code);
1620
- if (!result) return null;
1621
- return {
1622
- code: result,
1623
- map: null
1624
- };
1625
- }
1626
- }
1627
- },
1628
1881
  {
1629
1882
  name: "vinext:remove-console",
1630
1883
  apply: "build",
@@ -1643,6 +1896,16 @@ function vinext(options = {}) {
1643
1896
  }
1644
1897
  }
1645
1898
  },
1899
+ {
1900
+ name: "vinext:typeof-window",
1901
+ enforce: "post",
1902
+ transform: {
1903
+ filter: { code: /typeof\s+window/ },
1904
+ handler(code) {
1905
+ return replaceTypeofWindow(code, getTypeofWindowReplacement(this.environment));
1906
+ }
1907
+ }
1908
+ },
1646
1909
  {
1647
1910
  name: "vinext:compiler-define-server",
1648
1911
  configEnvironment(name) {
@@ -1658,16 +1921,36 @@ function vinext(options = {}) {
1658
1921
  name: "vinext:image-imports",
1659
1922
  enforce: "pre",
1660
1923
  _dimCache: imageImportDimCache,
1924
+ buildStart() {
1925
+ imageImportDimCache.clear();
1926
+ staticImageAssets.clear();
1927
+ },
1928
+ watchChange(id) {
1929
+ imageImportDimCache.delete(id);
1930
+ staticImageAssets.delete(id);
1931
+ staticImageImportsByModule.delete(id);
1932
+ },
1661
1933
  resolveId: {
1662
- filter: { id: /\?vinext-meta$/ },
1934
+ filter: { id: /\?vinext-(?:image-url|meta)$/ },
1663
1935
  handler(source, _importer) {
1664
- if (!source.endsWith("?vinext-meta")) return null;
1665
- return `\0vinext-image-meta:${source.replace("?vinext-meta", "")}`;
1936
+ if (source.endsWith("?vinext-image-url")) return `\0vinext-image-url:${source.slice(0, -17)}`;
1937
+ if (source.endsWith("?vinext-meta")) return `\0vinext-image-meta:${source.slice(0, -12)}`;
1938
+ return null;
1666
1939
  }
1667
1940
  },
1668
1941
  async load(id) {
1942
+ if (id.startsWith("\0vinext-image-url:")) {
1943
+ const imagePath = id.replace("\0vinext-image-url:", "");
1944
+ this.addWatchFile(imagePath);
1945
+ if (this.environment.config.command === "serve") return `import url from ${JSON.stringify(imagePath + "?url")}; export default url;`;
1946
+ const asset = createStaticImageAsset(imagePath);
1947
+ staticImageAssets.set(imagePath, asset);
1948
+ const builtFileName = `${resolveAssetsDir(nextConfig.assetPrefix)}/${asset.fileName}`;
1949
+ return `export default ${JSON.stringify(renderVinextBuiltUrl(builtFileName, nextConfig.assetPrefix, nextConfig.deploymentId))};`;
1950
+ }
1669
1951
  if (!id.startsWith("\0vinext-image-meta:")) return null;
1670
1952
  const imagePath = id.replace("\0vinext-image-meta:", "");
1953
+ this.addWatchFile(imagePath);
1671
1954
  const cache = imageImportDimCache;
1672
1955
  let dims = cache.get(imagePath);
1673
1956
  if (!dims) try {
@@ -1708,6 +1991,7 @@ function vinext(options = {}) {
1708
1991
  }
1709
1992
  const s = new MagicString(code);
1710
1993
  let hasChanges = false;
1994
+ const imageImports = /* @__PURE__ */ new Set();
1711
1995
  for (const node of ast.body) {
1712
1996
  if (node.type !== "ImportDeclaration") continue;
1713
1997
  const importNode = node;
@@ -1723,18 +2007,45 @@ function vinext(options = {}) {
1723
2007
  const dir = path.dirname(id);
1724
2008
  const absImagePath = normalizePathSeparators(path.resolve(dir, importPath));
1725
2009
  if (!fs.existsSync(absImagePath)) continue;
2010
+ imageImports.add(absImagePath);
1726
2011
  const urlVar = `__vinext_img_url_${varName}`;
1727
2012
  const metaVar = `__vinext_img_meta_${varName}`;
1728
- const replacement = `import ${urlVar} from ${JSON.stringify(importPath)};\nimport ${metaVar} from ${JSON.stringify(absImagePath + "?vinext-meta")};\nconst ${varName} = { src: ${urlVar}, width: ${metaVar}.width, height: ${metaVar}.height };`;
2013
+ const replacement = `import ${urlVar} from ${JSON.stringify(absImagePath + "?vinext-image-url")};\nimport ${metaVar} from ${JSON.stringify(absImagePath + "?vinext-meta")};\nconst ${varName} = { src: ${urlVar}, width: ${metaVar}.width, height: ${metaVar}.height };`;
1729
2014
  s.overwrite(importNode.start, importNode.end, replacement);
1730
2015
  hasChanges = true;
1731
2016
  }
1732
- if (!hasChanges) return null;
2017
+ if (!hasChanges) {
2018
+ staticImageImportsByModule.delete(id);
2019
+ return null;
2020
+ }
2021
+ staticImageImportsByModule.set(id, imageImports);
1733
2022
  return {
1734
2023
  code: s.toString(),
1735
2024
  map: s.generateMap({ hires: "boundary" })
1736
2025
  };
1737
2026
  }
2027
+ },
2028
+ writeBundle: {
2029
+ sequential: true,
2030
+ order: "post",
2031
+ handler(outputOptions) {
2032
+ if (this.environment?.name !== "client") return;
2033
+ const clientOutDir = outputOptions.dir ? path.resolve(root, outputOptions.dir) : path.resolve(root, options.clientOutDir ?? "dist/client");
2034
+ const assetsDir = resolveAssetsDir(nextConfig.assetPrefix);
2035
+ const activeImagePaths = new Set(Array.from(staticImageImportsByModule.values()).flatMap((imports) => [...imports]));
2036
+ const nextWrittenFiles = /* @__PURE__ */ new Set();
2037
+ for (const imagePath of activeImagePaths) {
2038
+ if (!fs.existsSync(imagePath)) continue;
2039
+ const asset = staticImageAssets.get(imagePath) ?? createStaticImageAsset(imagePath);
2040
+ const outputPath = path.join(clientOutDir, assetsDir, asset.fileName);
2041
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
2042
+ fs.writeFileSync(outputPath, asset.source);
2043
+ nextWrittenFiles.add(outputPath);
2044
+ }
2045
+ for (const outputPath of writtenStaticImageFiles) if (!nextWrittenFiles.has(outputPath)) fs.rmSync(outputPath, { force: true });
2046
+ writtenStaticImageFiles.clear();
2047
+ for (const outputPath of nextWrittenFiles) writtenStaticImageFiles.add(outputPath);
2048
+ }
1738
2049
  }
1739
2050
  },
1740
2051
  createGoogleFontsPlugin(_fontGoogleShimPath, _shimsDir),
@@ -1845,6 +2156,7 @@ function vinext(options = {}) {
1845
2156
  }
1846
2157
  },
1847
2158
  createImportMetaUrlPlugin({ getRoot: () => root }),
2159
+ createExtensionlessDynamicImportPlugin(),
1848
2160
  createRequireContextPlugin(),
1849
2161
  createOgInlineFetchAssetsPlugin(),
1850
2162
  createOgAssetsPlugin(),
@@ -1861,6 +2173,9 @@ function vinext(options = {}) {
1861
2173
  const outDir = options.dir;
1862
2174
  if (!outDir) return;
1863
2175
  const imageConfig = {
2176
+ deviceSizes: nextConfig?.images?.deviceSizes,
2177
+ imageSizes: nextConfig?.images?.imageSizes,
2178
+ qualities: nextConfig?.images?.qualities,
1864
2179
  dangerouslyAllowSVG: nextConfig?.images?.dangerouslyAllowSVG,
1865
2180
  contentDispositionType: nextConfig?.images?.contentDispositionType,
1866
2181
  contentSecurityPolicy: nextConfig?.images?.contentSecurityPolicy