From 20e9e176c74d0a45bdbceea0785b63b358e59b1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20Tr=C3=B8ndheim?= Date: Thu, 29 Jan 2026 14:37:45 +0100 Subject: [PATCH] Refactor to support custom Next.js distDir --- .../open-next/src/adapters/config/index.ts | 5 +- .../adapters/image-optimization-adapter.ts | 2 +- packages/open-next/src/build.ts | 2 +- .../open-next/src/build/copyTracedFiles.ts | 8 +- packages/open-next/src/build/createAssets.ts | 24 ++-- .../build/createImageOptimizationBundle.ts | 10 +- .../open-next/src/build/createMiddleware.ts | 5 +- .../src/build/createRevalidationBundle.ts | 2 +- .../open-next/src/build/createServerBundle.ts | 18 ++- .../src/build/edge/createEdgeBundle.ts | 12 +- .../open-next/src/build/generateOutput.ts | 4 +- packages/open-next/src/build/helper.ts | 104 ++++++++++++++++-- .../build/middleware/buildNodeMiddleware.ts | 4 +- .../patch/patches/patchOriginalNextConfig.ts | 9 +- .../src/core/nodeMiddlewareHandler.ts | 4 +- packages/open-next/src/plugins/edge.ts | 4 +- packages/open-next/src/types/global.ts | 7 ++ 17 files changed, 175 insertions(+), 49 deletions(-) diff --git a/packages/open-next/src/adapters/config/index.ts b/packages/open-next/src/adapters/config/index.ts index 257d435f7..fe9dc64d4 100644 --- a/packages/open-next/src/adapters/config/index.ts +++ b/packages/open-next/src/adapters/config/index.ts @@ -16,7 +16,10 @@ import { loadRoutesManifest, } from "./util.js"; -export const NEXT_DIR = path.join(__dirname, ".next"); +export const NEXT_DIR = path.join( + __dirname, + globalThis.nextDistDir || ".next", +); export const OPEN_NEXT_DIR = path.join(__dirname, ".open-next"); debug({ NEXT_DIR, OPEN_NEXT_DIR }); diff --git a/packages/open-next/src/adapters/image-optimization-adapter.ts b/packages/open-next/src/adapters/image-optimization-adapter.ts index 1058e4dd0..12ed55681 100644 --- a/packages/open-next/src/adapters/image-optimization-adapter.ts +++ b/packages/open-next/src/adapters/image-optimization-adapter.ts @@ -33,7 +33,7 @@ import { optimizeImage } from "./plugins/image-optimization/image-optimization.j import { setNodeEnv } from "./util.js"; setNodeEnv(); -const nextDir = path.join(__dirname, ".next"); +const nextDir = path.join(__dirname, globalThis.nextDistDir || ".next"); const config = loadConfig(nextDir); const buildId = loadBuildId(nextDir); const nextConfig = { diff --git a/packages/open-next/src/build.ts b/packages/open-next/src/build.ts index df051c339..4dfc4972c 100755 --- a/packages/open-next/src/build.ts +++ b/packages/open-next/src/build.ts @@ -40,7 +40,7 @@ export async function build( ); // Initialize options - const options = buildHelper.normalizeOptions( + const options = await buildHelper.normalizeOptions( config, openNextDistDir, buildDir, diff --git a/packages/open-next/src/build/copyTracedFiles.ts b/packages/open-next/src/build/copyTracedFiles.ts index e26d10595..17e7a2ed5 100644 --- a/packages/open-next/src/build/copyTracedFiles.ts +++ b/packages/open-next/src/build/copyTracedFiles.ts @@ -70,6 +70,7 @@ interface CopyTracedFilesOptions { routes: string[]; bundledNextServer: boolean; skipServerFiles?: boolean; + nextDistDir?: string; } export function getManifests(nextDir: string) { @@ -92,13 +93,14 @@ export async function copyTracedFiles({ routes, bundledNextServer, skipServerFiles, + nextDistDir = ".next", }: CopyTracedFilesOptions) { const tsStart = Date.now(); - const dotNextDir = path.join(buildOutputPath, ".next"); + const dotNextDir = path.join(buildOutputPath, nextDistDir); const standaloneDir = path.join(dotNextDir, "standalone"); - const standaloneNextDir = path.join(standaloneDir, packagePath, ".next"); + const standaloneNextDir = path.join(standaloneDir, packagePath, nextDistDir); const standaloneServerDir = path.join(standaloneNextDir, "server"); - const outputNextDir = path.join(outputDir, packagePath, ".next"); + const outputNextDir = path.join(outputDir, packagePath, nextDistDir); // Files to copy // Map from files in the `.next/standalone` to files in the `.open-next` folder diff --git a/packages/open-next/src/build/createAssets.ts b/packages/open-next/src/build/createAssets.ts index 5f850ab7f..0bb0c90f9 100644 --- a/packages/open-next/src/build/createAssets.ts +++ b/packages/open-next/src/build/createAssets.ts @@ -22,9 +22,10 @@ export function createStaticAssets( ) { logger.info("Bundling static assets..."); - const { appBuildOutputPath, appPublicPath, outputDir, appPath } = options; + const { appBuildOutputPath, appPublicPath, outputDir, appPath, nextDistDir } = + options; - const NextConfig = loadConfig(path.join(appBuildOutputPath, ".next")); + const NextConfig = loadConfig(path.join(appBuildOutputPath, nextDistDir)); const basePath = useBasePath ? (NextConfig.basePath ?? "") : ""; // Create output folder @@ -47,12 +48,12 @@ export function createStaticAssets( * Note: BUILD_ID is used by the SST infra. */ fs.copyFileSync( - path.join(appBuildOutputPath, ".next/BUILD_ID"), + path.join(appBuildOutputPath, nextDistDir, "BUILD_ID"), path.join(outputPath, "BUILD_ID"), ); fs.cpSync( - path.join(appBuildOutputPath, ".next/static"), + path.join(appBuildOutputPath, nextDistDir, "static"), path.join(outputPath, "_next", "static"), { recursive: true }, ); @@ -82,25 +83,29 @@ export function createStaticAssets( export function createCacheAssets(options: buildHelper.BuildOptions) { logger.info("Bundling cache assets..."); - const { appBuildOutputPath, outputDir } = options; + const { appBuildOutputPath, outputDir, nextDistDir } = options; const packagePath = buildHelper.getPackagePath(options); const buildId = buildHelper.getBuildId(options); let useTagCache = false; const dotNextPath = path.join( appBuildOutputPath, - ".next/standalone", + nextDistDir, + "standalone", packagePath, ); const outputCachePath = path.join(outputDir, "cache", buildId); fs.mkdirSync(outputCachePath, { recursive: true }); - const sourceDirs = [".next/server/pages", ".next/server/app"] + const sourceDirs = [ + path.join(nextDistDir, "server/pages"), + path.join(nextDistDir, "server/app"), + ] .map((dir) => path.join(dotNextPath, dir)) .filter(fs.existsSync); - const htmlPages = buildHelper.getHtmlPages(dotNextPath); + const htmlPages = buildHelper.getHtmlPages(dotNextPath, nextDistDir); const isFileSkipped = (relativePath: string) => relativePath.endsWith(".js") || @@ -219,7 +224,8 @@ export function createCacheAssets(options: buildHelper.BuildOptions) { // Copy fetch-cache to cache folder const fetchCachePath = path.join( appBuildOutputPath, - ".next/cache/fetch-cache", + nextDistDir, + "cache/fetch-cache", ); if (fs.existsSync(fetchCachePath)) { const fetchOutputPath = path.join(outputDir, "cache", "__fetch", buildId); diff --git a/packages/open-next/src/build/createImageOptimizationBundle.ts b/packages/open-next/src/build/createImageOptimizationBundle.ts index f7848bae4..d5e5a1e8d 100644 --- a/packages/open-next/src/build/createImageOptimizationBundle.ts +++ b/packages/open-next/src/build/createImageOptimizationBundle.ts @@ -97,14 +97,14 @@ export async function createImageOptimizationBundle( ); // Copy over .next/required-server-files.json file and BUILD_ID - fs.mkdirSync(path.join(outputPath, ".next")); + fs.mkdirSync(path.join(outputPath, options.nextDistDir)); fs.copyFileSync( - path.join(appBuildOutputPath, ".next/required-server-files.json"), - path.join(outputPath, ".next/required-server-files.json"), + path.join(appBuildOutputPath, options.nextDistDir, "required-server-files.json"), + path.join(outputPath, options.nextDistDir, "required-server-files.json"), ); fs.copyFileSync( - path.join(appBuildOutputPath, ".next/BUILD_ID"), - path.join(outputPath, ".next/BUILD_ID"), + path.join(appBuildOutputPath, options.nextDistDir, "BUILD_ID"), + path.join(outputPath, options.nextDistDir, "BUILD_ID"), ); // Sharp provides pre-build binaries for all platforms. https://github.com/lovell/sharp/blob/main/docs/install.md#cross-platform diff --git a/packages/open-next/src/build/createMiddleware.ts b/packages/open-next/src/build/createMiddleware.ts index 19fc80500..fc9bb3dd3 100644 --- a/packages/open-next/src/build/createMiddleware.ts +++ b/packages/open-next/src/build/createMiddleware.ts @@ -31,7 +31,10 @@ export async function createMiddleware( logger.info("Bundling middleware function..."); const { config, outputDir } = options; - const buildOutputDotNextDir = path.join(options.appBuildOutputPath, ".next"); + const buildOutputDotNextDir = path.join( + options.appBuildOutputPath, + options.nextDistDir, + ); // Get middleware manifest const middlewareManifest = loadMiddlewareManifest(buildOutputDotNextDir); diff --git a/packages/open-next/src/build/createRevalidationBundle.ts b/packages/open-next/src/build/createRevalidationBundle.ts index 81e5ad12d..29de652a6 100644 --- a/packages/open-next/src/build/createRevalidationBundle.ts +++ b/packages/open-next/src/build/createRevalidationBundle.ts @@ -46,7 +46,7 @@ export async function createRevalidationBundle( // Copy over .next/prerender-manifest.json file fs.copyFileSync( - path.join(appBuildOutputPath, ".next", "prerender-manifest.json"), + path.join(appBuildOutputPath, options.nextDistDir, "prerender-manifest.json"), path.join(outputPath, "prerender-manifest.json"), ); } diff --git a/packages/open-next/src/build/createServerBundle.ts b/packages/open-next/src/build/createServerBundle.ts index 6cb0d02c6..c5ff26d06 100644 --- a/packages/open-next/src/build/createServerBundle.ts +++ b/packages/open-next/src/build/createServerBundle.ts @@ -66,14 +66,16 @@ export async function createServerBundle( const remainingRoutes = new Set(); - const { appBuildOutputPath } = options; + const { appBuildOutputPath, nextDistDir } = options; // Find remaining routes const serverPath = path.join( appBuildOutputPath, - ".next/standalone", + nextDistDir, + "standalone", buildHelper.getPackagePath(options), - ".next/server", + nextDistDir, + "server", ); // Find app dir routes @@ -171,7 +173,7 @@ async function generateBundle( ); const middlewareManifest = loadMiddlewareManifest( - path.join(options.appBuildOutputPath, ".next"), + path.join(options.appBuildOutputPath, options.nextDistDir), ); copyMiddlewareResources( @@ -185,7 +187,12 @@ async function generateBundle( buildHelper.copyOpenNextConfig(options.buildDir, outPackagePath); // Copy env files - buildHelper.copyEnvFile(appBuildOutputPath, packagePath, outputPath); + buildHelper.copyEnvFile( + appBuildOutputPath, + options.nextDistDir, + packagePath, + outputPath, + ); // Copy all necessary traced files const { tracedFiles, manifests } = await copyTracedFiles({ @@ -194,6 +201,7 @@ async function generateBundle( outputDir: outputPath, routes: fnOptions.routes ?? ["app/page.tsx"], bundledNextServer: isBundled, + nextDistDir: options.nextDistDir, }); const additionalCodePatches = codeCustomization?.additionalCodePatches ?? []; diff --git a/packages/open-next/src/build/edge/createEdgeBundle.ts b/packages/open-next/src/build/edge/createEdgeBundle.ts index 412f8bc79..c85836c46 100644 --- a/packages/open-next/src/build/edge/createEdgeBundle.ts +++ b/packages/open-next/src/build/edge/createEdgeBundle.ts @@ -103,8 +103,9 @@ export async function buildEdgeBundle({ ), openNextEdgePlugins({ middlewareInfo, - nextDir: path.join(options.appBuildOutputPath, ".next"), + nextDir: path.join(options.appBuildOutputPath, options.nextDistDir), isInCloudflare, + distDir: options.nextDistDir, }), ...additionalPlugins, // The content updater plugin must be the last plugin @@ -188,7 +189,10 @@ export async function generateEdgeBundle( ) { logger.info(`Generating edge bundle for: ${name}`); - const buildOutputDotNextDir = path.join(options.appBuildOutputPath, ".next"); + const buildOutputDotNextDir = path.join( + options.appBuildOutputPath, + options.nextDistDir, + ); // Create output folder const outputDir = path.join(options.outputDir, "server-functions", name); @@ -235,7 +239,7 @@ export function copyMiddlewareResources( mkdirSync(path.join(destDir, "wasm"), { recursive: true }); for (const file of middlewareInfo?.wasm ?? []) { fs.copyFileSync( - path.join(options.appBuildOutputPath, ".next", file.filePath), + path.join(options.appBuildOutputPath, options.nextDistDir, file.filePath), path.join(destDir, `wasm/${file.name}.wasm`), ); } @@ -243,7 +247,7 @@ export function copyMiddlewareResources( mkdirSync(path.join(destDir, "assets"), { recursive: true }); for (const file of middlewareInfo?.assets ?? []) { fs.copyFileSync( - path.join(options.appBuildOutputPath, ".next", file.filePath), + path.join(options.appBuildOutputPath, options.nextDistDir, file.filePath), path.join(destDir, `assets/${file.name}`), ); } diff --git a/packages/open-next/src/build/generateOutput.ts b/packages/open-next/src/build/generateOutput.ts index 682fd23b0..c9789cbc5 100644 --- a/packages/open-next/src/build/generateOutput.ts +++ b/packages/open-next/src/build/generateOutput.ts @@ -190,7 +190,9 @@ export async function generateOutput(options: BuildOptions) { const defaultOriginCanstream = await canStream(config.default); - const nextConfig = loadConfig(path.join(appBuildOutputPath, ".next")); + const nextConfig = loadConfig( + path.join(appBuildOutputPath, options.nextDistDir), + ); const prefixer = prefixPattern(nextConfig.basePath ?? ""); // First add s3 origins and image optimization diff --git a/packages/open-next/src/build/helper.ts b/packages/open-next/src/build/helper.ts index fffc65b1a..b65e122c3 100644 --- a/packages/open-next/src/build/helper.ts +++ b/packages/open-next/src/build/helper.ts @@ -1,5 +1,6 @@ import fs from "node:fs"; import { createRequire } from "node:module"; +import os from "node:os"; import path from "node:path"; import url from "node:url"; @@ -15,9 +16,9 @@ import logger from "../logger.js"; const require = createRequire(import.meta.url); const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); -export type BuildOptions = ReturnType; +export type BuildOptions = Awaited>; -export function normalizeOptions( +export async function normalizeOptions( config: OpenNextConfig, distDir: string, tempBuildDir: string, @@ -29,6 +30,9 @@ export function normalizeOptions( ); const outputDir = path.join(buildOutputPath, ".open-next"); + // Read distDir from source config BEFORE building Next.js + const nextDistDir = await readDistDirFromConfig(appPath); + const { root: monorepoRoot, packager } = findPackagerAndRoot( path.join(process.cwd(), config.appPath || "."), ); @@ -57,6 +61,7 @@ export function normalizeOptions( minify: !debug, monorepoRoot, nextVersion: getNextVersion(appPath), + nextDistDir, openNextVersion: getOpenNextVersion(), openNextDistDir: distDir, outputDir, @@ -113,7 +118,7 @@ export function esbuildSync( esbuildOptions: ESBuildOptions, options: BuildOptions, ) { - const { openNextVersion, debug, minify } = options; + const { openNextVersion, debug, minify, nextDistDir } = options; const result = buildSync({ target: "esnext", format: "esm", @@ -131,6 +136,7 @@ export function esbuildSync( esbuildOptions.banner?.js || "", `globalThis.openNextDebug = ${debug};`, `globalThis.openNextVersion = "${openNextVersion}";`, + `globalThis.nextDistDir = "${nextDistDir}";`, ].join(""), }, }); @@ -149,7 +155,7 @@ export async function esbuildAsync( esbuildOptions: ESBuildOptions, options: BuildOptions, ) { - const { openNextVersion, debug, minify } = options; + const { openNextVersion, debug, minify, nextDistDir } = options; // Dump ESBuild build metadata to file in debug mode const metafile = debug && esbuildOptions.outfile !== undefined; const result = await buildAsync({ @@ -174,6 +180,7 @@ export async function esbuildAsync( esbuildOptions.banner?.js || "", `globalThis.openNextDebug = ${debug};`, `globalThis.openNextVersion = "${openNextVersion}";`, + `globalThis.nextDistDir = "${nextDistDir}";`, ].join(""), }, }); @@ -249,7 +256,7 @@ export function removeFiles( ); } -export function getHtmlPages(dotNextPath: string) { +export function getHtmlPages(dotNextPath: string, nextDistDir = ".next") { // Get a list of HTML pages // // sample return value: @@ -260,7 +267,8 @@ export function getHtmlPages(dotNextPath: string) { // ]) const manifestPath = path.join( dotNextPath, - ".next/server/pages-manifest.json", + nextDistDir, + "server/pages-manifest.json", ); const manifest = fs.readFileSync(manifestPath, "utf-8"); return Object.entries(JSON.parse(manifest)) @@ -272,7 +280,7 @@ export function getHtmlPages(dotNextPath: string) { export function getBuildId(options: BuildOptions) { return fs .readFileSync( - path.join(options.appBuildOutputPath, ".next/BUILD_ID"), + path.join(options.appBuildOutputPath, options.nextDistDir, "BUILD_ID"), "utf-8", ) .trim(); @@ -452,10 +460,11 @@ export function copyOpenNextConfig( export function copyEnvFile( appPath: string, + nextDistDir: string, packagePath: string, outputPath: string, ) { - const baseAppPath = path.join(appPath, ".next/standalone", packagePath); + const baseAppPath = path.join(appPath, nextDistDir, "standalone", packagePath); const baseOutputPath = path.join(outputPath, packagePath); const envPath = path.join(baseAppPath, ".env"); if (fs.existsSync(envPath)) { @@ -481,6 +490,79 @@ export function findNextConfig({ ); } +/** + * Read the distDir from the source Next.js config file. + * This must be called BEFORE building Next.js since distDir determines + * where the build output will be placed. + * + * @param appPath - The path to the Next.js app + * @returns The distDir from the config, or ".next" as default + */ +export async function readDistDirFromConfig(appPath: string): Promise { + const configExt = findNextConfig({ appPath }); + + if (!configExt) { + return ".next"; // Default + } + + const configPath = path.join(appPath, `next.config.${configExt}`); + + try { + // For TypeScript, compile first using esbuild (similar to importNextConfigFromSource) + if (configExt === "ts") { + const tempDir = fs.mkdtempSync( + path.join(os.tmpdir(), "opennext-distdir-"), + ); + const compiledPath = path.join(tempDir, "next.config.mjs"); + + try { + const { inlineRequireResolvePlugin } = await import( + "../plugins/inline-require-resolve.js" + ); + await buildAsync({ + entryPoints: [configPath], + outfile: compiledPath, + bundle: true, + format: "esm", + platform: "node", + plugins: [inlineRequireResolvePlugin], + }); + + const configModule = await import(compiledPath); + let config = configModule.default || configModule; + + // Handle config functions + if (typeof config === "function") { + config = await Promise.resolve(config("phase-production-build", {})); + } + + return config?.distDir || ".next"; + } finally { + fs.rmSync(tempDir, { recursive: true, force: true }); + } + } + + // For JS/MJS/CJS, import directly + // Need to use file:// protocol for ESM imports + const fileUrl = url.pathToFileURL(configPath).href; + const configModule = await import(fileUrl); + let config = configModule.default || configModule; + + // Handle config functions + if (typeof config === "function") { + config = await Promise.resolve(config("phase-production-build", {})); + } + + return config?.distDir || ".next"; + } catch (error) { + logger.warn( + `Failed to read distDir from ${configPath}, using default ".next"`, + error, + ); + return ".next"; + } +} + /** * Check we are in a Nextjs app by looking for the Nextjs config file. */ @@ -550,7 +632,11 @@ export function getPackagePath(options: BuildOptions) { export function getBundlerRuntime( options: BuildOptions, ): "webpack" | "turbopack" { - const dotNextServerPath = path.join(options.appPath, ".next/server"); + const dotNextServerPath = path.join( + options.appPath, + options.nextDistDir, + "server", + ); if (fs.existsSync(path.join(dotNextServerPath, "webpack-runtime.js"))) { return "webpack"; } diff --git a/packages/open-next/src/build/middleware/buildNodeMiddleware.ts b/packages/open-next/src/build/middleware/buildNodeMiddleware.ts index 8cf95f003..20fcd8feb 100644 --- a/packages/open-next/src/build/middleware/buildNodeMiddleware.ts +++ b/packages/open-next/src/build/middleware/buildNodeMiddleware.ts @@ -67,7 +67,7 @@ export async function buildExternalNodeMiddleware( path.join(options.openNextDistDir, "adapters", "middleware.js"), ], outfile: path.join(outputPath, "handler.mjs"), - external: ["./.next/*"], + external: [`./${options.nextDistDir}/*`], platform: "node", plugins: [ openNextResolvePlugin({ @@ -128,7 +128,7 @@ export async function buildBundledNodeMiddleware( entryPoints: [ path.join(options.openNextDistDir, "core/nodeMiddlewareHandler.js"), ], - external: ["./.next/*"], + external: [`./${options.nextDistDir}/*`], outfile: path.join(options.buildDir, "middleware.mjs"), bundle: true, platform: "node", diff --git a/packages/open-next/src/build/patch/patches/patchOriginalNextConfig.ts b/packages/open-next/src/build/patch/patches/patchOriginalNextConfig.ts index 59fd4ca44..7e8d4ca55 100644 --- a/packages/open-next/src/build/patch/patches/patchOriginalNextConfig.ts +++ b/packages/open-next/src/build/patch/patches/patchOriginalNextConfig.ts @@ -28,14 +28,17 @@ export async function patchOriginalNextConfig( // are patched as Open Next uses either of them. const manifestPath = path.join( options.appBuildOutputPath, - ".next/required-server-files.json", + options.nextDistDir, + "required-server-files.json", ); const manifestStandalonePath = path.join( options.appBuildOutputPath, - ".next/standalone", + options.nextDistDir, + "standalone", buildHelper.getPackagePath(options), - ".next/required-server-files.json", + options.nextDistDir, + "required-server-files.json", ); if (fs.existsSync(manifestPath)) { diff --git a/packages/open-next/src/core/nodeMiddlewareHandler.ts b/packages/open-next/src/core/nodeMiddlewareHandler.ts index 73c86d140..935de3760 100644 --- a/packages/open-next/src/core/nodeMiddlewareHandler.ts +++ b/packages/open-next/src/core/nodeMiddlewareHandler.ts @@ -30,8 +30,8 @@ export default async function middlewareHandler( if (!_module) { // We use await import here so that we are sure that it is loaded after AsyncLocalStorage is defined on globalThis // We need both await here, same way as in https://github.com/opennextjs/opennextjs-aws/pull/704 - //@ts-expect-error - This file should be bundled with esbuild - _module = await (await import("./.next/server/middleware.js")).default; + const distDir = globalThis.nextDistDir || ".next"; + _module = await (await import(`./${distDir}/server/middleware.js`)).default; } const adapterFn = _module!.default || _module; const result = await adapterFn({ diff --git a/packages/open-next/src/plugins/edge.ts b/packages/open-next/src/plugins/edge.ts index 7c6fd66dc..388f6af0d 100644 --- a/packages/open-next/src/plugins/edge.ts +++ b/packages/open-next/src/plugins/edge.ts @@ -27,6 +27,7 @@ export interface IPluginSettings { nextDir: string; middlewareInfo?: MiddlewareInfo; isInCloudflare?: boolean; + distDir?: string; } /** @@ -39,6 +40,7 @@ export function openNextEdgePlugins({ nextDir, middlewareInfo, isInCloudflare, + distDir = ".next", }: IPluginSettings): Plugin { const entryFiles = middlewareInfo?.files.map((file: string) => @@ -176,7 +178,7 @@ ${contents} globalThis.__dirname ??= ""; - export const NEXT_DIR = path.join(__dirname, ".next"); + export const NEXT_DIR = path.join(__dirname, "${distDir}"); export const OPEN_NEXT_DIR = path.join(__dirname, ".open-next"); debug({ NEXT_DIR, OPEN_NEXT_DIR }); diff --git a/packages/open-next/src/types/global.ts b/packages/open-next/src/types/global.ts index 3f3bc1e62..04372804f 100644 --- a/packages/open-next/src/types/global.ts +++ b/packages/open-next/src/types/global.ts @@ -201,6 +201,13 @@ declare global { */ var openNextVersion: string; + /** + * The Next.js dist directory (e.g., ".next" or custom distDir from next.config). + * Available everywhere. + * Defined in the esbuild banner. + */ + var nextDistDir: string; + /** * The function that is used when resolving external rewrite requests. * Only available in main functions