| | import type { ServerResponse, IncomingMessage } from 'http' |
| | import type { Telemetry } from '../../telemetry/storage' |
| | import { RESTART_EXIT_CODE } from '../../server/lib/utils' |
| | import { middlewareResponse } from './middleware-response' |
| | import type { Project } from '../../build/swc/types' |
| | import { invalidateFileSystemCache as invalidateWebpackFileSystemCache } from '../../build/webpack/cache-invalidation' |
| |
|
| | const EVENT_DEV_OVERLAY_RESTART_SERVER = 'DEV_OVERLAY_RESTART_SERVER' |
| |
|
| | interface RestartDevServerMiddlewareConfig { |
| | telemetry: Telemetry |
| | turbopackProject?: Project |
| | webpackCacheDirectories?: Set<string> |
| | } |
| |
|
| | export function getRestartDevServerMiddleware({ |
| | telemetry, |
| | turbopackProject, |
| | webpackCacheDirectories, |
| | }: RestartDevServerMiddlewareConfig) { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const executionId: number = |
| | Math.floor(Math.random() * Number.MAX_SAFE_INTEGER) + 1 |
| |
|
| | async function handleRestartRequest( |
| | req: IncomingMessage, |
| | res: ServerResponse, |
| | searchParams: URLSearchParams |
| | ) { |
| | if (req.method !== 'POST') { |
| | return middlewareResponse.methodNotAllowed(res) |
| | } |
| |
|
| | const shouldInvalidateFileSystemCache = searchParams.has( |
| | 'invalidateFileSystemCache' |
| | ) |
| | if (shouldInvalidateFileSystemCache) { |
| | if (webpackCacheDirectories != null) { |
| | await Promise.all( |
| | Array.from(webpackCacheDirectories).map( |
| | invalidateWebpackFileSystemCache |
| | ) |
| | ) |
| | } |
| | if (turbopackProject != null) { |
| | await turbopackProject.invalidateFileSystemCache() |
| | } |
| | } |
| |
|
| | telemetry.record({ |
| | eventName: EVENT_DEV_OVERLAY_RESTART_SERVER, |
| | payload: { invalidateFileSystemCache: shouldInvalidateFileSystemCache }, |
| | }) |
| |
|
| | |
| | await telemetry.flush() |
| |
|
| | |
| | |
| | setTimeout(() => { |
| | process.exit(RESTART_EXIT_CODE) |
| | }, 0) |
| |
|
| | return middlewareResponse.noContent(res) |
| | } |
| |
|
| | async function handleServerStatus(req: IncomingMessage, res: ServerResponse) { |
| | if (req.method !== 'GET') { |
| | return middlewareResponse.methodNotAllowed(res) |
| | } |
| |
|
| | return middlewareResponse.json(res, { |
| | executionId, |
| | }) |
| | } |
| |
|
| | return async function ( |
| | req: IncomingMessage, |
| | res: ServerResponse, |
| | next: () => void |
| | ): Promise<void> { |
| | const { pathname, searchParams } = new URL(`http://n${req.url}`) |
| |
|
| | switch (pathname) { |
| | case '/__nextjs_restart_dev': |
| | return await handleRestartRequest(req, res, searchParams) |
| | case '/__nextjs_server_status': |
| | return await handleServerStatus(req, res) |
| | default: |
| | return next() |
| | } |
| | } |
| | } |
| |
|