vinext 0.0.32 → 0.0.34

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 (95) hide show
  1. package/README.md +7 -6
  2. package/dist/config/next-config.d.ts +2 -0
  3. package/dist/config/next-config.js +4 -0
  4. package/dist/config/next-config.js.map +1 -1
  5. package/dist/deploy.js +52 -4
  6. package/dist/deploy.js.map +1 -1
  7. package/dist/entries/app-browser-entry.js +3 -330
  8. package/dist/entries/app-browser-entry.js.map +1 -1
  9. package/dist/entries/app-rsc-entry.js +444 -1265
  10. package/dist/entries/app-rsc-entry.js.map +1 -1
  11. package/dist/entries/app-ssr-entry.js +4 -460
  12. package/dist/entries/app-ssr-entry.js.map +1 -1
  13. package/dist/entries/pages-server-entry.js +8 -1
  14. package/dist/entries/pages-server-entry.js.map +1 -1
  15. package/dist/entries/runtime-entry-module.d.ts +13 -0
  16. package/dist/entries/runtime-entry-module.js +27 -0
  17. package/dist/entries/runtime-entry-module.js.map +1 -0
  18. package/dist/index.js +302 -23
  19. package/dist/index.js.map +1 -1
  20. package/dist/plugins/optimize-imports.d.ts +38 -0
  21. package/dist/plugins/optimize-imports.js +557 -0
  22. package/dist/plugins/optimize-imports.js.map +1 -0
  23. package/dist/server/app-browser-entry.d.ts +1 -0
  24. package/dist/server/app-browser-entry.js +160 -0
  25. package/dist/server/app-browser-entry.js.map +1 -0
  26. package/dist/server/app-browser-stream.d.ts +33 -0
  27. package/dist/server/app-browser-stream.js +54 -0
  28. package/dist/server/app-browser-stream.js.map +1 -0
  29. package/dist/server/app-page-boundary-render.d.ts +63 -0
  30. package/dist/server/app-page-boundary-render.js +182 -0
  31. package/dist/server/app-page-boundary-render.js.map +1 -0
  32. package/dist/server/app-page-boundary.d.ts +57 -0
  33. package/dist/server/app-page-boundary.js +60 -0
  34. package/dist/server/app-page-boundary.js.map +1 -0
  35. package/dist/server/app-page-cache.d.ts +61 -0
  36. package/dist/server/app-page-cache.js +133 -0
  37. package/dist/server/app-page-cache.js.map +1 -0
  38. package/dist/server/app-page-execution.d.ts +46 -0
  39. package/dist/server/app-page-execution.js +109 -0
  40. package/dist/server/app-page-execution.js.map +1 -0
  41. package/dist/server/app-page-probe.d.ts +17 -0
  42. package/dist/server/app-page-probe.js +35 -0
  43. package/dist/server/app-page-probe.js.map +1 -0
  44. package/dist/server/app-page-render.d.ts +59 -0
  45. package/dist/server/app-page-render.js +174 -0
  46. package/dist/server/app-page-render.js.map +1 -0
  47. package/dist/server/app-page-request.d.ts +58 -0
  48. package/dist/server/app-page-request.js +79 -0
  49. package/dist/server/app-page-request.js.map +1 -0
  50. package/dist/server/app-page-response.d.ts +51 -0
  51. package/dist/server/app-page-response.js +90 -0
  52. package/dist/server/app-page-response.js.map +1 -0
  53. package/dist/server/app-page-stream.d.ts +55 -0
  54. package/dist/server/app-page-stream.js +65 -0
  55. package/dist/server/app-page-stream.js.map +1 -0
  56. package/dist/server/app-route-handler-cache.d.ts +42 -0
  57. package/dist/server/app-route-handler-cache.js +69 -0
  58. package/dist/server/app-route-handler-cache.js.map +1 -0
  59. package/dist/server/app-route-handler-execution.d.ts +64 -0
  60. package/dist/server/app-route-handler-execution.js +100 -0
  61. package/dist/server/app-route-handler-execution.js.map +1 -0
  62. package/dist/server/app-route-handler-policy.d.ts +51 -0
  63. package/dist/server/app-route-handler-policy.js +57 -0
  64. package/dist/server/app-route-handler-policy.js.map +1 -0
  65. package/dist/server/app-route-handler-response.d.ts +26 -0
  66. package/dist/server/app-route-handler-response.js +61 -0
  67. package/dist/server/app-route-handler-response.js.map +1 -0
  68. package/dist/server/app-route-handler-runtime.d.ts +27 -0
  69. package/dist/server/app-route-handler-runtime.js +99 -0
  70. package/dist/server/app-route-handler-runtime.js.map +1 -0
  71. package/dist/server/app-ssr-entry.d.ts +19 -0
  72. package/dist/server/app-ssr-entry.js +105 -0
  73. package/dist/server/app-ssr-entry.js.map +1 -0
  74. package/dist/server/app-ssr-stream.d.ts +30 -0
  75. package/dist/server/app-ssr-stream.js +116 -0
  76. package/dist/server/app-ssr-stream.js.map +1 -0
  77. package/dist/server/prod-server.d.ts +13 -1
  78. package/dist/server/prod-server.js +113 -19
  79. package/dist/server/prod-server.js.map +1 -1
  80. package/dist/server/worker-utils.d.ts +0 -6
  81. package/dist/server/worker-utils.js +41 -5
  82. package/dist/server/worker-utils.js.map +1 -1
  83. package/dist/shims/error-boundary.js +1 -1
  84. package/dist/shims/font-google-base.js +1 -1
  85. package/dist/shims/font-google-base.js.map +1 -1
  86. package/dist/shims/font-google.d.ts +2 -3
  87. package/dist/shims/font-google.js +2 -3
  88. package/dist/shims/metadata.js +3 -3
  89. package/dist/shims/metadata.js.map +1 -1
  90. package/dist/shims/request-state-types.d.ts +2 -2
  91. package/dist/shims/unified-request-context.d.ts +1 -1
  92. package/package.json +1 -1
  93. package/dist/shims/font-google.generated.d.ts +0 -1929
  94. package/dist/shims/font-google.generated.js +0 -1929
  95. package/dist/shims/font-google.generated.js.map +0 -1
package/README.md CHANGED
@@ -480,12 +480,13 @@ Every `next/*` import is shimmed to a Vite-compatible implementation.
480
480
 
481
481
  ### Configuration
482
482
 
483
- | Feature | | Notes |
484
- | ------------------------------------------------ | --- | ------------------------------------------------------------------- |
485
- | `next.config.js` / `.ts` / `.mjs` | ✅ | Function configs, phase argument |
486
- | `rewrites` / `redirects` / `headers` | ✅ | All phases, param interpolation |
487
- | Environment variables (`.env*`, `NEXT_PUBLIC_*`) | ✅ | Auto-loads Next.js-style dotenv files; only public vars are inlined |
488
- | `images` config | 🟡 | Parsed but not used for optimization |
483
+ | Feature | | Notes |
484
+ | ------------------------------------------------ | --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
485
+ | `next.config.js` / `.ts` / `.mjs` | ✅ | Function configs, phase argument |
486
+ | `rewrites` / `redirects` / `headers` | ✅ | All phases, param interpolation |
487
+ | Environment variables (`.env*`, `NEXT_PUBLIC_*`) | ✅ | Auto-loads Next.js-style dotenv files; only public vars are inlined |
488
+ | `images` config | 🟡 | Parsed but not used for optimization |
489
+ | `experimental.optimizePackageImports` | ✅ | Rewrites barrel imports to direct sub-module imports in RSC/SSR environments. A default set (lucide-react, date-fns, radix-ui, antd, MUI, and others) are always optimized. Add package names here to extend the list. |
489
490
 
490
491
  ### Environment variable loading (`.env*`)
491
492
 
@@ -161,6 +161,8 @@ interface ResolvedNextConfig {
161
161
  allowedDevOrigins: string[];
162
162
  /** Extra allowed origins for server action CSRF validation (from experimental.serverActions.allowedOrigins). */
163
163
  serverActionsAllowedOrigins: string[];
164
+ /** Packages whose barrel imports should be optimized (from experimental.optimizePackageImports). */
165
+ optimizePackageImports: string[];
164
166
  /** Parsed body size limit for server actions in bytes (from experimental.serverActions.bodySizeLimit). Defaults to 1MB. */
165
167
  serverActionsBodySizeLimit: number;
166
168
  /**
@@ -180,6 +180,7 @@ async function resolveNextConfig(config, root = process.cwd()) {
180
180
  aliases: {},
181
181
  allowedDevOrigins: [],
182
182
  serverActionsAllowedOrigins: [],
183
+ optimizePackageImports: [],
183
184
  serverActionsBodySizeLimit: 1 * 1024 * 1024,
184
185
  serverExternalPackages: [],
185
186
  buildId
@@ -231,6 +232,8 @@ async function resolveNextConfig(config, root = process.cwd()) {
231
232
  const serverActionsConfig = experimental?.serverActions;
232
233
  const serverActionsAllowedOrigins = Array.isArray(serverActionsConfig?.allowedOrigins) ? serverActionsConfig.allowedOrigins : [];
233
234
  const serverActionsBodySizeLimit = parseBodySizeLimit(serverActionsConfig?.bodySizeLimit);
235
+ const rawOptimize = experimental?.optimizePackageImports;
236
+ const optimizePackageImports = Array.isArray(rawOptimize) ? rawOptimize.filter((x) => typeof x === "string") : [];
234
237
  const legacyServerComponentsExternal = experimental?.serverComponentsExternalPackages;
235
238
  const serverExternalPackages = Array.isArray(config.serverExternalPackages) ? config.serverExternalPackages : Array.isArray(legacyServerComponentsExternal) ? legacyServerComponentsExternal : [];
236
239
  if (config.webpack !== void 0) if (mdx || Object.keys(webpackProbe.aliases).length > 0) console.warn("[vinext] next.config option \"webpack\" is only partially supported. vinext preserves resolve.alias entries and MDX loader settings, but other webpack customization is ignored");
@@ -262,6 +265,7 @@ async function resolveNextConfig(config, root = process.cwd()) {
262
265
  aliases,
263
266
  allowedDevOrigins,
264
267
  serverActionsAllowedOrigins,
268
+ optimizePackageImports,
265
269
  serverActionsBodySizeLimit,
266
270
  serverExternalPackages,
267
271
  buildId
@@ -1 +1 @@
1
- {"version":3,"file":"next-config.js","names":[],"sources":["../../src/config/next-config.ts"],"sourcesContent":["/**\n * next.config.js / next.config.mjs / next.config.ts parser\n *\n * Loads the Next.js config file (if present) and extracts supported options.\n * Unsupported options are logged as warnings.\n */\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport fs from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\nimport { PHASE_DEVELOPMENT_SERVER } from \"../shims/constants.js\";\nimport { normalizePageExtensions } from \"../routing/file-matcher.js\";\nimport { isExternalUrl } from \"./config-matchers.js\";\n\n/**\n * Parse a body size limit value (string or number) into bytes.\n * Accepts Next.js-style strings like \"1mb\", \"500kb\", \"10mb\", bare number strings like \"1048576\" (bytes),\n * and numeric values. Supports b, kb, mb, gb, tb, pb units.\n * Returns the default 1MB if the value is not provided or invalid.\n * Throws if the parsed value is less than 1.\n */\nexport function parseBodySizeLimit(value: string | number | undefined | null): number {\n if (value === undefined || value === null) return 1 * 1024 * 1024;\n if (typeof value === \"number\") {\n if (value < 1) throw new Error(`Body size limit must be a positive number, got ${value}`);\n return value;\n }\n const trimmed = value.trim();\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb|tb|pb)?$/i);\n if (!match) {\n console.warn(\n `[vinext] Invalid bodySizeLimit value: \"${value}\". Expected a number or a string like \"1mb\", \"500kb\". Falling back to 1MB.`,\n );\n return 1 * 1024 * 1024;\n }\n const num = parseFloat(match[1]);\n const unit = (match[2] ?? \"b\").toLowerCase();\n let bytes: number;\n switch (unit) {\n case \"b\":\n bytes = Math.floor(num);\n break;\n case \"kb\":\n bytes = Math.floor(num * 1024);\n break;\n case \"mb\":\n bytes = Math.floor(num * 1024 * 1024);\n break;\n case \"gb\":\n bytes = Math.floor(num * 1024 * 1024 * 1024);\n break;\n case \"tb\":\n bytes = Math.floor(num * 1024 * 1024 * 1024 * 1024);\n break;\n case \"pb\":\n bytes = Math.floor(num * 1024 * 1024 * 1024 * 1024 * 1024);\n break;\n default:\n return 1 * 1024 * 1024;\n }\n if (bytes < 1) throw new Error(`Body size limit must be a positive number, got ${bytes}`);\n return bytes;\n}\n\nexport interface HasCondition {\n type: \"header\" | \"cookie\" | \"query\" | \"host\";\n key: string;\n value?: string;\n}\n\nexport interface NextRedirect {\n source: string;\n destination: string;\n permanent: boolean;\n has?: HasCondition[];\n missing?: HasCondition[];\n}\n\nexport interface NextRewrite {\n source: string;\n destination: string;\n has?: HasCondition[];\n missing?: HasCondition[];\n}\n\nexport interface NextHeader {\n source: string;\n has?: HasCondition[];\n missing?: HasCondition[];\n headers: Array<{ key: string; value: string }>;\n}\n\nexport interface NextI18nConfig {\n /** List of supported locales */\n locales: string[];\n /** The default locale (used when no locale prefix is in the URL) */\n defaultLocale: string;\n /**\n * Whether to auto-detect locale from Accept-Language header.\n * Defaults to true in Next.js.\n */\n localeDetection?: boolean;\n /**\n * Domain-based routing. Each domain maps to a specific locale.\n */\n domains?: Array<{\n domain: string;\n defaultLocale: string;\n locales?: string[];\n http?: boolean;\n }>;\n}\n\n/**\n * MDX compilation options extracted from @next/mdx config.\n * These are passed through to @mdx-js/rollup so that custom\n * remark/rehype/recma plugins configured in next.config work with Vite.\n */\nexport interface MdxOptions {\n remarkPlugins?: unknown[];\n rehypePlugins?: unknown[];\n recmaPlugins?: unknown[];\n}\n\nexport interface NextConfig {\n /** Additional env variables */\n env?: Record<string, string>;\n /** Base URL path prefix */\n basePath?: string;\n /** Whether to add trailing slashes */\n trailingSlash?: boolean;\n /** Internationalization routing config */\n i18n?: NextI18nConfig;\n /** URL redirect rules */\n redirects?: () => Promise<NextRedirect[]> | NextRedirect[];\n /** URL rewrite rules */\n rewrites?: () =>\n | Promise<\n | NextRewrite[]\n | {\n beforeFiles: NextRewrite[];\n afterFiles: NextRewrite[];\n fallback: NextRewrite[];\n }\n >\n | NextRewrite[]\n | {\n beforeFiles: NextRewrite[];\n afterFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n /** Custom response headers */\n headers?: () => Promise<NextHeader[]> | NextHeader[];\n /** Image optimization config */\n images?: {\n remotePatterns?: Array<{\n protocol?: string;\n hostname: string;\n port?: string;\n pathname?: string;\n search?: string;\n }>;\n domains?: string[];\n unoptimized?: boolean;\n /** Allowed device widths for image optimization. Defaults to Next.js defaults: [640, 750, 828, 1080, 1200, 1920, 2048, 3840] */\n deviceSizes?: number[];\n /** Allowed image sizes for fixed-width images. Defaults to Next.js defaults: [16, 32, 48, 64, 96, 128, 256, 384] */\n imageSizes?: number[];\n /** Allow SVG images through the image optimization endpoint. SVG can contain scripts, so only enable if you trust all image sources. */\n dangerouslyAllowSVG?: boolean;\n /** Content-Disposition header for image responses. Defaults to \"inline\". */\n contentDispositionType?: \"inline\" | \"attachment\";\n /** Content-Security-Policy header for image responses. Defaults to \"script-src 'none'; frame-src 'none'; sandbox;\" */\n contentSecurityPolicy?: string;\n };\n /** Build output mode: 'export' for full static export, 'standalone' for single server */\n output?: \"export\" | \"standalone\";\n /** File extensions treated as routable pages/routes (Next.js pageExtensions) */\n pageExtensions?: string[];\n /** Extra origins allowed to access the dev server. */\n allowedDevOrigins?: string[];\n /**\n * Enable Cache Components (Next.js 16).\n * When true, enables the \"use cache\" directive for pages, components, and functions.\n * Replaces the removed experimental.ppr and experimental.dynamicIO flags.\n */\n cacheComponents?: boolean;\n /** Transpile packages (Vite handles this natively) */\n transpilePackages?: string[];\n /**\n * Packages that should be treated as server-external (not bundled by Vite).\n * Corresponds to Next.js `serverExternalPackages` (or the legacy\n * `experimental.serverComponentsExternalPackages`).\n */\n serverExternalPackages?: string[];\n /** Webpack config (ignored — we use Vite) */\n webpack?: unknown;\n /**\n * Custom build ID generator. If provided, called once at build/dev start.\n * Must return a non-empty string, or null to use the default random ID.\n */\n generateBuildId?: () => string | null | Promise<string | null>;\n /** Any other options */\n [key: string]: unknown;\n}\n\n/**\n * Resolved configuration with all async values awaited.\n */\nexport interface ResolvedNextConfig {\n env: Record<string, string>;\n basePath: string;\n trailingSlash: boolean;\n output: \"\" | \"export\" | \"standalone\";\n pageExtensions: string[];\n cacheComponents: boolean;\n redirects: NextRedirect[];\n rewrites: {\n beforeFiles: NextRewrite[];\n afterFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n headers: NextHeader[];\n images: NextConfig[\"images\"];\n i18n: NextI18nConfig | null;\n /** MDX remark/rehype/recma plugins extracted from @next/mdx config */\n mdx: MdxOptions | null;\n /** Explicit module aliases preserved from wrapped next.config plugins. */\n aliases: Record<string, string>;\n /** Extra allowed origins for dev server access (from allowedDevOrigins). */\n allowedDevOrigins: string[];\n /** Extra allowed origins for server action CSRF validation (from experimental.serverActions.allowedOrigins). */\n serverActionsAllowedOrigins: string[];\n /** Parsed body size limit for server actions in bytes (from experimental.serverActions.bodySizeLimit). Defaults to 1MB. */\n serverActionsBodySizeLimit: number;\n /**\n * Packages that should be treated as server-external (not bundled by Vite).\n * Sourced from `serverExternalPackages` or the legacy\n * `experimental.serverComponentsExternalPackages` in next.config.\n */\n serverExternalPackages: string[];\n /** Resolved build ID (from generateBuildId, or a random UUID if not provided). */\n buildId: string;\n}\n\nconst CONFIG_FILES = [\"next.config.ts\", \"next.config.mjs\", \"next.config.js\", \"next.config.cjs\"];\n\n/**\n * Check whether an error indicates a CJS module was loaded in an ESM context\n * (i.e. the file uses `require()` which is not available in ESM).\n */\nfunction isCjsError(e: unknown): boolean {\n if (!(e instanceof Error)) return false;\n const msg = e.message;\n return (\n msg.includes(\"require is not a function\") ||\n msg.includes(\"require is not defined\") ||\n msg.includes(\"exports is not defined\") ||\n msg.includes(\"module is not defined\") ||\n msg.includes(\"__dirname is not defined\") ||\n msg.includes(\"__filename is not defined\")\n );\n}\n\n/**\n * Emit a warning when config loading fails, with a targeted hint for\n * known plugin wrappers that are unnecessary in vinext.\n */\nfunction warnConfigLoadFailure(filename: string, err: Error): void {\n const msg = err.message ?? \"\";\n const stack = err.stack ?? \"\";\n const isNextIntlPlugin =\n msg.includes(\"next-intl\") ||\n stack.includes(\"next-intl/plugin\") ||\n stack.includes(\"next-intl/dist\");\n\n console.log();\n console.error(`[vinext] Failed to load ${filename}: ${msg}`);\n console.log();\n if (isNextIntlPlugin) {\n console.warn(\n \"[vinext] Hint: createNextIntlPlugin() is not needed with vinext. \" +\n \"Remove the next-intl/plugin wrapper from your next.config — \" +\n \"vinext auto-detects next-intl and registers the i18n config alias automatically.\",\n );\n }\n}\n\n/**\n * Unwrap the config value from a loaded module, calling it if it's a\n * function-form config (Next.js supports `module.exports = (phase, opts) => config`).\n */\nasync function unwrapConfig(\n mod: any,\n phase: string = PHASE_DEVELOPMENT_SERVER,\n): Promise<NextConfig> {\n const config = mod.default ?? mod;\n if (typeof config === \"function\") {\n const result = await config(phase, {\n defaultConfig: {},\n });\n return result as NextConfig;\n }\n return config as NextConfig;\n}\n\n/**\n * Find and load the next.config file from the project root.\n * Returns null if no config file is found.\n *\n * Attempts Vite's module runner first so TS configs and extensionless local\n * imports (e.g. `import \"./env\"`) resolve consistently. If loading fails due\n * to CJS constructs (`require`, `module.exports`), falls back to `createRequire`\n * so common CJS plugin wrappers (nextra, @next/mdx, etc.) still work.\n */\nexport async function loadNextConfig(\n root: string,\n phase: string = PHASE_DEVELOPMENT_SERVER,\n): Promise<NextConfig | null> {\n for (const filename of CONFIG_FILES) {\n const configPath = path.join(root, filename);\n if (!fs.existsSync(configPath)) continue;\n\n try {\n // Load config via Vite's module runner (TS + extensionless import support)\n const { runnerImport } = await import(\"vite\");\n const { module: mod } = await runnerImport(configPath, {\n root,\n logLevel: \"error\",\n clearScreen: false,\n });\n return await unwrapConfig(mod, phase);\n } catch (e) {\n // If the error indicates a CJS file loaded in ESM context, retry with\n // createRequire which provides a proper CommonJS environment.\n if (isCjsError(e) && (filename.endsWith(\".js\") || filename.endsWith(\".cjs\"))) {\n try {\n const require = createRequire(path.join(root, \"package.json\"));\n const mod = require(configPath);\n return await unwrapConfig({ default: mod }, phase);\n } catch (e2) {\n warnConfigLoadFailure(filename, e2 as Error);\n throw e2;\n }\n }\n\n warnConfigLoadFailure(filename, e as Error);\n throw e;\n }\n }\n\n return null;\n}\n\n/**\n * Generate a UUID that doesn't contain \"ad\" to avoid false-positive ad-blocker hits.\n * Mirrors Next.js's own nanoid retry loop.\n */\nfunction safeUUID(): string {\n let id = randomUUID();\n while (/ad/i.test(id)) id = randomUUID();\n return id;\n}\n\n/**\n * Call the user's generateBuildId function and validate its return value.\n * Follows Next.js semantics: null return falls back to a random UUID; any\n * other non-string throws. Leading/trailing whitespace is trimmed.\n *\n * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/generateBuildId\n */\nasync function resolveBuildId(\n generate: (() => string | null | Promise<string | null>) | undefined,\n): Promise<string> {\n if (!generate) return safeUUID();\n\n const result = await generate();\n\n if (result === null) return safeUUID();\n\n if (typeof result !== \"string\") {\n throw new Error(\n \"generateBuildId did not return a string. https://nextjs.org/docs/messages/generatebuildid-not-a-string\",\n );\n }\n\n const trimmed = result.trim();\n if (trimmed.length === 0) {\n throw new Error(\n \"generateBuildId returned an empty string. https://nextjs.org/docs/messages/generatebuildid-not-a-string\",\n );\n }\n\n return trimmed;\n}\n\n/**\n * Resolve a NextConfig into a fully-resolved ResolvedNextConfig.\n * Awaits async functions for redirects/rewrites/headers.\n */\nexport async function resolveNextConfig(\n config: NextConfig | null,\n root: string = process.cwd(),\n): Promise<ResolvedNextConfig> {\n if (!config) {\n const buildId = await resolveBuildId(undefined);\n const resolved: ResolvedNextConfig = {\n env: {},\n basePath: \"\",\n trailingSlash: false,\n output: \"\",\n pageExtensions: normalizePageExtensions(),\n cacheComponents: false,\n redirects: [],\n rewrites: { beforeFiles: [], afterFiles: [], fallback: [] },\n headers: [],\n images: undefined,\n i18n: null,\n mdx: null,\n aliases: {},\n allowedDevOrigins: [],\n serverActionsAllowedOrigins: [],\n serverActionsBodySizeLimit: 1 * 1024 * 1024,\n serverExternalPackages: [],\n buildId,\n };\n detectNextIntlConfig(root, resolved);\n return resolved;\n }\n\n // Resolve redirects\n let redirects: NextRedirect[] = [];\n if (config.redirects) {\n const result = await config.redirects();\n redirects = Array.isArray(result) ? result : [];\n }\n\n // Resolve rewrites\n let rewrites = {\n beforeFiles: [] as NextRewrite[],\n afterFiles: [] as NextRewrite[],\n fallback: [] as NextRewrite[],\n };\n if (config.rewrites) {\n const result = await config.rewrites();\n if (Array.isArray(result)) {\n rewrites.afterFiles = result;\n } else {\n rewrites = {\n beforeFiles: result.beforeFiles ?? [],\n afterFiles: result.afterFiles ?? [],\n fallback: result.fallback ?? [],\n };\n }\n }\n\n {\n const allRewrites = [...rewrites.beforeFiles, ...rewrites.afterFiles, ...rewrites.fallback];\n const externalRewrites = allRewrites.filter((rewrite) => isExternalUrl(rewrite.destination));\n\n if (externalRewrites.length > 0) {\n const noun = externalRewrites.length === 1 ? \"external rewrite\" : \"external rewrites\";\n const listing = externalRewrites\n .map((rewrite) => ` ${rewrite.source} → ${rewrite.destination}`)\n .join(\"\\n\");\n\n console.warn(\n `[vinext] Found ${externalRewrites.length} ${noun} that proxy requests to external origins:\\n` +\n `${listing}\\n` +\n `Request headers, including credential headers (cookie, authorization, proxy-authorization, x-api-key), ` +\n `are forwarded to the external origin to match Next.js behavior. ` +\n `If you do not want to forward credentials, use an API route or route handler where you control exactly which headers are sent.`,\n );\n }\n }\n\n // Resolve headers\n let headers: NextHeader[] = [];\n if (config.headers) {\n headers = await config.headers();\n }\n\n // Probe wrapped webpack config once so alias extraction and MDX extraction\n // observe the same mock environment.\n const webpackProbe = await probeWebpackConfig(config, root);\n const mdx = webpackProbe.mdx;\n const aliases = {\n ...extractTurboAliases(config, root),\n ...webpackProbe.aliases,\n };\n\n const allowedDevOrigins = Array.isArray(config.allowedDevOrigins) ? config.allowedDevOrigins : [];\n\n // Resolve serverActions.allowedOrigins and bodySizeLimit from experimental config\n const experimental = config.experimental as Record<string, unknown> | undefined;\n const serverActionsConfig = experimental?.serverActions as Record<string, unknown> | undefined;\n const serverActionsAllowedOrigins = Array.isArray(serverActionsConfig?.allowedOrigins)\n ? (serverActionsConfig.allowedOrigins as string[])\n : [];\n const serverActionsBodySizeLimit = parseBodySizeLimit(\n serverActionsConfig?.bodySizeLimit as string | number | undefined,\n );\n\n // Resolve serverExternalPackages — support the current top-level key and the\n // legacy experimental.serverComponentsExternalPackages name that Next.js still\n // accepts (it moved out of experimental in Next.js 14.2).\n const legacyServerComponentsExternal = experimental?.serverComponentsExternalPackages;\n const serverExternalPackages: string[] = Array.isArray(config.serverExternalPackages)\n ? (config.serverExternalPackages as string[])\n : Array.isArray(legacyServerComponentsExternal)\n ? (legacyServerComponentsExternal as string[])\n : [];\n\n // Warn about unsupported webpack usage. We preserve alias injection and\n // extract MDX settings, but all other webpack customization is still ignored.\n if (config.webpack !== undefined) {\n if (mdx || Object.keys(webpackProbe.aliases).length > 0) {\n console.warn(\n '[vinext] next.config option \"webpack\" is only partially supported. ' +\n \"vinext preserves resolve.alias entries and MDX loader settings, but other webpack customization is ignored\",\n );\n } else {\n console.warn(\n '[vinext] next.config option \"webpack\" is not yet supported and will be ignored',\n );\n }\n }\n\n const output = config.output ?? \"\";\n if (output && output !== \"export\" && output !== \"standalone\") {\n console.warn(`[vinext] Unknown output mode \"${output as string}\", ignoring`);\n }\n\n const pageExtensions = normalizePageExtensions(config.pageExtensions);\n\n // Parse i18n config\n let i18n: NextI18nConfig | null = null;\n if (config.i18n) {\n i18n = {\n locales: config.i18n.locales,\n defaultLocale: config.i18n.defaultLocale,\n localeDetection: config.i18n.localeDetection ?? true,\n domains: config.i18n.domains,\n };\n }\n\n const buildId = await resolveBuildId(\n config.generateBuildId as (() => string | null | Promise<string | null>) | undefined,\n );\n\n const resolved: ResolvedNextConfig = {\n env: config.env ?? {},\n basePath: config.basePath ?? \"\",\n trailingSlash: config.trailingSlash ?? false,\n output: output === \"export\" || output === \"standalone\" ? output : \"\",\n pageExtensions,\n cacheComponents: config.cacheComponents ?? false,\n redirects,\n rewrites,\n headers,\n images: config.images,\n i18n,\n mdx,\n aliases,\n allowedDevOrigins,\n serverActionsAllowedOrigins,\n serverActionsBodySizeLimit,\n serverExternalPackages,\n buildId,\n };\n\n // Auto-detect next-intl (lowest priority — explicit aliases from\n // webpack/turbopack already in `aliases` take precedence)\n detectNextIntlConfig(root, resolved);\n\n return resolved;\n}\n\nfunction normalizeAliasEntries(\n aliases: Record<string, unknown> | undefined,\n root: string,\n): Record<string, string> {\n if (!aliases) return {};\n\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(aliases)) {\n if (typeof value !== \"string\") continue;\n normalized[key] = path.isAbsolute(value) ? value : path.resolve(root, value);\n }\n return normalized;\n}\n\nfunction extractTurboAliases(config: NextConfig, root: string): Record<string, string> {\n const experimental = config.experimental as Record<string, unknown> | undefined;\n const experimentalTurbo = experimental?.turbo as Record<string, unknown> | undefined;\n const topLevelTurbopack = config.turbopack as Record<string, unknown> | undefined;\n\n return {\n ...normalizeAliasEntries(\n experimentalTurbo?.resolveAlias as Record<string, unknown> | undefined,\n root,\n ),\n ...normalizeAliasEntries(\n topLevelTurbopack?.resolveAlias as Record<string, unknown> | undefined,\n root,\n ),\n };\n}\n\nasync function probeWebpackConfig(\n config: NextConfig,\n root: string,\n): Promise<{ aliases: Record<string, string>; mdx: MdxOptions | null }> {\n if (typeof config.webpack !== \"function\") {\n return { aliases: {}, mdx: null };\n }\n\n const mockModuleRules: any[] = [];\n const mockConfig = {\n context: root,\n resolve: { alias: {} as Record<string, unknown> },\n module: { rules: mockModuleRules },\n plugins: [] as any[],\n };\n const mockOptions = {\n defaultLoaders: { babel: { loader: \"next-babel-loader\" } },\n isServer: false,\n dev: false,\n dir: root,\n };\n\n try {\n const result = await (config.webpack as Function)(mockConfig, mockOptions);\n const finalConfig = result ?? mockConfig;\n const rules: any[] = finalConfig.module?.rules ?? mockModuleRules;\n return {\n aliases: normalizeAliasEntries(finalConfig.resolve?.alias, root),\n mdx: extractMdxOptionsFromRules(rules),\n };\n } catch {\n return { aliases: {}, mdx: null };\n }\n}\n\n/**\n * Extract MDX compilation options (remark/rehype/recma plugins) from\n * a Next.js config that uses @next/mdx.\n *\n * @next/mdx wraps the config with a webpack function that injects an MDX\n * loader rule. The remark/rehype plugins are captured in that closure.\n * We probe the webpack function with a mock config to extract them.\n */\nexport async function extractMdxOptions(\n config: NextConfig,\n root: string = process.cwd(),\n): Promise<MdxOptions | null> {\n return (await probeWebpackConfig(config, root)).mdx;\n}\n\n/**\n * Probe file candidates relative to root. Returns the first one that exists,\n * or null if none match.\n */\nfunction probeFiles(root: string, candidates: string[]): string | null {\n for (const candidate of candidates) {\n const abs = path.resolve(root, candidate);\n if (fs.existsSync(abs)) return abs;\n }\n return null;\n}\n\nconst I18N_REQUEST_CANDIDATES = [\n \"i18n/request.ts\",\n \"i18n/request.tsx\",\n \"i18n/request.js\",\n \"i18n/request.jsx\",\n \"src/i18n/request.ts\",\n \"src/i18n/request.tsx\",\n \"src/i18n/request.js\",\n \"src/i18n/request.jsx\",\n];\n\n/**\n * Detect next-intl in the project and auto-register the `next-intl/config`\n * alias if needed.\n *\n * next-intl's `createNextIntlPlugin()` crashes in vinext because it calls\n * `require('next/package.json')` to check the Next.js version. Instead,\n * vinext detects next-intl and registers the alias automatically.\n *\n * Note: `require.resolve('next-intl')` walks up to parent `node_modules`\n * directories via standard Node module resolution. In a monorepo, next-intl\n * installed at the workspace root will trigger detection even if not listed\n * in the project's own package.json. This is acceptable since a workspace-root\n * install implies the user wants it available.\n *\n * Mutates `resolved.aliases` and `resolved.env` in place.\n */\nexport function detectNextIntlConfig(root: string, resolved: ResolvedNextConfig): void {\n // Explicit alias wins — user or plugin already set it\n if (resolved.aliases[\"next-intl/config\"]) return;\n\n // Check if next-intl is installed (use main entry — some packages\n // don't expose ./package.json in their exports map)\n const require = createRequire(path.join(root, \"package.json\"));\n try {\n require.resolve(\"next-intl\");\n } catch {\n return; // next-intl not installed\n }\n\n // Probe for the i18n request config file\n const configPath = probeFiles(root, I18N_REQUEST_CANDIDATES);\n if (!configPath) return;\n\n resolved.aliases[\"next-intl/config\"] = configPath;\n\n if (resolved.trailingSlash) {\n resolved.env._next_intl_trailing_slash = \"true\";\n }\n}\n\nfunction extractMdxOptionsFromRules(rules: any[]): MdxOptions | null {\n // Search through webpack rules for the MDX loader injected by @next/mdx\n for (const rule of rules) {\n const loaders = extractMdxLoaders(rule);\n if (loaders) return loaders;\n }\n return null;\n}\n\n/**\n * Recursively search a webpack rule (which may have nested `oneOf` arrays)\n * for an MDX loader and extract its remark/rehype/recma plugin options.\n */\nfunction extractMdxLoaders(rule: any): MdxOptions | null {\n if (!rule) return null;\n\n // Check `oneOf` arrays (Next.js uses these extensively)\n if (Array.isArray(rule.oneOf)) {\n for (const child of rule.oneOf) {\n const result = extractMdxLoaders(child);\n if (result) return result;\n }\n }\n\n // Check `use` array (loader chain)\n const use = Array.isArray(rule.use) ? rule.use : rule.use ? [rule.use] : [];\n for (const loader of use) {\n const loaderPath = typeof loader === \"string\" ? loader : loader?.loader;\n if (typeof loaderPath === \"string\" && isMdxLoader(loaderPath)) {\n const opts = typeof loader === \"object\" ? loader.options : {};\n return extractPluginsFromOptions(opts);\n }\n }\n\n // Check direct `loader` field\n if (typeof rule.loader === \"string\" && isMdxLoader(rule.loader)) {\n return extractPluginsFromOptions(rule.options);\n }\n\n return null;\n}\n\nfunction isMdxLoader(loaderPath: string): boolean {\n return (\n loaderPath.includes(\"mdx\") &&\n (loaderPath.includes(\"@next\") ||\n loaderPath.includes(\"@mdx-js\") ||\n loaderPath.includes(\"mdx-js-loader\") ||\n loaderPath.includes(\"next-mdx\"))\n );\n}\n\nfunction extractPluginsFromOptions(opts: any): MdxOptions | null {\n if (!opts || typeof opts !== \"object\") return null;\n\n const remarkPlugins = Array.isArray(opts.remarkPlugins) ? opts.remarkPlugins : undefined;\n const rehypePlugins = Array.isArray(opts.rehypePlugins) ? opts.rehypePlugins : undefined;\n const recmaPlugins = Array.isArray(opts.recmaPlugins) ? opts.recmaPlugins : undefined;\n\n // Only return if at least one plugin array is non-empty\n if (\n (remarkPlugins && remarkPlugins.length > 0) ||\n (rehypePlugins && rehypePlugins.length > 0) ||\n (recmaPlugins && recmaPlugins.length > 0)\n ) {\n return {\n ...(remarkPlugins && remarkPlugins.length > 0 ? { remarkPlugins } : {}),\n ...(rehypePlugins && rehypePlugins.length > 0 ? { rehypePlugins } : {}),\n ...(recmaPlugins && recmaPlugins.length > 0 ? { recmaPlugins } : {}),\n };\n }\n\n return null;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"next-config.js","names":[],"sources":["../../src/config/next-config.ts"],"sourcesContent":["/**\n * next.config.js / next.config.mjs / next.config.ts parser\n *\n * Loads the Next.js config file (if present) and extracts supported options.\n * Unsupported options are logged as warnings.\n */\nimport path from \"node:path\";\nimport { createRequire } from \"node:module\";\nimport fs from \"node:fs\";\nimport { randomUUID } from \"node:crypto\";\nimport { PHASE_DEVELOPMENT_SERVER } from \"../shims/constants.js\";\nimport { normalizePageExtensions } from \"../routing/file-matcher.js\";\nimport { isExternalUrl } from \"./config-matchers.js\";\n\n/**\n * Parse a body size limit value (string or number) into bytes.\n * Accepts Next.js-style strings like \"1mb\", \"500kb\", \"10mb\", bare number strings like \"1048576\" (bytes),\n * and numeric values. Supports b, kb, mb, gb, tb, pb units.\n * Returns the default 1MB if the value is not provided or invalid.\n * Throws if the parsed value is less than 1.\n */\nexport function parseBodySizeLimit(value: string | number | undefined | null): number {\n if (value === undefined || value === null) return 1 * 1024 * 1024;\n if (typeof value === \"number\") {\n if (value < 1) throw new Error(`Body size limit must be a positive number, got ${value}`);\n return value;\n }\n const trimmed = value.trim();\n const match = trimmed.match(/^(\\d+(?:\\.\\d+)?)\\s*(b|kb|mb|gb|tb|pb)?$/i);\n if (!match) {\n console.warn(\n `[vinext] Invalid bodySizeLimit value: \"${value}\". Expected a number or a string like \"1mb\", \"500kb\". Falling back to 1MB.`,\n );\n return 1 * 1024 * 1024;\n }\n const num = parseFloat(match[1]);\n const unit = (match[2] ?? \"b\").toLowerCase();\n let bytes: number;\n switch (unit) {\n case \"b\":\n bytes = Math.floor(num);\n break;\n case \"kb\":\n bytes = Math.floor(num * 1024);\n break;\n case \"mb\":\n bytes = Math.floor(num * 1024 * 1024);\n break;\n case \"gb\":\n bytes = Math.floor(num * 1024 * 1024 * 1024);\n break;\n case \"tb\":\n bytes = Math.floor(num * 1024 * 1024 * 1024 * 1024);\n break;\n case \"pb\":\n bytes = Math.floor(num * 1024 * 1024 * 1024 * 1024 * 1024);\n break;\n default:\n return 1 * 1024 * 1024;\n }\n if (bytes < 1) throw new Error(`Body size limit must be a positive number, got ${bytes}`);\n return bytes;\n}\n\nexport interface HasCondition {\n type: \"header\" | \"cookie\" | \"query\" | \"host\";\n key: string;\n value?: string;\n}\n\nexport interface NextRedirect {\n source: string;\n destination: string;\n permanent: boolean;\n has?: HasCondition[];\n missing?: HasCondition[];\n}\n\nexport interface NextRewrite {\n source: string;\n destination: string;\n has?: HasCondition[];\n missing?: HasCondition[];\n}\n\nexport interface NextHeader {\n source: string;\n has?: HasCondition[];\n missing?: HasCondition[];\n headers: Array<{ key: string; value: string }>;\n}\n\nexport interface NextI18nConfig {\n /** List of supported locales */\n locales: string[];\n /** The default locale (used when no locale prefix is in the URL) */\n defaultLocale: string;\n /**\n * Whether to auto-detect locale from Accept-Language header.\n * Defaults to true in Next.js.\n */\n localeDetection?: boolean;\n /**\n * Domain-based routing. Each domain maps to a specific locale.\n */\n domains?: Array<{\n domain: string;\n defaultLocale: string;\n locales?: string[];\n http?: boolean;\n }>;\n}\n\n/**\n * MDX compilation options extracted from @next/mdx config.\n * These are passed through to @mdx-js/rollup so that custom\n * remark/rehype/recma plugins configured in next.config work with Vite.\n */\nexport interface MdxOptions {\n remarkPlugins?: unknown[];\n rehypePlugins?: unknown[];\n recmaPlugins?: unknown[];\n}\n\nexport interface NextConfig {\n /** Additional env variables */\n env?: Record<string, string>;\n /** Base URL path prefix */\n basePath?: string;\n /** Whether to add trailing slashes */\n trailingSlash?: boolean;\n /** Internationalization routing config */\n i18n?: NextI18nConfig;\n /** URL redirect rules */\n redirects?: () => Promise<NextRedirect[]> | NextRedirect[];\n /** URL rewrite rules */\n rewrites?: () =>\n | Promise<\n | NextRewrite[]\n | {\n beforeFiles: NextRewrite[];\n afterFiles: NextRewrite[];\n fallback: NextRewrite[];\n }\n >\n | NextRewrite[]\n | {\n beforeFiles: NextRewrite[];\n afterFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n /** Custom response headers */\n headers?: () => Promise<NextHeader[]> | NextHeader[];\n /** Image optimization config */\n images?: {\n remotePatterns?: Array<{\n protocol?: string;\n hostname: string;\n port?: string;\n pathname?: string;\n search?: string;\n }>;\n domains?: string[];\n unoptimized?: boolean;\n /** Allowed device widths for image optimization. Defaults to Next.js defaults: [640, 750, 828, 1080, 1200, 1920, 2048, 3840] */\n deviceSizes?: number[];\n /** Allowed image sizes for fixed-width images. Defaults to Next.js defaults: [16, 32, 48, 64, 96, 128, 256, 384] */\n imageSizes?: number[];\n /** Allow SVG images through the image optimization endpoint. SVG can contain scripts, so only enable if you trust all image sources. */\n dangerouslyAllowSVG?: boolean;\n /** Content-Disposition header for image responses. Defaults to \"inline\". */\n contentDispositionType?: \"inline\" | \"attachment\";\n /** Content-Security-Policy header for image responses. Defaults to \"script-src 'none'; frame-src 'none'; sandbox;\" */\n contentSecurityPolicy?: string;\n };\n /** Build output mode: 'export' for full static export, 'standalone' for single server */\n output?: \"export\" | \"standalone\";\n /** File extensions treated as routable pages/routes (Next.js pageExtensions) */\n pageExtensions?: string[];\n /** Extra origins allowed to access the dev server. */\n allowedDevOrigins?: string[];\n /**\n * Enable Cache Components (Next.js 16).\n * When true, enables the \"use cache\" directive for pages, components, and functions.\n * Replaces the removed experimental.ppr and experimental.dynamicIO flags.\n */\n cacheComponents?: boolean;\n /** Transpile packages (Vite handles this natively) */\n transpilePackages?: string[];\n /**\n * Packages that should be treated as server-external (not bundled by Vite).\n * Corresponds to Next.js `serverExternalPackages` (or the legacy\n * `experimental.serverComponentsExternalPackages`).\n */\n serverExternalPackages?: string[];\n /** Webpack config (ignored — we use Vite) */\n webpack?: unknown;\n /**\n * Custom build ID generator. If provided, called once at build/dev start.\n * Must return a non-empty string, or null to use the default random ID.\n */\n generateBuildId?: () => string | null | Promise<string | null>;\n /** Any other options */\n [key: string]: unknown;\n}\n\n/**\n * Resolved configuration with all async values awaited.\n */\nexport interface ResolvedNextConfig {\n env: Record<string, string>;\n basePath: string;\n trailingSlash: boolean;\n output: \"\" | \"export\" | \"standalone\";\n pageExtensions: string[];\n cacheComponents: boolean;\n redirects: NextRedirect[];\n rewrites: {\n beforeFiles: NextRewrite[];\n afterFiles: NextRewrite[];\n fallback: NextRewrite[];\n };\n headers: NextHeader[];\n images: NextConfig[\"images\"];\n i18n: NextI18nConfig | null;\n /** MDX remark/rehype/recma plugins extracted from @next/mdx config */\n mdx: MdxOptions | null;\n /** Explicit module aliases preserved from wrapped next.config plugins. */\n aliases: Record<string, string>;\n /** Extra allowed origins for dev server access (from allowedDevOrigins). */\n allowedDevOrigins: string[];\n /** Extra allowed origins for server action CSRF validation (from experimental.serverActions.allowedOrigins). */\n serverActionsAllowedOrigins: string[];\n /** Packages whose barrel imports should be optimized (from experimental.optimizePackageImports). */\n optimizePackageImports: string[];\n /** Parsed body size limit for server actions in bytes (from experimental.serverActions.bodySizeLimit). Defaults to 1MB. */\n serverActionsBodySizeLimit: number;\n /**\n * Packages that should be treated as server-external (not bundled by Vite).\n * Sourced from `serverExternalPackages` or the legacy\n * `experimental.serverComponentsExternalPackages` in next.config.\n */\n serverExternalPackages: string[];\n /** Resolved build ID (from generateBuildId, or a random UUID if not provided). */\n buildId: string;\n}\n\nconst CONFIG_FILES = [\"next.config.ts\", \"next.config.mjs\", \"next.config.js\", \"next.config.cjs\"];\n\n/**\n * Check whether an error indicates a CJS module was loaded in an ESM context\n * (i.e. the file uses `require()` which is not available in ESM).\n */\nfunction isCjsError(e: unknown): boolean {\n if (!(e instanceof Error)) return false;\n const msg = e.message;\n return (\n msg.includes(\"require is not a function\") ||\n msg.includes(\"require is not defined\") ||\n msg.includes(\"exports is not defined\") ||\n msg.includes(\"module is not defined\") ||\n msg.includes(\"__dirname is not defined\") ||\n msg.includes(\"__filename is not defined\")\n );\n}\n\n/**\n * Emit a warning when config loading fails, with a targeted hint for\n * known plugin wrappers that are unnecessary in vinext.\n */\nfunction warnConfigLoadFailure(filename: string, err: Error): void {\n const msg = err.message ?? \"\";\n const stack = err.stack ?? \"\";\n const isNextIntlPlugin =\n msg.includes(\"next-intl\") ||\n stack.includes(\"next-intl/plugin\") ||\n stack.includes(\"next-intl/dist\");\n\n console.log();\n console.error(`[vinext] Failed to load ${filename}: ${msg}`);\n console.log();\n if (isNextIntlPlugin) {\n console.warn(\n \"[vinext] Hint: createNextIntlPlugin() is not needed with vinext. \" +\n \"Remove the next-intl/plugin wrapper from your next.config — \" +\n \"vinext auto-detects next-intl and registers the i18n config alias automatically.\",\n );\n }\n}\n\n/**\n * Unwrap the config value from a loaded module, calling it if it's a\n * function-form config (Next.js supports `module.exports = (phase, opts) => config`).\n */\nasync function unwrapConfig(\n mod: any,\n phase: string = PHASE_DEVELOPMENT_SERVER,\n): Promise<NextConfig> {\n const config = mod.default ?? mod;\n if (typeof config === \"function\") {\n const result = await config(phase, {\n defaultConfig: {},\n });\n return result as NextConfig;\n }\n return config as NextConfig;\n}\n\n/**\n * Find and load the next.config file from the project root.\n * Returns null if no config file is found.\n *\n * Attempts Vite's module runner first so TS configs and extensionless local\n * imports (e.g. `import \"./env\"`) resolve consistently. If loading fails due\n * to CJS constructs (`require`, `module.exports`), falls back to `createRequire`\n * so common CJS plugin wrappers (nextra, @next/mdx, etc.) still work.\n */\nexport async function loadNextConfig(\n root: string,\n phase: string = PHASE_DEVELOPMENT_SERVER,\n): Promise<NextConfig | null> {\n for (const filename of CONFIG_FILES) {\n const configPath = path.join(root, filename);\n if (!fs.existsSync(configPath)) continue;\n\n try {\n // Load config via Vite's module runner (TS + extensionless import support)\n const { runnerImport } = await import(\"vite\");\n const { module: mod } = await runnerImport(configPath, {\n root,\n logLevel: \"error\",\n clearScreen: false,\n });\n return await unwrapConfig(mod, phase);\n } catch (e) {\n // If the error indicates a CJS file loaded in ESM context, retry with\n // createRequire which provides a proper CommonJS environment.\n if (isCjsError(e) && (filename.endsWith(\".js\") || filename.endsWith(\".cjs\"))) {\n try {\n const require = createRequire(path.join(root, \"package.json\"));\n const mod = require(configPath);\n return await unwrapConfig({ default: mod }, phase);\n } catch (e2) {\n warnConfigLoadFailure(filename, e2 as Error);\n throw e2;\n }\n }\n\n warnConfigLoadFailure(filename, e as Error);\n throw e;\n }\n }\n\n return null;\n}\n\n/**\n * Generate a UUID that doesn't contain \"ad\" to avoid false-positive ad-blocker hits.\n * Mirrors Next.js's own nanoid retry loop.\n */\nfunction safeUUID(): string {\n let id = randomUUID();\n while (/ad/i.test(id)) id = randomUUID();\n return id;\n}\n\n/**\n * Call the user's generateBuildId function and validate its return value.\n * Follows Next.js semantics: null return falls back to a random UUID; any\n * other non-string throws. Leading/trailing whitespace is trimmed.\n *\n * @see https://nextjs.org/docs/app/api-reference/config/next-config-js/generateBuildId\n */\nasync function resolveBuildId(\n generate: (() => string | null | Promise<string | null>) | undefined,\n): Promise<string> {\n if (!generate) return safeUUID();\n\n const result = await generate();\n\n if (result === null) return safeUUID();\n\n if (typeof result !== \"string\") {\n throw new Error(\n \"generateBuildId did not return a string. https://nextjs.org/docs/messages/generatebuildid-not-a-string\",\n );\n }\n\n const trimmed = result.trim();\n if (trimmed.length === 0) {\n throw new Error(\n \"generateBuildId returned an empty string. https://nextjs.org/docs/messages/generatebuildid-not-a-string\",\n );\n }\n\n return trimmed;\n}\n\n/**\n * Resolve a NextConfig into a fully-resolved ResolvedNextConfig.\n * Awaits async functions for redirects/rewrites/headers.\n */\nexport async function resolveNextConfig(\n config: NextConfig | null,\n root: string = process.cwd(),\n): Promise<ResolvedNextConfig> {\n if (!config) {\n const buildId = await resolveBuildId(undefined);\n const resolved: ResolvedNextConfig = {\n env: {},\n basePath: \"\",\n trailingSlash: false,\n output: \"\",\n pageExtensions: normalizePageExtensions(),\n cacheComponents: false,\n redirects: [],\n rewrites: { beforeFiles: [], afterFiles: [], fallback: [] },\n headers: [],\n images: undefined,\n i18n: null,\n mdx: null,\n aliases: {},\n allowedDevOrigins: [],\n serverActionsAllowedOrigins: [],\n optimizePackageImports: [],\n serverActionsBodySizeLimit: 1 * 1024 * 1024,\n serverExternalPackages: [],\n buildId,\n };\n detectNextIntlConfig(root, resolved);\n return resolved;\n }\n\n // Resolve redirects\n let redirects: NextRedirect[] = [];\n if (config.redirects) {\n const result = await config.redirects();\n redirects = Array.isArray(result) ? result : [];\n }\n\n // Resolve rewrites\n let rewrites = {\n beforeFiles: [] as NextRewrite[],\n afterFiles: [] as NextRewrite[],\n fallback: [] as NextRewrite[],\n };\n if (config.rewrites) {\n const result = await config.rewrites();\n if (Array.isArray(result)) {\n rewrites.afterFiles = result;\n } else {\n rewrites = {\n beforeFiles: result.beforeFiles ?? [],\n afterFiles: result.afterFiles ?? [],\n fallback: result.fallback ?? [],\n };\n }\n }\n\n {\n const allRewrites = [...rewrites.beforeFiles, ...rewrites.afterFiles, ...rewrites.fallback];\n const externalRewrites = allRewrites.filter((rewrite) => isExternalUrl(rewrite.destination));\n\n if (externalRewrites.length > 0) {\n const noun = externalRewrites.length === 1 ? \"external rewrite\" : \"external rewrites\";\n const listing = externalRewrites\n .map((rewrite) => ` ${rewrite.source} → ${rewrite.destination}`)\n .join(\"\\n\");\n\n console.warn(\n `[vinext] Found ${externalRewrites.length} ${noun} that proxy requests to external origins:\\n` +\n `${listing}\\n` +\n `Request headers, including credential headers (cookie, authorization, proxy-authorization, x-api-key), ` +\n `are forwarded to the external origin to match Next.js behavior. ` +\n `If you do not want to forward credentials, use an API route or route handler where you control exactly which headers are sent.`,\n );\n }\n }\n\n // Resolve headers\n let headers: NextHeader[] = [];\n if (config.headers) {\n headers = await config.headers();\n }\n\n // Probe wrapped webpack config once so alias extraction and MDX extraction\n // observe the same mock environment.\n const webpackProbe = await probeWebpackConfig(config, root);\n const mdx = webpackProbe.mdx;\n const aliases = {\n ...extractTurboAliases(config, root),\n ...webpackProbe.aliases,\n };\n\n const allowedDevOrigins = Array.isArray(config.allowedDevOrigins) ? config.allowedDevOrigins : [];\n\n // Resolve serverActions.allowedOrigins and bodySizeLimit from experimental config\n const experimental = config.experimental as Record<string, unknown> | undefined;\n const serverActionsConfig = experimental?.serverActions as Record<string, unknown> | undefined;\n const serverActionsAllowedOrigins = Array.isArray(serverActionsConfig?.allowedOrigins)\n ? (serverActionsConfig.allowedOrigins as string[])\n : [];\n const serverActionsBodySizeLimit = parseBodySizeLimit(\n serverActionsConfig?.bodySizeLimit as string | number | undefined,\n );\n\n // Resolve optimizePackageImports from experimental config\n const rawOptimize = experimental?.optimizePackageImports;\n const optimizePackageImports = Array.isArray(rawOptimize)\n ? rawOptimize.filter((x): x is string => typeof x === \"string\")\n : [];\n\n // Resolve serverExternalPackages — support the current top-level key and the\n // legacy experimental.serverComponentsExternalPackages name that Next.js still\n // accepts (it moved out of experimental in Next.js 14.2).\n const legacyServerComponentsExternal = experimental?.serverComponentsExternalPackages;\n const serverExternalPackages: string[] = Array.isArray(config.serverExternalPackages)\n ? (config.serverExternalPackages as string[])\n : Array.isArray(legacyServerComponentsExternal)\n ? (legacyServerComponentsExternal as string[])\n : [];\n\n // Warn about unsupported webpack usage. We preserve alias injection and\n // extract MDX settings, but all other webpack customization is still ignored.\n if (config.webpack !== undefined) {\n if (mdx || Object.keys(webpackProbe.aliases).length > 0) {\n console.warn(\n '[vinext] next.config option \"webpack\" is only partially supported. ' +\n \"vinext preserves resolve.alias entries and MDX loader settings, but other webpack customization is ignored\",\n );\n } else {\n console.warn(\n '[vinext] next.config option \"webpack\" is not yet supported and will be ignored',\n );\n }\n }\n\n const output = config.output ?? \"\";\n if (output && output !== \"export\" && output !== \"standalone\") {\n console.warn(`[vinext] Unknown output mode \"${output as string}\", ignoring`);\n }\n\n const pageExtensions = normalizePageExtensions(config.pageExtensions);\n\n // Parse i18n config\n let i18n: NextI18nConfig | null = null;\n if (config.i18n) {\n i18n = {\n locales: config.i18n.locales,\n defaultLocale: config.i18n.defaultLocale,\n localeDetection: config.i18n.localeDetection ?? true,\n domains: config.i18n.domains,\n };\n }\n\n const buildId = await resolveBuildId(\n config.generateBuildId as (() => string | null | Promise<string | null>) | undefined,\n );\n\n const resolved: ResolvedNextConfig = {\n env: config.env ?? {},\n basePath: config.basePath ?? \"\",\n trailingSlash: config.trailingSlash ?? false,\n output: output === \"export\" || output === \"standalone\" ? output : \"\",\n pageExtensions,\n cacheComponents: config.cacheComponents ?? false,\n redirects,\n rewrites,\n headers,\n images: config.images,\n i18n,\n mdx,\n aliases,\n allowedDevOrigins,\n serverActionsAllowedOrigins,\n optimizePackageImports,\n serverActionsBodySizeLimit,\n serverExternalPackages,\n buildId,\n };\n\n // Auto-detect next-intl (lowest priority — explicit aliases from\n // webpack/turbopack already in `aliases` take precedence)\n detectNextIntlConfig(root, resolved);\n\n return resolved;\n}\n\nfunction normalizeAliasEntries(\n aliases: Record<string, unknown> | undefined,\n root: string,\n): Record<string, string> {\n if (!aliases) return {};\n\n const normalized: Record<string, string> = {};\n for (const [key, value] of Object.entries(aliases)) {\n if (typeof value !== \"string\") continue;\n normalized[key] = path.isAbsolute(value) ? value : path.resolve(root, value);\n }\n return normalized;\n}\n\nfunction extractTurboAliases(config: NextConfig, root: string): Record<string, string> {\n const experimental = config.experimental as Record<string, unknown> | undefined;\n const experimentalTurbo = experimental?.turbo as Record<string, unknown> | undefined;\n const topLevelTurbopack = config.turbopack as Record<string, unknown> | undefined;\n\n return {\n ...normalizeAliasEntries(\n experimentalTurbo?.resolveAlias as Record<string, unknown> | undefined,\n root,\n ),\n ...normalizeAliasEntries(\n topLevelTurbopack?.resolveAlias as Record<string, unknown> | undefined,\n root,\n ),\n };\n}\n\nasync function probeWebpackConfig(\n config: NextConfig,\n root: string,\n): Promise<{ aliases: Record<string, string>; mdx: MdxOptions | null }> {\n if (typeof config.webpack !== \"function\") {\n return { aliases: {}, mdx: null };\n }\n\n const mockModuleRules: any[] = [];\n const mockConfig = {\n context: root,\n resolve: { alias: {} as Record<string, unknown> },\n module: { rules: mockModuleRules },\n plugins: [] as any[],\n };\n const mockOptions = {\n defaultLoaders: { babel: { loader: \"next-babel-loader\" } },\n isServer: false,\n dev: false,\n dir: root,\n };\n\n try {\n const result = await (config.webpack as Function)(mockConfig, mockOptions);\n const finalConfig = result ?? mockConfig;\n const rules: any[] = finalConfig.module?.rules ?? mockModuleRules;\n return {\n aliases: normalizeAliasEntries(finalConfig.resolve?.alias, root),\n mdx: extractMdxOptionsFromRules(rules),\n };\n } catch {\n return { aliases: {}, mdx: null };\n }\n}\n\n/**\n * Extract MDX compilation options (remark/rehype/recma plugins) from\n * a Next.js config that uses @next/mdx.\n *\n * @next/mdx wraps the config with a webpack function that injects an MDX\n * loader rule. The remark/rehype plugins are captured in that closure.\n * We probe the webpack function with a mock config to extract them.\n */\nexport async function extractMdxOptions(\n config: NextConfig,\n root: string = process.cwd(),\n): Promise<MdxOptions | null> {\n return (await probeWebpackConfig(config, root)).mdx;\n}\n\n/**\n * Probe file candidates relative to root. Returns the first one that exists,\n * or null if none match.\n */\nfunction probeFiles(root: string, candidates: string[]): string | null {\n for (const candidate of candidates) {\n const abs = path.resolve(root, candidate);\n if (fs.existsSync(abs)) return abs;\n }\n return null;\n}\n\nconst I18N_REQUEST_CANDIDATES = [\n \"i18n/request.ts\",\n \"i18n/request.tsx\",\n \"i18n/request.js\",\n \"i18n/request.jsx\",\n \"src/i18n/request.ts\",\n \"src/i18n/request.tsx\",\n \"src/i18n/request.js\",\n \"src/i18n/request.jsx\",\n];\n\n/**\n * Detect next-intl in the project and auto-register the `next-intl/config`\n * alias if needed.\n *\n * next-intl's `createNextIntlPlugin()` crashes in vinext because it calls\n * `require('next/package.json')` to check the Next.js version. Instead,\n * vinext detects next-intl and registers the alias automatically.\n *\n * Note: `require.resolve('next-intl')` walks up to parent `node_modules`\n * directories via standard Node module resolution. In a monorepo, next-intl\n * installed at the workspace root will trigger detection even if not listed\n * in the project's own package.json. This is acceptable since a workspace-root\n * install implies the user wants it available.\n *\n * Mutates `resolved.aliases` and `resolved.env` in place.\n */\nexport function detectNextIntlConfig(root: string, resolved: ResolvedNextConfig): void {\n // Explicit alias wins — user or plugin already set it\n if (resolved.aliases[\"next-intl/config\"]) return;\n\n // Check if next-intl is installed (use main entry — some packages\n // don't expose ./package.json in their exports map)\n const require = createRequire(path.join(root, \"package.json\"));\n try {\n require.resolve(\"next-intl\");\n } catch {\n return; // next-intl not installed\n }\n\n // Probe for the i18n request config file\n const configPath = probeFiles(root, I18N_REQUEST_CANDIDATES);\n if (!configPath) return;\n\n resolved.aliases[\"next-intl/config\"] = configPath;\n\n if (resolved.trailingSlash) {\n resolved.env._next_intl_trailing_slash = \"true\";\n }\n}\n\nfunction extractMdxOptionsFromRules(rules: any[]): MdxOptions | null {\n // Search through webpack rules for the MDX loader injected by @next/mdx\n for (const rule of rules) {\n const loaders = extractMdxLoaders(rule);\n if (loaders) return loaders;\n }\n return null;\n}\n\n/**\n * Recursively search a webpack rule (which may have nested `oneOf` arrays)\n * for an MDX loader and extract its remark/rehype/recma plugin options.\n */\nfunction extractMdxLoaders(rule: any): MdxOptions | null {\n if (!rule) return null;\n\n // Check `oneOf` arrays (Next.js uses these extensively)\n if (Array.isArray(rule.oneOf)) {\n for (const child of rule.oneOf) {\n const result = extractMdxLoaders(child);\n if (result) return result;\n }\n }\n\n // Check `use` array (loader chain)\n const use = Array.isArray(rule.use) ? rule.use : rule.use ? [rule.use] : [];\n for (const loader of use) {\n const loaderPath = typeof loader === \"string\" ? loader : loader?.loader;\n if (typeof loaderPath === \"string\" && isMdxLoader(loaderPath)) {\n const opts = typeof loader === \"object\" ? loader.options : {};\n return extractPluginsFromOptions(opts);\n }\n }\n\n // Check direct `loader` field\n if (typeof rule.loader === \"string\" && isMdxLoader(rule.loader)) {\n return extractPluginsFromOptions(rule.options);\n }\n\n return null;\n}\n\nfunction isMdxLoader(loaderPath: string): boolean {\n return (\n loaderPath.includes(\"mdx\") &&\n (loaderPath.includes(\"@next\") ||\n loaderPath.includes(\"@mdx-js\") ||\n loaderPath.includes(\"mdx-js-loader\") ||\n loaderPath.includes(\"next-mdx\"))\n );\n}\n\nfunction extractPluginsFromOptions(opts: any): MdxOptions | null {\n if (!opts || typeof opts !== \"object\") return null;\n\n const remarkPlugins = Array.isArray(opts.remarkPlugins) ? opts.remarkPlugins : undefined;\n const rehypePlugins = Array.isArray(opts.rehypePlugins) ? opts.rehypePlugins : undefined;\n const recmaPlugins = Array.isArray(opts.recmaPlugins) ? opts.recmaPlugins : undefined;\n\n // Only return if at least one plugin array is non-empty\n if (\n (remarkPlugins && remarkPlugins.length > 0) ||\n (rehypePlugins && rehypePlugins.length > 0) ||\n (recmaPlugins && recmaPlugins.length > 0)\n ) {\n return {\n ...(remarkPlugins && remarkPlugins.length > 0 ? { remarkPlugins } : {}),\n ...(rehypePlugins && rehypePlugins.length > 0 ? { rehypePlugins } : {}),\n ...(recmaPlugins && recmaPlugins.length > 0 ? { recmaPlugins } : {}),\n };\n }\n\n return null;\n}\n"],"mappings":"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"}
package/dist/deploy.js CHANGED
@@ -636,17 +636,34 @@ export default {
636
636
  * Response headers take precedence over middleware headers for all headers
637
637
  * except Set-Cookie, which is additive (both middleware and response cookies
638
638
  * are preserved). Matches the behavior in prod-server.ts. Uses getSetCookie()
639
- * to preserve multiple Set-Cookie values.
639
+ * to preserve multiple Set-Cookie values. Keep this in sync with
640
+ * prod-server.ts and server/worker-utils.ts.
640
641
  */
641
642
  function mergeHeaders(
642
643
  response: Response,
643
644
  extraHeaders: Record<string, string | string[]>,
644
645
  statusOverride?: number,
645
646
  ): Response {
646
- if (!Object.keys(extraHeaders).length && !statusOverride) return response;
647
+ const NO_BODY_RESPONSE_STATUSES = new Set([204, 205, 304]);
648
+ function isVinextStreamedHtmlResponse(response: Response): boolean {
649
+ return response.__vinextStreamedHtmlResponse === true;
650
+ }
651
+ function isContentLengthHeader(name: string): boolean {
652
+ return name.toLowerCase() === "content-length";
653
+ }
654
+ function cancelResponseBody(response: Response): void {
655
+ const body = response.body;
656
+ if (!body || body.locked) return;
657
+ void body.cancel().catch(() => {
658
+ /* ignore cancellation failures on discarded bodies */
659
+ });
660
+ }
661
+
662
+ const status = statusOverride ?? response.status;
647
663
  const merged = new Headers();
648
664
  // Middleware/config headers go in first (lower precedence)
649
665
  for (const [k, v] of Object.entries(extraHeaders)) {
666
+ if (isContentLengthHeader(k)) continue;
650
667
  if (Array.isArray(v)) {
651
668
  for (const item of v) merged.append(k, item);
652
669
  } else {
@@ -661,9 +678,40 @@ function mergeHeaders(
661
678
  });
662
679
  const responseCookies = response.headers.getSetCookie?.() ?? [];
663
680
  for (const cookie of responseCookies) merged.append("set-cookie", cookie);
681
+
682
+ const shouldDropBody = NO_BODY_RESPONSE_STATUSES.has(status);
683
+ const shouldStripStreamLength =
684
+ isVinextStreamedHtmlResponse(response) && merged.has("content-length");
685
+
686
+ if (
687
+ !Object.keys(extraHeaders).some((key) => !isContentLengthHeader(key)) &&
688
+ statusOverride === undefined &&
689
+ !shouldDropBody &&
690
+ !shouldStripStreamLength
691
+ ) {
692
+ return response;
693
+ }
694
+
695
+ if (shouldDropBody) {
696
+ cancelResponseBody(response);
697
+ merged.delete("content-encoding");
698
+ merged.delete("content-length");
699
+ merged.delete("content-type");
700
+ merged.delete("transfer-encoding");
701
+ return new Response(null, {
702
+ status,
703
+ statusText: status === response.status ? response.statusText : undefined,
704
+ headers: merged,
705
+ });
706
+ }
707
+
708
+ if (shouldStripStreamLength) {
709
+ merged.delete("content-length");
710
+ }
711
+
664
712
  return new Response(response.body, {
665
- status: statusOverride ?? response.status,
666
- statusText: response.statusText,
713
+ status,
714
+ statusText: status === response.status ? response.statusText : undefined,
667
715
  headers: merged,
668
716
  });
669
717
  }