resolveConfig failures were already caught, but a failure inside
startServer() itself (e.g. a theme/plugin markdown.config hook throwing
during the rebuild) rejected after the old server was closed. The
rejection surfaced through hotUpdate into handleHMRUpdate, which turns
it into a client error event no client can receive anymore — the process
then drained and exited without printing anything.
Log the failure, restore the previous config, and bring a server back up
so the watcher keeps running and a config fix triggers a fresh restart.
This also keeps the r shortcut from dying on the same path (its action
awaits restartServer with no rejection handler).
server.close() can wedge on its own too: it waits for the client
environment's in-flight transform requests, and those never settle once
the plugin container and dep optimizer are torn down under them. The
watcher, ws and http server are all closed by then, so the port is free
— bound the wait, warn, and carry on. And because nothing references the
event loop between the two servers, hold a handle for the length of a
restart so a stall anywhere in it can never drain node into a silent
exit(0).