UNPKG

next

Version:

The React Framework

1,047 lines 86.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "createHotReloaderTurbopack", { enumerable: true, get: function() { return createHotReloaderTurbopack; } }); const _promises = require("fs/promises"); const _fs = require("fs"); const _inspector = /*#__PURE__*/ _interop_require_wildcard(require("inspector")); const _path = require("path"); const _url = require("url"); const _ws = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/ws")); const _store = require("../../build/output/store"); const _hotreloadertypes = require("./hot-reloader-types"); const _swc = require("../../build/swc"); const _log = /*#__PURE__*/ _interop_require_wildcard(require("../../build/output/log")); const _constants = require("../../shared/lib/constants"); const _middlewareturbopack = require("./middleware-turbopack"); const _utils = require("../../shared/lib/utils"); const _utils1 = require("../utils"); const _loadmanifestexternal = require("../load-manifest.external"); const _requirecache = require("./require-cache"); const _renderserver = require("../lib/render-server"); const _denormalizepagepath = require("../../shared/lib/page-path/denormalize-page-path"); const _trace = require("../../trace"); const _turbopackutils = require("./turbopack-utils"); const _setupdevbundler = require("../lib/router-utils/setup-dev-bundler"); const _manifestloader = require("../../shared/lib/turbopack/manifest-loader"); const _ondemandentryhandler = require("./on-demand-entry-handler"); const _entrykey = require("../../shared/lib/turbopack/entry-key"); const _messages = require("./messages"); const _encryptionutilsserver = require("../app-render/encryption-utils-server"); const _apppageroutedefinition = require("../route-definitions/app-page-route-definition"); const _apppaths = require("../../shared/lib/router/utils/app-paths"); const _entries = require("../../build/entries"); const _ismetadataroute = require("../../lib/metadata/is-metadata-route"); const _patcherrorinspect = require("../patch-error-inspect"); const _sourcemaps = require("../lib/source-maps"); const _getnexterrorfeedbackmiddleware = require("../../next-devtools/server/get-next-error-feedback-middleware"); const _utils2 = require("../../shared/lib/turbopack/utils"); const _getdevoverlayfontmiddleware = require("../../next-devtools/server/font/get-dev-overlay-font-middleware"); const _devindicatorserverstate = require("./dev-indicator-server-state"); const _devindicatormiddleware = require("../../next-devtools/server/dev-indicator-middleware"); const _restartdevservermiddleware = require("../../next-devtools/server/restart-dev-server-middleware"); const _compilationevents = require("../../shared/lib/turbopack/compilation-events"); const _deferredemit = require("../../shared/lib/turbopack/deferred-emit"); const _getsupportedbrowsers = require("../../build/get-supported-browsers"); const _printbuilderrors = require("../../build/print-build-errors"); const _receivelogs = require("./browser-logs/receive-logs"); const _normalizepath = require("../../lib/normalize-path"); const _turbopackcacheseed = require("../../lib/turbopack-cache-seed"); const _devtoolsconfigmiddleware = require("../../next-devtools/server/devtools-config-middleware"); const _attachnodejsdebuggermiddleware = require("../../next-devtools/server/attach-nodejs-debugger-middleware"); const _debugchannel = require("./debug-channel"); const _hotreloadersharedutils = require("./hot-reloader-shared-utils"); const _getmcpmiddleware = require("../mcp/get-mcp-middleware"); const _formatcompilationissues = require("../mcp/tools/utils/format-compilation-issues"); const _requestinsights = require("../lib/trace/request-insights"); const _resolvepathtoroute = require("../mcp/tools/utils/resolve-path-to-route"); const _geterrors = require("../mcp/tools/get-errors"); const _getpagemetadata = require("../mcp/tools/get-page-metadata"); const _formaterrors = require("../mcp/tools/utils/format-errors"); const _mcptelemetrytracker = require("../mcp/mcp-telemetry-tracker"); const _filelogger = require("./browser-logs/file-logger"); const _serializederrors = require("./serialized-errors"); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interop_require_wildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = { __proto__: null }; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for(var key in obj){ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const wsServer = new _ws.default.Server({ noServer: true }); const isTestMode = !!(process.env.NEXT_TEST_MODE || process.env.__NEXT_TEST_MODE || process.env.DEBUG); const sessionId = Math.floor(Number.MAX_SAFE_INTEGER * Math.random()); /** Output directory (relative to `distDir`) of server-HMR-managed chunks. */ const SERVER_HMR_CHUNKS_DIR = (0, _path.join)('server', 'chunks'); /** * Collects the output chunk paths touched by a partial HMR update. Both * single-chunk `EcmascriptMergedUpdate`s and `ChunkListUpdate`s (which nest * per-chunk deltas inside `merged`) are flattened so the manifest cache can be * invalidated for every affected chunk after a successful apply. */ function collectUpdatedChunkPaths(instruction) { const paths = new Set(); if (instruction.type === 'EcmascriptMergedUpdate') { for (const chunkPath of Object.keys(instruction.chunks ?? {})){ paths.add(chunkPath); } } else if (instruction.type === 'ChunkListUpdate') { for (const chunkPath of Object.keys(instruction.chunks ?? {})){ paths.add(chunkPath); } for (const merged of instruction.merged ?? []){ for (const chunkPath of Object.keys(merged.chunks ?? {})){ paths.add(chunkPath); } } } else { throw Object.defineProperty(new Error(`[Server HMR] unreachable: unknown HMR instruction type ${instruction.type}`), "__NEXT_ERROR_CODE", { value: "E1459", enumerable: false, configurable: true }); } return Array.from(paths); } function setupServerHmr(project, { reEvaluateAllModulesExpensive, onApplied }) { async function runSubscription() { const subscription = project.allHmrEvents(_swc.HmrTarget.Server); // Subscribing immediately emits one event describing the current state. // There's no previous state to diff it against, so it never carries anything // to apply. Drop it; real updates start with the second event. await subscription.next(); for await (const result of subscription){ const update = result; // A 'restart' from the wire protocol means the update can't be applied // incrementally, so we must fully re-evaluate all chunks from disk. This // clears the module cache and notifies browsers to refetch RSC. const requiresFullReEvaluation = update.type === 'restart'; if (requiresFullReEvaluation) { await reEvaluateAllModulesExpensive(); continue; } if (update.type !== 'partial') { continue; } // `EcmascriptMergedUpdate` is the only instruction the Node.js runtime // knows how to apply; `ChunkListUpdate` is browser-only. Anything else is // unknown to us, so ignore it rather than evicting the module cache. const instruction = update.instruction; if (!instruction || instruction.type !== 'EcmascriptMergedUpdate' && instruction.type !== 'ChunkListUpdate') { throw Object.defineProperty(new Error(`[Server HMR] unreachable: unexpected update instruction type ${instruction.type}`), "__NEXT_ERROR_CODE", { value: "E1460", enumerable: false, configurable: true }); } // No handler registered yet (before first request, or right after // reEvaluateAllModulesExpensive()) — nothing live to update, so skip // until the next request. const handlers = globalThis.__turbopack_server_hmr_handlers__; if (!handlers || handlers.size === 0) { continue; } if (typeof __turbopack_server_hmr_apply__ === 'function') { try { __turbopack_server_hmr_apply__(update); } catch { // A matching runtime tried the apply and threw. Evict require.cache // so the next request loads fresh, then skip onApplied. (A no-match // update is a no-op and does not throw.) await reEvaluateAllModulesExpensive(); continue; } const updatedChunkPaths = collectUpdatedChunkPaths(instruction); // An empty partial only advances the version state (e.g. the seed // transition or a new endpoint); nothing changed on disk, so don't // invalidate manifests or ping browsers to refetch RSC. if (updatedChunkPaths.length > 0) { await onApplied(updatedChunkPaths); } } else { await reEvaluateAllModulesExpensive(); } } } // Start listening for changes in background. Re-subscribe on error so // server Fast Refresh continues working for the rest of the dev session. // The delay keeps a persistently-failing subscription (which throws on the // initial read) from hot-looping through reEvaluateAllModulesExpensive(). ; (async ()=>{ for(;;){ try { await runSubscription(); return; } catch (err) { console.error('[Server HMR] Subscription error, resubscribing:', err); await reEvaluateAllModulesExpensive(); await new Promise((resolve)=>setTimeout(resolve, 1000)); } } })(); } function getSourceMapFromTurbopack(project, sourceURL) { let sourceMapJson = null; try { sourceMapJson = project.getSourceMapSync(sourceURL); } catch (err) {} if (sourceMapJson === null) { return undefined; } else { return JSON.parse(sourceMapJson); } } function getSourceMapURLFromTurbopack(distDir, scriptNameOrSourceURL) { // React invokes this with the raw stack-frame filename, which arrives // either as an absolute filesystem path or as a `file:` URL. Anything else // (`file:` URLs with a query are eval'd server HMR modules carrying inline // source maps, `webpack-internal://`, `node:internal/...`, `<anonymous>`, // ...) is not something we have an emitted source map for. let scriptPath = scriptNameOrSourceURL; if (scriptNameOrSourceURL.startsWith('file://')) { if (scriptNameOrSourceURL.includes('?')) { return null; } try { scriptPath = (0, _url.fileURLToPath)(scriptNameOrSourceURL); } catch { return null; } } if (!(0, _path.isAbsolute)(scriptPath)) { return null; } // Only chunks emitted into `distDir` have an on-disk source map to point at. const relativePath = (0, _path.relative)(distDir, scriptPath); if (relativePath.startsWith('..') || // On Windows an absolute path on a different drive is returned unchanged // rather than as a `..`-prefixed relative path. (0, _path.isAbsolute)(relativePath)) { return null; } // The emitted source map lives next to its chunk with a `.map` suffix (see // `SourceMapAsset::path`). Encode through `pathToFileURL` so any special // characters in the path are escaped into a well-formed `file:` URL. return (0, _url.pathToFileURL)(scriptPath + '.map').href; } async function createHotReloaderTurbopack(opts, serverFields, distDir, resetFetch, lockfile, serverFastRefresh) { var _opts_nextConfig_turbopack, _nextConfig_watchOptions; const dev = true; const buildId = 'development'; const { nextConfig, dir: projectPath } = opts; const bindings = (0, _swc.getBindingsSync)(); // Turbopack requires native bindings and cannot run with WASM bindings. // Detect this early and give a clear, actionable error message. if (bindings.isWasm) { throw Object.defineProperty(new Error(`Turbopack is not supported on this platform (${process.platform}/${process.arch}) because native bindings are not available. ` + `Only WebAssembly (WASM) bindings were loaded, and Turbopack requires native bindings.\n\n` + `To use Next.js on this platform, use Webpack instead:\n` + ` next dev --webpack\n\n` + `For more information, see: https://nextjs.org/docs/app/api-reference/turbopack#supported-platforms`), "__NEXT_ERROR_CODE", { value: "E1049", enumerable: false, configurable: true }); } // For the debugging purpose, check if createNext or equivalent next instance setup in test cases // works correctly. Normally `run-test` hides output so only will be visible when `--debug` flag is used. if (isTestMode) { ; require('console').log('Creating turbopack project', { dir: projectPath, testMode: isTestMode }); } const hasRewrites = opts.fsChecker.rewrites.afterFiles.length > 0 || opts.fsChecker.rewrites.beforeFiles.length > 0 || opts.fsChecker.rewrites.fallback.length > 0; const hotReloaderSpan = (0, _trace.trace)('hot-reloader', undefined, { version: "16.3.0" }); // Ensure the hotReloaderSpan is flushed immediately as it's the parentSpan for all processing // of the current `next dev` invocation. hotReloaderSpan.stop(); // Initialize log monitor for file logging // Enable logging by default in development mode const mcpServerEnabled = !!nextConfig.experimental.mcpServer; const fileLogger = (0, _filelogger.getFileLogger)(); fileLogger.initialize(distDir, mcpServerEnabled); const encryptionKey = await (0, _encryptionutilsserver.generateEncryptionKeyBase64)({ isBuild: false, distDir }); // TODO: Implement let clientRouterFilters; if (nextConfig.experimental.clientRouterFilter) { // TODO this need to be set correctly for filesystem cache to work } const supportedBrowsers = (0, _getsupportedbrowsers.getSupportedBrowsers)(projectPath, dev); const currentNodeJsVersion = process.versions.node; const rootPath = ((_opts_nextConfig_turbopack = opts.nextConfig.turbopack) == null ? void 0 : _opts_nextConfig_turbopack.root) || opts.nextConfig.outputFileTracingRoot || projectPath; if (nextConfig.experimental.turbopackSeedCacheFromWorktree) { (0, _turbopackcacheseed.seedTurbopackCacheIfNeeded)({ projectDir: projectPath, distDir }); } const project = await bindings.turbo.createProject({ rootPath, projectPath: (0, _normalizepath.normalizePath)((0, _path.relative)(rootPath, projectPath) || '.'), distDir, nextConfig: opts.nextConfig, watch: { enable: dev, pollIntervalMs: (_nextConfig_watchOptions = nextConfig.watchOptions) == null ? void 0 : _nextConfig_watchOptions.pollIntervalMs }, dev, env: process.env, defineEnv: (0, _swc.createDefineEnv)({ isTurbopack: true, clientRouterFilters, config: nextConfig, dev, distDir, projectPath, fetchCacheKeyPrefix: opts.nextConfig.experimental.fetchCacheKeyPrefix, hasRewrites, // TODO: Implement middlewareMatchers: undefined, rewrites: opts.fsChecker.rewrites }), buildId, encryptionKey, previewProps: opts.fsChecker.previewProps, browserslistQuery: supportedBrowsers.join(', '), noMangling: false, writeRoutesHashesManifest: false, currentNodeJsVersion, isPersistentCachingEnabled: (0, _utils2.isFileSystemCacheEnabledForDev)(opts.nextConfig), nextVersion: "16.3.0", serverHmr: serverFastRefresh }, { turbopackMemoryEviction: opts.nextConfig.experimental.turbopackMemoryEvictionMode, isShortSession: false }); (0, _compilationevents.backgroundLogCompilationEvents)(project, { eventTypes: [ 'StartupCacheInvalidationEvent', 'TimingEvent', 'SlowFilesystemEvent', 'TraceEvent' ], parentSpan: hotReloaderSpan }); (0, _patcherrorinspect.setBundlerFindSourceMapImplementation)(getSourceMapFromTurbopack.bind(null, project)); let canonicalDistDir = distDir; try { canonicalDistDir = (0, _fs.realpathSync)(distDir); } catch {} (0, _sourcemaps.setBundlerFindSourceMapURLImplementation)(getSourceMapURLFromTurbopack.bind(null, canonicalDistDir)); // Set up code frame renderer using native bindings const { installCodeFrameSupport } = require('../lib/install-code-frame'); installCodeFrameSupport(); opts.onDevServerCleanup == null ? void 0 : opts.onDevServerCleanup.call(opts, async ()=>{ (0, _patcherrorinspect.setBundlerFindSourceMapImplementation)(()=>undefined); (0, _sourcemaps.setBundlerFindSourceMapURLImplementation)(()=>null); await project.onExit(); await (lockfile == null ? void 0 : lockfile.unlock()); }); const entrypointsSubscription = project.entrypointsSubscribe(); const currentWrittenEntrypoints = new Map(); const currentEntrypoints = { global: { app: undefined, document: undefined, error: undefined, middleware: undefined, instrumentation: undefined }, page: new Map(), app: new Map() }; const currentTopLevelIssues = new Map(); const currentEntryIssues = new Map(); const manifestLoader = new _manifestloader.TurbopackManifestLoader({ buildId, distDir, encryptionKey, dev: true, sriEnabled: false }); // Dev specific const changeSubscriptions = new Map(); const serverPathState = new Map(); const readyIds = new Set(); let currentEntriesHandlingResolve; let currentEntriesHandling = new Promise((resolve)=>currentEntriesHandlingResolve = resolve); const assetMapper = new _turbopackutils.AssetMapper(); // Deferred entries state management const deferredEntriesConfig = nextConfig.experimental.deferredEntries; const hasDeferredEntriesConfig = deferredEntriesConfig && deferredEntriesConfig.length > 0; let onBeforeDeferredEntriesCalled = false; let onBeforeDeferredEntriesPromise = null; // Track non-deferred entries that are currently being built const nonDeferredBuildingEntries = new Set(); // Function to wait for all non-deferred entries to be built async function waitForNonDeferredEntries() { return new Promise((resolve)=>{ const checkEntries = ()=>{ // Check if there are any non-deferred entries that are still building if (nonDeferredBuildingEntries.size === 0) { resolve(); } else { // Check again after a short delay setTimeout(checkEntries, 100); } }; checkEntries(); }); } // Function to handle deferred entry processing async function processDeferredEntry() { if (!hasDeferredEntriesConfig) return; // Wait for all non-deferred entries to be built await waitForNonDeferredEntries(); // Call the onBeforeDeferredEntries callback once if (!onBeforeDeferredEntriesCalled) { onBeforeDeferredEntriesCalled = true; if (nextConfig.experimental.onBeforeDeferredEntries) { if (!onBeforeDeferredEntriesPromise) { onBeforeDeferredEntriesPromise = nextConfig.experimental.onBeforeDeferredEntries(); } await onBeforeDeferredEntriesPromise; } } else if (onBeforeDeferredEntriesPromise) { // Wait for any in-progress callback await onBeforeDeferredEntriesPromise; } } // Track whether HMR is pending - used to call callback once after HMR settles let hmrPendingDeferredCallback = false; // Debounced function to call onBeforeDeferredEntries after HMR // This prevents rapid-fire calls when turbopack fires many update events // Use 500ms debounce to ensure all rapid updates are batched together const callOnBeforeDeferredEntriesAfterHMR = (0, _utils1.debounce)(()=>{ // Only call if HMR triggered a need for the callback if (hasDeferredEntriesConfig && hmrPendingDeferredCallback) { hmrPendingDeferredCallback = false; onBeforeDeferredEntriesCalled = true; if (nextConfig.experimental.onBeforeDeferredEntries) { onBeforeDeferredEntriesPromise = nextConfig.experimental.onBeforeDeferredEntries(); } } }, 500); function clearRequireCache(key, writtenEndpoint, { force } = {}) { if (force) { for (const { path, contentHash } of writtenEndpoint.serverPaths){ // We ignore source maps if (path.endsWith('.map')) continue; const localKey = `${key}:${path}`; serverPathState.set(localKey, contentHash); serverPathState.set(path, contentHash); } } else { // Figure out if the server files have changed let hasChange = false; const currentPaths = new Set(); for (const { path, contentHash } of writtenEndpoint.serverPaths){ // We ignore source maps if (path.endsWith('.map')) continue; currentPaths.add(path); const localKey = `${key}:${path}`; const localHash = serverPathState.get(localKey); const globalHash = serverPathState.get(path); if (localHash && localHash !== contentHash || globalHash && globalHash !== contentHash) { hasChange = true; serverPathState.set(localKey, contentHash); serverPathState.set(path, contentHash); } else { if (!localHash) { serverPathState.set(localKey, contentHash); } if (!globalHash) { serverPathState.set(path, contentHash); } } } const localKeyPrefix = `${key}:`; for (const pathKey of serverPathState.keys()){ if (pathKey.startsWith(localKeyPrefix) && !currentPaths.has(pathKey.slice(localKeyPrefix.length))) { serverPathState.delete(pathKey); hasChange = true; } } if (!hasChange) { return false; } } // Edge does not participate in server HMR. if (writtenEndpoint.type === 'edge') { void (0, _renderserver.clearAllModuleContexts)(); } const serverPaths = writtenEndpoint.serverPaths.map(({ path: p })=>(0, _path.join)(distDir, p)); const { type: entryType } = (0, _entrykey.splitEntryKey)(key); // Server HMR applies to App Router entries built with the Turbopack Node.js // runtime: app pages and route handlers (including metadata routes). Edge // routes, Pages Router pages, and middleware/instrumentation are excluded. const usesServerHmr = serverFastRefresh && entryType === 'app' && writtenEndpoint.type !== 'edge'; const serverChunksPrefix = SERVER_HMR_CHUNKS_DIR + _path.sep; const filesToDelete = []; for (const file of serverPaths){ (0, _renderserver.clearModuleContext)(file); const relativePath = (0, _path.relative)(distDir, file); if (// For Pages Router, edge routes, middleware, and any entry not // participating in server HMR: clear the sharedCache in // evalManifest(), Node.js require.cache, and edge runtime module // contexts. force || !usesServerHmr || !relativePath.startsWith(serverChunksPrefix)) { filesToDelete.push(file); } } (0, _requirecache.deleteCache)(filesToDelete); // Reset the fetch patch so patchFetch() can re-wrap on the next request. if (serverPaths.length > 0) { resetFetch(); } // Clear Turbopack's chunk-loading cache so chunks are re-required from disk on // the next request. // // For App Router with server HMR, this is normally skipped as server HMR // manages module updates in-place. However, it *is* required when force is `true` // (like for .env file or tsconfig changes). if ((!usesServerHmr || force) && typeof __next__clear_chunk_cache__ === 'function') { __next__clear_chunk_cache__(); } return true; } const buildingIds = new Set(); const startBuilding = (id, requestUrl, forceRebuild)=>{ if (!forceRebuild && readyIds.has(id)) { return ()=>{}; } if (buildingIds.size === 0) { _store.store.setState({ loading: true, trigger: id, url: requestUrl }, true); } buildingIds.add(id); return function finishBuilding() { if (buildingIds.size === 0) { return; } readyIds.add(id); buildingIds.delete(id); if (buildingIds.size === 0) { hmrEventHappened = false; _store.store.setState({ loading: false }, true); } }; }; let hmrEventHappened = false; // A counter identifying the current version of the compiled output, included // by `"use cache"` in dev cache keys so that cached entries revalidate after // an edit. It advances once per HMR change event (for App Router pages that // is an RSC change, which is what a cached render depends on), independent of // how many clients are connected. It deliberately does not advance on `BUILT` // messages: those are sent per connected client on every compilation, so // advancing there would both churn the hash without an edit and fail to // advance it at all when no client is connected. let hmrHash = 0; // HACK: Defer sending `building` messages. Turbopack emits a compile pass for every // foreground-job cycle, including empty no-op recompiles scheduled by // request/render activity that changed no files. This allows us to prevent // sending them if we quickly get a `built` message after a `building` message. const pendingBuilding = new _deferredemit.DeferredEmit(); const clientsWithoutHtmlRequestId = new Set(); const clientsByHtmlRequestId = new Map(); const cacheStatusesByHtmlRequestId = new Map(); const clientStates = new WeakMap(); function sendToClient(client, message) { const data = typeof message.type === 'number' ? (0, _messages.createBinaryHmrMessageData)(message) : JSON.stringify(message); client.send(data); } let updateInProgress = false; let pendingServerComponentChanges = false; function sendServerComponentChanges() { sendHmr('server-component-changes', { type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.SERVER_COMPONENT_CHANGES }); } // Each announcement makes every client refetch its page, so an update's // changes are announced once, on the update's end. function handleServerComponentChanges() { if (updateInProgress) { pendingServerComponentChanges = true; } else { sendServerComponentChanges(); } } function hasCompilationErrors() { for (const [, issueMap] of currentEntryIssues){ if ([ ...issueMap.values() ].filter((i)=>i.severity !== 'warning').length > 0) { return true; } } return false; } function sendEnqueuedMessages() { if (hasCompilationErrors()) { // During compilation errors we want to delay the HMR events until errors are fixed return; } for (const client of [ ...clientsWithoutHtmlRequestId, ...clientsByHtmlRequestId.values() ]){ const state = clientStates.get(client); if (!state) { continue; } for (const [, issueMap] of state.clientIssues){ if ([ ...issueMap.values() ].filter((i)=>i.severity !== 'warning').length > 0) { // During compilation errors we want to delay the HMR events until errors are fixed return; } } for (const message of state.messages.values()){ sendToClient(client, message); } state.messages.clear(); if (state.turbopackUpdates.length > 0) { sendToClient(client, { type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.TURBOPACK_MESSAGE, data: state.turbopackUpdates }); state.turbopackUpdates.length = 0; } } } const sendEnqueuedMessagesDebounce = (0, _utils1.debounce)(sendEnqueuedMessages, 2); const sendHmr = (id, message)=>{ pendingBuilding.flush(); for (const client of [ ...clientsWithoutHtmlRequestId, ...clientsByHtmlRequestId.values() ]){ var _clientStates_get; (_clientStates_get = clientStates.get(client)) == null ? void 0 : _clientStates_get.messages.set(id, message); } hmrEventHappened = true; sendEnqueuedMessagesDebounce(); }; function sendTurbopackMessage(payload) { // TODO(PACK-2049): For some reason we end up emitting hundreds of issues messages on bigger apps, // a lot of which are duplicates. // They are currently not handled on the client at all, so might as well not send them for now. payload.diagnostics = []; payload.issues = []; pendingBuilding.flush(); for (const client of [ ...clientsWithoutHtmlRequestId, ...clientsByHtmlRequestId.values() ]){ var _clientStates_get; (_clientStates_get = clientStates.get(client)) == null ? void 0 : _clientStates_get.turbopackUpdates.push(payload); } hmrEventHappened = true; sendEnqueuedMessagesDebounce(); } async function subscribeToClientChanges(key, includeIssues, endpoint, createMessage, onError) { if (changeSubscriptions.has(key)) { return; } const { side } = (0, _entrykey.splitEntryKey)(key); const changedPromise = endpoint[`${side}Changed`](includeIssues); changeSubscriptions.set(key, changedPromise); try { const changed = await changedPromise; for await (const change of changed){ (0, _utils2.processIssues)(currentEntryIssues, key, change, false, true); // TODO: Get an actual content hash from Turbopack. const message = await createMessage(change, String(++hmrHash)); if (message) { sendHmr(key, message); } } } catch (e) { changeSubscriptions.delete(key); const payload = await (onError == null ? void 0 : onError(e)); if (payload) { sendHmr(key, payload); } return; } changeSubscriptions.delete(key); } async function unsubscribeFromClientChanges(key) { const subscription = await changeSubscriptions.get(key); if (subscription) { await (subscription.return == null ? void 0 : subscription.return.call(subscription)); changeSubscriptions.delete(key); } currentEntryIssues.delete(key); } async function subscribeToClientHmrEvents(client, id) { const key = (0, _entrykey.getEntryKey)('assets', 'client', id); if (!(0, _turbopackutils.hasEntrypointForKey)(currentEntrypoints, key, assetMapper)) { // maybe throw an error / force the client to reload? return; } const state = clientStates.get(client); if (!state || state.subscriptions.has(id)) { return; } const subscription = project.hmrEvents(id, _swc.HmrTarget.Client); state.subscriptions.set(id, subscription); // The subscription will always emit once, which is the initial // computation. This is not a change, so swallow it. try { await subscription.next(); for await (const data of subscription){ (0, _utils2.processIssues)(state.clientIssues, key, data, false, true); if (data.type !== 'issues') { sendTurbopackMessage(data); } } } catch (e) { // The client might be using an HMR session from a previous server, tell them // to fully reload the page to resolve the issue. We can't use // `hotReloader.send` since that would force every connected client to // reload, only this client is out of date. const reloadMessage = { type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.RELOAD_PAGE, data: `error in HMR event subscription for ${id}: ${e}` }; sendToClient(client, reloadMessage); client.close(); return; } } function unsubscribeFromClientHmrEvents(client, id) { const state = clientStates.get(client); if (!state) { return; } const subscription = state.subscriptions.get(id); subscription == null ? void 0 : subscription.return(); const key = (0, _entrykey.getEntryKey)('assets', 'client', id); state.clientIssues.delete(key); } async function handleEntrypointsSubscription() { for await (const entrypoints of entrypointsSubscription){ if (!currentEntriesHandlingResolve) { currentEntriesHandling = new Promise(// eslint-disable-next-line no-loop-func (resolve)=>currentEntriesHandlingResolve = resolve); } // Always process issues/diagnostics, even if there are no entrypoints yet (0, _turbopackutils.processTopLevelIssues)(currentTopLevelIssues, entrypoints); // Certain crtical issues prevent any entrypoints from being constructed so return early if (!('routes' in entrypoints)) { (0, _printbuilderrors.printBuildErrors)(entrypoints, true); currentEntriesHandlingResolve(); currentEntriesHandlingResolve = undefined; continue; } const routes = entrypoints.routes; const existingRoutes = [ ...currentEntrypoints.app.keys(), ...currentEntrypoints.page.keys() ]; const newRoutes = [ ...routes.keys() ]; const addedRoutes = newRoutes.filter((route)=>!currentEntrypoints.app.has(route) && !currentEntrypoints.page.has(route)); const removedRoutes = existingRoutes.filter((route)=>!routes.has(route)); await (0, _turbopackutils.handleEntrypoints)({ entrypoints: entrypoints, currentEntrypoints, currentEntryIssues, manifestLoader, devRewrites: opts.fsChecker.rewrites, productionRewrites: undefined, logErrors: true, dev: { assetMapper, changeSubscriptions, clients: [ ...clientsWithoutHtmlRequestId, ...clientsByHtmlRequestId.values() ], clientStates, serverFields, hooks: { handleWrittenEndpoint: (id, result, forceDeleteCache)=>{ currentWrittenEntrypoints.set(id, result); return clearRequireCache(id, result, { force: forceDeleteCache }); }, propagateServerField: _setupdevbundler.propagateServerField.bind(null, opts), sendHmr, startBuilding, subscribeToChanges: subscribeToClientChanges, unsubscribeFromChanges: unsubscribeFromClientChanges, unsubscribeFromHmrEvents: unsubscribeFromClientHmrEvents } } }); // Reload matchers when the files have been compiled await (0, _setupdevbundler.propagateServerField)(opts, 'reloadMatchers', undefined); if (addedRoutes.length > 0 || removedRoutes.length > 0) { // When the list of routes changes a new manifest should be fetched for Pages Router. hotReloader.send({ type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.DEV_PAGES_MANIFEST_UPDATE, data: [ { devPagesManifest: true } ] }); } for (const route of addedRoutes){ hotReloader.send({ type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.ADDED_PAGE, data: [ route ] }); } for (const route of removedRoutes){ hotReloader.send({ type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.REMOVED_PAGE, data: [ route ] }); } currentEntriesHandlingResolve(); currentEntriesHandlingResolve = undefined; } } await (0, _promises.mkdir)((0, _path.join)(distDir, 'server'), { recursive: true }); await (0, _promises.mkdir)((0, _path.join)(distDir, 'static', buildId), { recursive: true }); await (0, _promises.writeFile)((0, _path.join)(distDir, 'package.json'), JSON.stringify({ type: 'commonjs' }, null, 2)); const middlewares = [ (0, _middlewareturbopack.getOverlayMiddleware)({ project, projectPath, isSrcDir: opts.isSrcDir }), (0, _middlewareturbopack.getSourceMapMiddleware)(project), (0, _getnexterrorfeedbackmiddleware.getNextErrorFeedbackMiddleware)(opts.telemetry), (0, _getdevoverlayfontmiddleware.getDevOverlayFontMiddleware)(), (0, _devindicatormiddleware.getDisableDevIndicatorMiddleware)(), (0, _restartdevservermiddleware.getRestartDevServerMiddleware)({ telemetry: opts.telemetry, turbopackProject: project }), (0, _devtoolsconfigmiddleware.devToolsConfigMiddleware)({ distDir, sendUpdateSignal: (data)=>{ hotReloader.send({ type: _hotreloadertypes.HMR_MESSAGE_SENT_TO_BROWSER.DEVTOOLS_CONFIG, data }); } }), (0, _attachnodejsdebuggermiddleware.getAttachNodejsDebuggerMiddleware)(), ...nextConfig.experimental.mcpServer ? [ (0, _getmcpmiddleware.getMcpMiddleware)({ projectPath, distDir, nextConfig, pagesDir: opts.pagesDir, appDir: opts.appDir, sendHmrMessage: (message)=>hotReloader.send(message), getActiveConnectionCount: ()=>clientsWithoutHtmlRequestId.size + clientsByHtmlRequestId.size, getDevServerUrl: ()=>process.env.__NEXT_PRIVATE_ORIGIN, getTurbopackProject: ()=>project, compileRoute: async ({ routeSpecifier, path })=>{ // Resolve the caller's input to a concrete route specifier. The // path-mode branch reuses the dev router's own live route table // (opts.fsChecker) — the same one resolve-routes.ts consults on // every incoming HTTP request — so first-match ordering and live // route updates are inherited for free. let page; if (routeSpecifier != null) { page = routeSpecifier; } else if (path != null) { const resolved = (0, _resolvepathtoroute.resolvePathToRoute)(path, { appFiles: opts.fsChecker.appFiles, pageFiles: opts.fsChecker.pageFiles, dynamicRoutes: opts.fsChecker.getDynamicRoutes() }); if ('notFound' in resolved) { const err = Object.defineProperty(new Error(`no route matched for path "${resolved.pathname}"`), "__NEXT_ERROR_CODE", { value: "E1277", enumerable: false, configurable: true }); err.code = 'ENOENT'; throw err; } page = resolved.routeSpecifier; } else { // Tool handler rejects the empty case; defend the boundary. throw Object.defineProperty(new Error('compileRoute: either routeSpecifier or path is required'), "__NEXT_ERROR_CODE", { value: "E1278", enumerable: false, configurable: true }); } // ensurePage uses findPagePathData when no definition is provided, // which calls normalizePagePath("/") → "/index" then findPageFile // looking for "index.tsx" — neither of which matches "page.tsx" in // the app dir. Pass a synthetic definition instead. // // currentEntrypoints.app is keyed by originalName which includes the // trailing /page or /route segment (e.g. "/page" for the root route, // "/blog/[slug]/page" for a dynamic page). Use normalizeAppPath to // strip that suffix and find the entry matching the user-facing route. let extraOptions = undefined; for (const [name] of currentEntrypoints.app){ if ((0, _apppaths.normalizeAppPath)(name) === page) { extraOptions = { // Synthesize a definition so ensurePage bypasses findPagePathData. // Only page and bundlePath are used from the definition: // - page: the originalName used as the route key for currentEntrypoints lookup // - bundlePath: must start with "app/" to set isInsideAppDir=true definition: { page: name, bundlePath: `app${name}`, filename: '' } }; break; } } const ensureOpts = { page, // Compile both server and client bundles, matching what happens // on a real page navigation. Client-only compilation isn't a // meaningful MCP use case so we don't expose it as a knob. clientOnly: false, // Skip wiring HMR subscriptions: there is no client to receive // updates for routes compiled this way, and these subscriptions // are never unsubscribed (see TODOs in handleRouteType). subscribeToChanges: false, ...extraOptions }; // Snapshot the current issue maps before compilation so we can // identify which entry keys were added or updated by this call. // processIssues always creates a new Map() reference, so identity // comparison detects changes even for re-compilations. const snapshotBefore = new Map(currentEntryIssues); // For app-page routes, processIssues is called with throwIssue=true, // meaning it throws ModuleBuildError when there are compile errors—but // it still writes the issues into currentEntryIssues before throwing. // Catch ModuleBuildError so we can read those issues and return them // as structured output rather than propagating the throw. let moduleBuildError; try { await hotReloader.ensurePage(ensureOpts); } catch (err) { if (err instanceof _utils2.ModuleBuildError) { moduleBuildError = err; } else { throw err; } } const rawIssues = []; for (const [key, issueMap] of currentEntryIssues){ if (snapshotBefore.get(key) !== issueMap) { rawIssues.push(...issueMap.values()); } } // If ensurePage threw ModuleBuildError but we found no new issues in // the map (shouldn't happen, but be safe), re-surface the original // error so its message and stack are preserved. if (moduleBuildError && rawIssues.length === 0) { throw moduleBuildError; } return { routeSpecifier: page, issues: (0, _formatcompilationissues.formatCompilationIssues)(rawIssues) }; } }) ] : [] ]; (0, _formaterrors.setStackFrameResolver)(async (request)=>{ return (0, _middlewareturbopack.getOriginalStackFrames)({ project, projectPath, isServer: request.isServer, isEdgeServer: request.isEdgeServer, isAppDirectory: request.isAppDirectory, frames: request.frames }); }); let versionInfoCached; // This fetch, even though not awaited, is not kicked off eagerly because the first `fetch()` in // Node.js adds roughly 20ms main-thread blocking to load the SSL certificate cache // We don't want that blocking time to be in the hot path for the `ready in` logging. // Instead, the fetch is kicked off lazily when the first `getVersionInfoCached()` is called. const getVersionInfoCached = ()=>{ if (!versionInfoCached) { versionInfoCached = (0, _hotreloadersharedutils.getVersionInfo)(); } return versionInfoCached; }; let devtoolsFrontendUrl; const inspectorURLRaw = _inspector.url(); if (inspectorURLRaw !== undefined) { const inspectorURL =