import { addRequestMeta, getRequestMeta } from '../request-meta'; import * as React from 'react'; import fs from 'fs'; import { Worker } from 'next/dist/compiled/jest-worker'; import { join as pathJoin } from 'path'; import { ampValidation } from '../../build/output'; import { PUBLIC_DIR_MIDDLEWARE_CONFLICT } from '../../lib/constants'; import { findPagesDir } from '../../lib/find-pages-dir'; import { PHASE_DEVELOPMENT_SERVER, PAGES_MANIFEST, APP_PATHS_MANIFEST, COMPILER_NAMES, PRERENDER_MANIFEST } from '../../shared/lib/constants'; import Server, { WrappedBuildError } from '../next-server'; import { normalizePagePath } from '../../shared/lib/page-path/normalize-page-path'; import { pathHasPrefix } from '../../shared/lib/router/utils/path-has-prefix'; import { removePathPrefix } from '../../shared/lib/router/utils/remove-path-prefix'; import { Telemetry } from '../../telemetry/storage'; import { setGlobal, trace } from '../../trace'; import { findPageFile } from '../lib/find-page-file'; import { getFormattedNodeOptionsWithoutInspect } from '../lib/utils'; import { withCoalescedInvoke } from '../../lib/coalesced-function'; import { loadDefaultErrorComponents } from '../load-default-error-components'; import { DecodeError, MiddlewareNotFoundError } from '../../shared/lib/utils'; import * as Log from '../../build/output/log'; import isError, { getProperError } from '../../lib/is-error'; import { isMiddlewareFile } from '../../build/utils'; import { formatServerError } from '../../lib/format-server-error'; import { DevRouteMatcherManager } from '../route-matcher-managers/dev-route-matcher-manager'; import { DevPagesRouteMatcherProvider } from '../route-matcher-providers/dev/dev-pages-route-matcher-provider'; import { DevPagesAPIRouteMatcherProvider } from '../route-matcher-providers/dev/dev-pages-api-route-matcher-provider'; import { DevAppPageRouteMatcherProvider } from '../route-matcher-providers/dev/dev-app-page-route-matcher-provider'; import { DevAppRouteRouteMatcherProvider } from '../route-matcher-providers/dev/dev-app-route-route-matcher-provider'; import { NodeManifestLoader } from '../route-matcher-providers/helpers/manifest-loaders/node-manifest-loader'; import { BatchedFileReader } from '../route-matcher-providers/dev/helpers/file-reader/batched-file-reader'; import { DefaultFileReader } from '../route-matcher-providers/dev/helpers/file-reader/default-file-reader'; import { LRUCache } from '../lib/lru-cache'; import { getMiddlewareRouteMatcher } from '../../shared/lib/router/utils/middleware-route-matcher'; import { DetachedPromise } from '../../lib/detached-promise'; import { isPostpone } from '../lib/router-utils/is-postpone'; import { generateInterceptionRoutesRewrites } from '../../lib/generate-interception-routes-rewrites'; import { buildCustomRoute } from '../../lib/build-custom-route'; import { decorateServerError } from '../../shared/lib/error-source'; import { logRequests } from './log-requests'; import { FallbackMode, fallbackModeToFallbackField } from '../../lib/fallback'; import { ensureInstrumentationRegistered, getInstrumentationModule } from '../lib/router-utils/instrumentation-globals.external'; import { getRouteRegex } from '../../shared/lib/router/utils/route-regex'; // Load ReactDevOverlay only when needed let PagesDevOverlayBridgeImpl; const ReactDevOverlay = (props)=>{ if (PagesDevOverlayBridgeImpl === undefined) { PagesDevOverlayBridgeImpl = require('../../next-devtools/userspace/pages/pages-dev-overlay-setup').PagesDevOverlayBridge; } return React.createElement(PagesDevOverlayBridgeImpl, props); }; export default class DevServer extends Server { getStaticPathsWorker() { const worker = new Worker(require.resolve('./static-paths-worker'), { maxRetries: 1, // For dev server, it's not necessary to spin up too many workers as long as you are not doing a load test. // This helps reusing the memory a lot. numWorkers: 1, enableWorkerThreads: this.nextConfig.experimental.workerThreads, forkOptions: { env: { ...process.env, // discard --inspect/--inspect-brk flags from process.env.NODE_OPTIONS. Otherwise multiple Node.js debuggers // would be started if user launch Next.js in debugging mode. The number of debuggers is linked to // the number of workers Next.js tries to launch. The only worker users are interested in debugging // is the main Next.js one NODE_OPTIONS: getFormattedNodeOptionsWithoutInspect() } } }); worker.getStdout().pipe(process.stdout); worker.getStderr().pipe(process.stderr); return worker; } constructor(options){ var _this_nextConfig_experimental_amp, _this_nextConfig_experimental; try { // Increase the number of stack frames on the server Error.stackTraceLimit = 50; } catch {} super({ ...options, dev: true }), /** * The promise that resolves when the server is ready. When this is unset * the server is ready. */ this.ready = new DetachedPromise(); this.bundlerService = options.bundlerService; this.startServerSpan = options.startServerSpan ?? trace('start-next-dev-server'); this.renderOpts.dev = true; this.renderOpts.ErrorDebug = ReactDevOverlay; this.staticPathsCache = new LRUCache(// 5MB 5 * 1024 * 1024, function length(value) { var _JSON_stringify; // Ensure minimum size of 1 for LRU eviction to work correctly return ((_JSON_stringify = JSON.stringify(value.staticPaths)) == null ? void 0 : _JSON_stringify.length) || 1; }); this.renderOpts.ampSkipValidation = ((_this_nextConfig_experimental = this.nextConfig.experimental) == null ? void 0 : (_this_nextConfig_experimental_amp = _this_nextConfig_experimental.amp) == null ? void 0 : _this_nextConfig_experimental_amp.skipValidation) ?? false; this.renderOpts.ampValidator = async (html, pathname)=>{ var _this_nextConfig_experimental_amp, _this_nextConfig_experimental; const { getAmpValidatorInstance, getBundledAmpValidatorFilepath } = require('../../export/helpers/get-amp-html-validator'); const validatorPath = ((_this_nextConfig_experimental = this.nextConfig.experimental) == null ? void 0 : (_this_nextConfig_experimental_amp = _this_nextConfig_experimental.amp) == null ? void 0 : _this_nextConfig_experimental_amp.validator) || getBundledAmpValidatorFilepath(); const validator = await getAmpValidatorInstance(validatorPath); const result = validator.validateString(html); ampValidation(pathname, result.errors.filter((error)=>{ if (error.severity === 'ERROR') { // Unclear yet if these actually prevent the page from being indexed by the AMP cache. // These are coming from React so all we can do is ignore them for now. // // https://github.com/ampproject/amphtml/issues/40279 if (error.code === 'DISALLOWED_ATTR' && error.params[0] === 'blocking' && error.params[1] === 'link') { return false; } //