diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 4f4094121dd..4de8875c2f1 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -1782,15 +1782,13 @@ export default async function loadConfig( } // Original implementation continues below... - if (!process.env.__NEXT_PRIVATE_RENDER_WORKER) { - try { - loadWebpackHook() - } catch (err) { - // this can fail in standalone mode as the files - // aren't traced/included - if (!process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) { - throw err - } + try { + loadWebpackHook() + } catch (err) { + // this can fail in standalone mode as the files + // aren't traced/included + if (!process.env.__NEXT_PRIVATE_STANDALONE_CONFIG) { + throw err } } diff --git a/packages/next/src/server/dev/hot-reloader-turbopack.ts b/packages/next/src/server/dev/hot-reloader-turbopack.ts index 6c4a3af7fc5..8cfbaac754f 100644 --- a/packages/next/src/server/dev/hot-reloader-turbopack.ts +++ b/packages/next/src/server/dev/hot-reloader-turbopack.ts @@ -41,7 +41,7 @@ import { deleteCache } from './require-cache' import { clearAllModuleContexts, clearModuleContext, -} from '../lib/render-server' +} from '../web/sandbox/context' import { denormalizePagePath } from '../../shared/lib/page-path/denormalize-page-path' import { trace } from '../../trace' import { diff --git a/packages/next/src/server/lib/render-server.ts b/packages/next/src/server/lib/render-server.ts deleted file mode 100644 index 0c23057710d..00000000000 --- a/packages/next/src/server/lib/render-server.ts +++ /dev/null @@ -1,188 +0,0 @@ -import type { NextServer, RequestHandler, UpgradeHandler } from '../next' -import type { DevBundlerService } from './dev-bundler-service' -import type { - DevServerState, - DevServerStateUpdate, -} from '../dev/dev-server-state' -import type { WorkerRequestHandler } from './types' - -import next from '../next' -import type { Span } from '../../trace' -import type { ServerResponse } from 'http' -import type { OnCacheEntryHandler } from '../request-meta' -import { interopDefault } from '../../lib/interop-default' -import { formatDynamicImportPath } from '../../lib/format-dynamic-import-path' -import type { ConfiguredExperimentalFeature } from '../config' - -export type ServerInitResult = { - requestHandler: RequestHandler - upgradeHandler: UpgradeHandler - server: NextServer - // Make an effort to close upgraded HTTP requests (e.g. Turbopack HMR websockets) - closeUpgraded: () => void - // The distDir from config, used by the parent process for telemetry/trace - distDir: string - // Experimental features from config, used for logging after server is ready - experimentalFeatures: ConfiguredExperimentalFeature[] - // Whether cache components is enabled - cacheComponents: boolean - // Whether AGENTS.md / CLAUDE.md auto-generation is enabled (default true) - agentRules?: boolean -} - -let initializations: Record | undefined> = {} - -let sandboxContext: undefined | typeof import('../web/sandbox/context') - -if (process.env.NODE_ENV !== 'production') { - sandboxContext = - require('../web/sandbox/context') as typeof import('../web/sandbox/context') -} - -export function clearAllModuleContexts() { - return sandboxContext?.clearAllModuleContexts() -} - -export function clearModuleContext(target: string) { - return sandboxContext?.clearModuleContext(target) -} - -async function getInitialization(dir: string) { - const initialization = await initializations[dir] - if (!initialization) { - throw new Error('Invariant: no app initialized') - } - return initialization -} - -export async function updateDevServerState( - dir: string, - update: DevServerStateUpdate -) { - const initialization = await getInitialization(dir) - const { server } = initialization - await server.updateDevServerState(update) -} - -export async function reloadEnv(dir: string) { - const initialization = await getInitialization(dir) - const { server } = initialization - await server.reloadEnv() -} - -async function initializeImpl(opts: { - dir: string - port: number - dev: boolean - minimalMode?: boolean - hostname?: string - keepAliveTimeout?: number - devServerState?: DevServerState - routerServerHandler?: WorkerRequestHandler - server?: any - experimentalTestProxy: boolean - experimentalHttpsServer: boolean - _ipcPort?: string - _ipcKey?: string - bundlerService: DevBundlerService | undefined - startServerSpan: Span | undefined - quiet?: boolean - onDevServerCleanup: ((listener: () => Promise) => void) | undefined - distDir: string - experimentalFeatures: ConfiguredExperimentalFeature[] - cacheComponents: boolean -}): Promise { - const type = process.env.__NEXT_PRIVATE_RENDER_WORKER - if (type) { - process.title = 'next-render-worker-' + type - } - - let requestHandler: RequestHandler - let upgradeHandler: UpgradeHandler - - const { devServerState, ...serverOptions } = opts - const server = next({ - ...serverOptions, - hostname: opts.hostname || 'localhost', - customServer: false, - httpServer: opts.server, - port: opts.port, - }) as NextServer // should return a NextServer when `customServer: false` - - // If we're in test mode and there's a debug cache entry handler available, - // then use it to wrap the request handler instead of using the default one. - if ( - process.env.__NEXT_TEST_MODE && - process.env.NEXT_PRIVATE_DEBUG_CACHE_ENTRY_HANDLERS - ) { - // This mirrors the sole implementation of this over in: - // test/production/standalone-mode/required-server-files/cache-entry-handler.js - const createOnCacheEntryHandlers = interopDefault( - await import( - formatDynamicImportPath( - opts.dir, - process.env.NEXT_PRIVATE_DEBUG_CACHE_ENTRY_HANDLERS - ) - ) - ) as (res: ServerResponse) => { - // TODO: remove onCacheEntry once onCacheEntryV2 is the default. - onCacheEntry: OnCacheEntryHandler - onCacheEntryV2: OnCacheEntryHandler - } - - // This is not to be used in any environment other than testing, as it is - // not memoized and is subject to constant change. - requestHandler = async (req, res, parsedUrl) => { - // Re re-create the entry handler for each request. This is not - // performant, and is only used in testing environments. - const { - // TODO: remove onCacheEntry once onCacheEntryV2 is the default. - onCacheEntry, - onCacheEntryV2, - } = createOnCacheEntryHandlers(res) - - // Get the request handler, using the entry handler as the metadata each - // request. - const handler = server.getRequestHandlerWithMetadata({ - // TODO: remove onCacheEntry once onCacheEntryV2 is the default. - onCacheEntry, - onCacheEntryV2, - }) - - return handler(req, res, parsedUrl) - } - - upgradeHandler = server.getUpgradeHandler() - } else { - requestHandler = server.getRequestHandler() - upgradeHandler = server.getUpgradeHandler() - } - - if (devServerState) { - await server.updateDevServerState(devServerState) - } - await server.prepare() - - return { - requestHandler, - upgradeHandler, - server, - closeUpgraded() { - opts.bundlerService?.close() - }, - distDir: opts.distDir, - experimentalFeatures: opts.experimentalFeatures, - cacheComponents: opts.cacheComponents, - } -} - -export async function initialize( - opts: Parameters[0] -): Promise { - // if we already setup the server return as we only need to do - // this on first worker boot - if (initializations[opts.dir]) { - return initializations[opts.dir]! - } - return (initializations[opts.dir] = initializeImpl(opts)) -} diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index 73b5d56908e..09cdd6a9329 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -1,7 +1,17 @@ // this must come first as it includes require hooks -import type { WorkerRequestHandler, WorkerUpgradeHandler } from './types' +import type { + ServerInitResult, + WorkerRequestHandler, + WorkerUpgradeHandler, +} from './types' import type { DevBundler } from './router-utils/setup-dev-bundler' -import type { NextUrlWithParsedQuery, RequestMeta } from '../request-meta' +import type { + NextUrlWithParsedQuery, + OnCacheEntryHandler, + RequestMeta, +} from '../request-meta' +import type { DevServerStateUpdate } from '../dev/dev-server-state' +import type { ServerResponse } from 'http' // This is required before other imports to ensure the require hook is setup. import '../node-environment' @@ -9,6 +19,7 @@ import '../require-hook' import url from 'url' import path from 'path' +import type { NextServer, NextServerOptions, RequestHandler } from '../next' import loadConfig, { type ConfiguredExperimentalFeature } from '../config' import { serveStatic } from '../serve-static' import setupDebug from 'next/dist/compiled/debug' @@ -47,7 +58,6 @@ import { } from '../dev/hot-reloader-types' import { normalizedAssetPrefix } from '../../shared/lib/normalized-asset-prefix' import { NEXT_PATCH_SYMBOL } from './patch-fetch' -import type { ServerInitResult } from './render-server' import { filterInternalHeaders } from './server-ipc/utils' import { blockCrossSiteDEV } from './router-utils/block-cross-site-dev' import { traceGlobals } from '../../trace/shared' @@ -61,6 +71,8 @@ import { isChromeDevtoolsWorkspaceUrl, } from './chrome-devtools-workspace' import { getNextConfigRuntime, type NextConfigComplete } from '../config-shared' +import { interopDefault } from '../../lib/interop-default' +import { formatDynamicImportPath } from '../../lib/format-dynamic-import-path' const debug = setupDebug('next:router-server:main') const isNextFont = (pathname: string | null) => @@ -102,17 +114,6 @@ function getErrorMessage(error: unknown): string { return deobfuscateText(String(error)) } -export type RenderServer = Pick< - typeof import('./render-server'), - 'initialize' | 'clearModuleContext' | 'updateDevServerState' | 'reloadEnv' -> - -export interface LazyRenderServerInstance { - instance?: RenderServer -} - -const requestHandlers: Record = {} - export async function initialize(opts: { dir: string port: number @@ -160,8 +161,6 @@ export async function initialize(opts: { minimalMode: opts.minimalMode, }) - const renderServer: LazyRenderServerInstance = {} - let development: | { bundler: DevBundler @@ -171,6 +170,33 @@ export async function initialize(opts: { | undefined = undefined let originalFetch = globalThis.fetch + let server: NextServer | undefined + let serverReady: Promise | undefined + let renderRequestHandler: RequestHandler | undefined + let createNextServer: (typeof import('../next'))['default'] | undefined + let requestHandler: WorkerRequestHandler = async () => { + throw new Error('Invariant request handler was not setup') + } + + const updateDevServerState = async (update: DevServerStateUpdate) => { + const ready = serverReady + const initializedServer = server + if (!ready || !initializedServer) { + return + } + await ready + await initializedServer.updateDevServerState(update) + } + + const reloadEnv = async () => { + const ready = serverReady + const initializedServer = server + if (!ready || !initializedServer) { + return + } + await ready + await initializedServer.reloadEnv() + } if (opts.dev) { const { Telemetry } = @@ -183,6 +209,10 @@ export async function initialize(opts: { const { pagesDir, appDir } = findPagesDir(opts.dir) + createNextServer = interopDefault( + require('../next') as typeof import('../next') + ) + const { setupDevBundler } = require('./router-utils/setup-dev-bundler') as typeof import('./router-utils/setup-dev-bundler') @@ -221,8 +251,8 @@ export async function initialize(opts: { let developmentBundler = await setupDevBundlerSpan.traceAsyncFn(() => setupDevBundler({ - // Passed here but the initialization of this object happens below, doing the initialization before the setupDev call breaks. - renderServer, + updateDevServerState, + reloadEnv, appDir, pagesDir, telemetry, @@ -232,6 +262,7 @@ export async function initialize(opts: { isCustomServer: opts.customServer, turbo: !!process.env.TURBOPACK, port: opts.port, + // Cleanup listeners belong to the dev bundler lifecycle. onDevServerCleanup: opts.onDevServerCleanup, resetFetch, serverFastRefresh: effectiveServerFastRefresh, @@ -240,10 +271,11 @@ export async function initialize(opts: { let devBundlerService = new DevBundlerService( developmentBundler, - // The request handler is assigned below, this allows us to create a lazy - // reference to it. + // Each initialize call owns one dev bundler and request handler. This + // closure observes the handler assigned below, so no directory-keyed + // registry is needed. (req, res) => { - return requestHandlers[opts.dir](req, res) + return requestHandler(req, res) } ) @@ -254,8 +286,9 @@ export async function initialize(opts: { } } - renderServer.instance = - require('./render-server') as typeof import('./render-server') + const next = + createNextServer ?? + interopDefault(require('../next') as typeof import('../next')) const requestHandlerImpl: WorkerRequestHandler = async (req, res) => { addRequestMeta(req, 'relativeProjectDir', relativeProjectDir) @@ -360,7 +393,8 @@ export async function initialize(opts: { return null } - if (!handlers) { + const handler = renderRequestHandler + if (!handler) { throw new Error('Failed to initialize render server') } @@ -379,10 +413,8 @@ export async function initialize(opts: { debug('invokeRender', req.url, req.headers) try { - const initResult = - await renderServer?.instance?.initialize(renderServerOpts) try { - await initResult?.requestHandler(req, res) + await handler(req, res) } catch (err) { if (err instanceof NoFallbackError) { await handleRequest(handleIndex + 1) @@ -807,7 +839,7 @@ export async function initialize(opts: { } } - let requestHandler: WorkerRequestHandler = requestHandlerImpl + requestHandler = requestHandlerImpl if (config.experimental.testProxy) { // Intercept fetch and other testmode apis. const { wrapRequestHandlerWorker, interceptTestApis } = @@ -818,31 +850,95 @@ export async function initialize(opts: { // We treat the intercepted fetch as "original" fetch that should be reset to during HMR. originalFetch = globalThis.fetch } - requestHandlers[opts.dir] = requestHandler + const serverInitMetadata = { + distDir: config.distDir, + experimentalFeatures, + cacheComponents: config.cacheComponents, + agentRules: config.agentRules, + } satisfies Pick< + ServerInitResult, + 'distDir' | 'experimentalFeatures' | 'cacheComponents' | 'agentRules' + > - const renderServerOpts: Parameters[0] = { - port: opts.port, + const commonServerOptions = { dir: opts.dir, - hostname: opts.hostname, + port: opts.port, + hostname: opts.hostname || 'localhost', minimalMode: opts.minimalMode, - dev: !!opts.dev, - server: opts.server, - devServerState: development?.bundler.devServerState, + customServer: false, + httpServer: opts.server, routerServerHandler: requestHandlerImpl, experimentalTestProxy: !!config.experimental.testProxy, experimentalHttpsServer: !!opts.experimentalHttpsServer, - bundlerService: development?.service, - startServerSpan: opts.startServerSpan, quiet: opts.quiet, - onDevServerCleanup: opts.onDevServerCleanup, - distDir: config.distDir, - experimentalFeatures, - cacheComponents: config.cacheComponents, + } as const + + if (development) { + const serverOptions = { + ...commonServerOptions, + dev: true, + bundlerService: development.service, + startServerSpan: opts.startServerSpan ?? trace('start-next-dev-server'), + } satisfies NextServerOptions & { + customServer: false + } + server = next(serverOptions) + } else { + const serverOptions = { + ...commonServerOptions, + dev: false, + } satisfies NextServerOptions & { + customServer: false + } + server = next(serverOptions) } - // pre-initialize workers - const handlers = await renderServer.instance.initialize(renderServerOpts) - // this must come after initialize of render server since it's + if ( + process.env.__NEXT_TEST_MODE && + process.env.NEXT_PRIVATE_DEBUG_CACHE_ENTRY_HANDLERS + ) { + const createOnCacheEntryHandlers = interopDefault( + await import( + formatDynamicImportPath( + opts.dir, + process.env.NEXT_PRIVATE_DEBUG_CACHE_ENTRY_HANDLERS + ) + ) + ) as (res: ServerResponse) => { + // TODO: remove onCacheEntry once onCacheEntryV2 is the default. + onCacheEntry: OnCacheEntryHandler + onCacheEntryV2: OnCacheEntryHandler + } + + renderRequestHandler = async (req, res, parsedUrl) => { + const { + // TODO: remove onCacheEntry once onCacheEntryV2 is the default. + onCacheEntry, + onCacheEntryV2, + } = createOnCacheEntryHandlers(res) + + const handler = server.getRequestHandlerWithMetadata({ + // TODO: remove onCacheEntry once onCacheEntryV2 is the default. + onCacheEntry, + onCacheEntryV2, + }) + + return handler(req, res, parsedUrl) + } + } else { + renderRequestHandler = server.getRequestHandler() + } + + serverReady = (async () => { + const devServerState = development?.bundler.devServerState + if (devServerState) { + await server.updateDevServerState(devServerState) + } + await server.prepare() + })() + await serverReady + + // this must come after initialization of the server since it's // using initialized methods if (!routerServerGlobal[RouterServerContextSymbol]) { routerServerGlobal[RouterServerContextSymbol] = {} @@ -851,12 +947,12 @@ export async function initialize(opts: { routerServerGlobal[RouterServerContextSymbol][relativeProjectDir] = { nextConfig: getNextConfigRuntime(config), - hostname: handlers.server.hostname, - revalidate: handlers.server.revalidate.bind(handlers.server), - render404: handlers.server.render404.bind(handlers.server), - experimentalTestProxy: renderServerOpts.experimentalTestProxy, + hostname: server.hostname, + revalidate: server.revalidate.bind(server), + render404: server.render404.bind(server), + experimentalTestProxy: !!config.experimental.testProxy, logErrorWithOriginalStack: opts.dev - ? handlers.server.logErrorWithOriginalStack.bind(handlers.server) + ? server.logErrorWithOriginalStack.bind(server) : (err: unknown) => !opts.quiet && Log.error(err), setCacheStatus: config.cacheComponents ? development?.service?.setCacheStatus.bind(development?.service) @@ -893,8 +989,7 @@ export async function initialize(opts: { fsChecker, config, opts, - renderServer.instance, - renderServerOpts, + renderRequestHandler, development?.bundler?.ensureMiddleware ) @@ -1008,13 +1103,10 @@ export async function initialize(opts: { return { requestHandler, upgradeHandler, - server: handlers.server, + server, closeUpgraded() { development?.bundler?.hotReloader?.close() }, - distDir: config.distDir, - experimentalFeatures, - cacheComponents: config.cacheComponents, - agentRules: config.agentRules, + ...serverInitMetadata, } } diff --git a/packages/next/src/server/lib/router-utils/resolve-routes.ts b/packages/next/src/server/lib/router-utils/resolve-routes.ts index 9bf4d8863e9..72a975d92a8 100644 --- a/packages/next/src/server/lib/router-utils/resolve-routes.ts +++ b/packages/next/src/server/lib/router-utils/resolve-routes.ts @@ -1,7 +1,8 @@ import type { FsOutput } from './filesystem' import type { IncomingMessage, ServerResponse } from 'http' import type { NextConfigRuntime } from '../../config-shared' -import type { RenderServer, initialize } from '../router-server' +import type { RequestHandler } from '../../next' +import type { initialize } from '../router-server' import type { PatchMatcher } from '../../../shared/lib/router/utils/path-match' import type { Redirect } from '../../../types' import type { Header } from '../../../lib/load-custom-routes' @@ -54,8 +55,7 @@ export function getResolveRoutes( >, config: NextConfigRuntime, opts: Parameters[0], - renderServer: RenderServer, - renderServerOpts: Parameters[0], + renderRequestHandler: RequestHandler, ensureMiddleware?: (url?: string) => Promise ) { let clientHashes: Record | undefined = undefined @@ -587,13 +587,6 @@ export function getResolveRoutes( await ensureMiddleware(req.url) } - const serverResult = - await renderServer?.initialize(renderServerOpts) - - if (!serverResult) { - throw new Error(`Failed to initialize render server "middleware"`) - } - addRequestMeta(req, 'invokePath', '') addRequestMeta(req, 'invokeOutput', '') addRequestMeta(req, 'invokeQuery', {}) @@ -611,7 +604,7 @@ export function getResolveRoutes( let bodyStream: ReadableStream | undefined = undefined try { try { - await serverResult.requestHandler(req, res, parsedUrl) + await renderRequestHandler(req, res, parsedUrl) } catch (err: any) { if (!('result' in err) || !('response' in err.result)) { throw err diff --git a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts index 739c54dd2e1..ba5365fa6b6 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @@ -67,7 +67,6 @@ import { getPossibleInstrumentationHookFilenames, } from '../../../build/utils' import { devPageFiles } from '../../../build/webpack/plugins/next-types-plugin/shared' -import type { LazyRenderServerInstance } from '../router-server' import { HMR_MESSAGE_SENT_TO_BROWSER } from '../../dev/hot-reloader-types' import { PAGE_TYPES } from '../../../lib/page-types' import { generateEncryptionKeyBase64 } from '../../app-render/encryption-utils-server' @@ -117,7 +116,8 @@ import { deobfuscateText } from '../../../shared/lib/magic-identifier' import { RouteKind } from '../../route-kind' export type SetupOpts = { - renderServer: LazyRenderServerInstance + updateDevServerState: (update: DevServerStateUpdate) => Promise + reloadEnv: () => Promise dir: string turbo?: boolean appDir?: string @@ -189,7 +189,7 @@ export async function updateDevServerState( update: DevServerStateUpdate ) { Object.assign(state, update) - await opts.renderServer.instance?.updateDevServerState(opts.dir, update) + await opts.updateDevServerState(update) } async function startWatcher( @@ -854,7 +854,7 @@ async function startWatcher( if (envChange) { writeEnvDefinitions = true - await opts.renderServer.instance?.reloadEnv(opts.dir) + await opts.reloadEnv() } if (hotReloader.turbopackProject) { diff --git a/packages/next/src/server/lib/types.ts b/packages/next/src/server/lib/types.ts index f329b57c06b..e2bd0771503 100644 --- a/packages/next/src/server/lib/types.ts +++ b/packages/next/src/server/lib/types.ts @@ -1,6 +1,8 @@ import type { IncomingMessage, ServerResponse } from 'http' import type { Duplex } from 'stream' +import type { NextServer, RequestHandler, UpgradeHandler } from '../next' +import type { ConfiguredExperimentalFeature } from '../config' export type WorkerRequestHandler = ( req: IncomingMessage, @@ -12,3 +14,19 @@ export type WorkerUpgradeHandler = ( socket: Duplex, head: Buffer ) => any + +export type ServerInitResult = { + requestHandler: RequestHandler + upgradeHandler: UpgradeHandler + server: NextServer + // Make an effort to close upgraded HTTP requests (e.g. Turbopack HMR websockets) + closeUpgraded: () => void + // The distDir from config, used by the parent process for telemetry/trace + distDir: string + // Experimental features from config, used for logging after server is ready + experimentalFeatures: ConfiguredExperimentalFeature[] + // Whether cache components is enabled + cacheComponents: boolean + // Whether AGENTS.md / CLAUDE.md auto-generation is enabled (default true) + agentRules?: boolean +} diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 74c5805216f..aa945983764 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -1133,7 +1133,7 @@ export default class NextNodeServer extends BaseServer< } // The matcher manager previously fell through to render for unknown - // paths. Preserve that behavior for direct render-server requests that do + // paths. Preserve that behavior for direct server requests that do // not pass through fsChecker. if (!match) { await this.render(req, res, pathname, query, parsedUrl, true) diff --git a/packages/next/src/server/next.ts b/packages/next/src/server/next.ts index 4e5a9a64c99..bfd6aa99168 100644 --- a/packages/next/src/server/next.ts +++ b/packages/next/src/server/next.ts @@ -24,7 +24,7 @@ import { getTracer } from './lib/trace/tracer' import { NextServerSpan } from './lib/trace/constants' import { formatUrl } from '../shared/lib/router/utils/format-url' import type { DevServerStateUpdate } from './dev/dev-server-state' -import type { ServerInitResult } from './lib/render-server' +import type { ServerInitResult } from './lib/types' import { AsyncCallbackSet } from './lib/async-callback-set' import { RouterServerContextSymbol, @@ -44,12 +44,19 @@ const getServerImpl = async () => { return ServerImpl } -export type NextServerOptions = Omit< - ServerOptions | DevServerOptions, - // This is assigned in this server abstraction. - 'conf' -> & - Partial> +type OptionalServerConfig = + T extends ServerOptions | DevServerOptions + ? Omit< + T, + // This is assigned in this server abstraction. + 'conf' + > & + Partial> + : never + +export type NextServerOptions = OptionalServerConfig< + ServerOptions | DevServerOptions +> export type NextBundlerOptions = { /** @deprecated Use `turbopack` instead */ @@ -621,6 +628,15 @@ class NextCustomServer implements NextWrapperServer { } // This file is used for when users run `require('next')` +function createServer( + options: NextServerOptions & + NextBundlerOptions & { + customServer: false + } +): NextServer +function createServer( + options: NextServerOptions & NextBundlerOptions +): NextWrapperServer function createServer( options: NextServerOptions & NextBundlerOptions ): NextWrapperServer {