Refactor to support custom Next.js distDir#1100
Refactor to support custom Next.js distDir#1100troendheim wants to merge 2 commits intoopennextjs:mainfrom
Conversation
|
commit: |
There was a problem hiding this comment.
Pull request overview
This PR refactors OpenNext’s build + runtime path handling to support Next.js’ configurable distDir, enabling multiple builds of the same app output with different Next build directories.
Changes:
- Introduces
globalThis.nextDistDir(injected via esbuild banner) and uses it across runtime adapters/handlers. - Replaces hardcoded
.nextpaths withoptions.nextDistDirthroughout build/bundling/copy steps. - Adds logic to read
distDirfromnext.config.*before running the Next.js build.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/open-next/src/types/global.ts | Adds global type for nextDistDir. |
| packages/open-next/src/plugins/edge.ts | Allows edge bundling to target a configurable dist dir. |
| packages/open-next/src/core/nodeMiddlewareHandler.ts | Loads middleware from globalThis.nextDistDir. |
| packages/open-next/src/build/patch/patches/patchOriginalNextConfig.ts | Patches manifests under options.nextDistDir. |
| packages/open-next/src/build/middleware/buildNodeMiddleware.ts | Updates esbuild externals to match nextDistDir. |
| packages/open-next/src/build/helper.ts | Makes normalizeOptions async; reads distDir; injects nextDistDir into esbuild banner. |
| packages/open-next/src/build/generateOutput.ts | Loads Next config from the configured dist dir. |
| packages/open-next/src/build/edge/createEdgeBundle.ts | Uses options.nextDistDir for edge bundle inputs/resources. |
| packages/open-next/src/build/createServerBundle.ts | Updates standalone server paths + traced-file copying for nextDistDir. |
| packages/open-next/src/build/createRevalidationBundle.ts | Copies prerender manifest from nextDistDir. |
| packages/open-next/src/build/createMiddleware.ts | Loads middleware manifest from nextDistDir. |
| packages/open-next/src/build/createImageOptimizationBundle.ts | Copies required server files/BUILD_ID from nextDistDir. |
| packages/open-next/src/build/createAssets.ts | Copies static/cache assets from nextDistDir. |
| packages/open-next/src/build/copyTracedFiles.ts | Adds nextDistDir option to support custom standalone paths. |
| packages/open-next/src/build.ts | Awaits async normalizeOptions. |
| packages/open-next/src/adapters/image-optimization-adapter.ts | Uses globalThis.nextDistDir for runtime config/build ID. |
| packages/open-next/src/adapters/config/index.ts | Uses globalThis.nextDistDir to locate Next artifacts at runtime. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export async function readDistDirFromConfig(appPath: string): Promise<string> { | ||
| const configExt = findNextConfig({ appPath }); | ||
|
|
||
| if (!configExt) { | ||
| return ".next"; // Default |
| // 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"; |
|
|
||
| // Copy over .next/required-server-files.json file and BUILD_ID | ||
| fs.mkdirSync(path.join(outputPath, ".next")); | ||
| fs.mkdirSync(path.join(outputPath, options.nextDistDir)); |
| `globalThis.openNextVersion = "${openNextVersion}";`, | ||
| `globalThis.nextDistDir = "${nextDistDir}";`, |
| esbuildOptions.banner?.js || "", | ||
| `globalThis.openNextDebug = ${debug};`, | ||
| `globalThis.openNextVersion = "${openNextVersion}";`, | ||
| `globalThis.nextDistDir = "${nextDistDir}";`, |
| // Handle config functions | ||
| if (typeof config === "function") { | ||
| config = await Promise.resolve(config("phase-production-build", {})); | ||
| } | ||
|
|
||
| return config?.distDir || ".next"; | ||
| } catch (error) { |
| globalThis.__dirname ??= ""; | ||
|
|
||
| export const NEXT_DIR = path.join(__dirname, ".next"); | ||
| export const NEXT_DIR = path.join(__dirname, "${distDir}"); |
| outfile: path.join(outputPath, "handler.mjs"), | ||
| external: ["./.next/*"], | ||
| external: [`./${options.nextDistDir}/*`], | ||
| platform: "node", |
| plugins: [inlineRequireResolvePlugin], | ||
| }); | ||
|
|
||
| const configModule = await import(compiledPath); |
NextJS allows the configuration of distDir (https://nextjs.org/docs/app/api-reference/config/next-config-js/distDir).
This PR introduces changes needed for the support of this config in open-next.
We will use it to build the same NextJS app (one build dir) with different distDirs simultaneously.
This functionality is already supported in the netlify adapter through opennextjs/opennextjs-netlify@6a35de6 which has been a great inspiration for these changes.