refactor(cli): reorganize command handling and the dev server lifecycle

The file grew a nested if/else chain with inline command bodies, a dev
path that redefined restartServer inside createDevServer on every server
generation, and a module-level restartPromise shared with it.

Read it top to bottom instead: argv parsing, a flat dispatch chain, then
runDev() owning the dev session — its config, its current server and the
restart de-duplication — with the restart sequence spelled out in order.

No behavior change.
fix/dev-restart-resilience
Divyansh Singh 2 weeks ago
parent 110209dd32
commit 392d4cebb4

@ -1,6 +1,6 @@
import minimist from 'minimist'
import c from 'picocolors'
import { createLogger } from 'vite'
import { createLogger, type ViteDevServer } from 'vite'
import {
build,
@ -16,6 +16,7 @@ import { logVersion } from './utils/logVersion'
const argv: any = minimist(process.argv.slice(2))
// minimist keeps `--flag=true` as the string 'true'
Object.keys(argv).forEach((key) => {
if (argv[key] === 'true') {
argv[key] = true
@ -24,16 +25,33 @@ Object.keys(argv).forEach((key) => {
}
})
// vitepress [command] [root]
const command = argv._[0]
const root = argv._[command ? 1 : 0]
if (root) {
argv.root = root
}
let restartPromise: Promise<void> | undefined
if (!command || command === 'dev') {
runDev(root, argv).catch(
logErrorAndExit.bind(null, `failed to start server. error:`)
)
} else if (command === 'init') {
createLogger().info('', { clear: true })
init(argv.root)
} else if (command === 'build') {
build(root, argv).catch(logErrorAndExit.bind(null, `build error:`))
} else if (command === 'serve' || command === 'preview') {
serve(argv).catch(
logErrorAndExit.bind(null, `failed to start server. error:`)
)
} else {
logErrorAndExit(`unknown command "${command}".`)
}
async function runDev(root: string, argv: any) {
if (argv.force) {
// vite moved --force under optimizeDeps
delete argv.force
argv.optimizeDeps = { force: true }
}
@ -41,48 +59,41 @@ if (!command || command === 'dev') {
let config = await resolveConfig(root, argv).catch(
logErrorAndExit.bind(null, `failed to resolve config. error:`)
)
const createDevServer = async (isRestart = true) => {
const server = await createServer(root, argv, restartServer, config)
function restartServer() {
if (!restartPromise) {
restartPromise = (async () => {
try {
config = await resolveConfig(root, argv)
} catch (err: any) {
logError(`failed to resolve config. error:`, err)
return
}
disposeMdItInstance()
clearCache()
await server.close()
await createDevServer()
})().finally(() => {
restartPromise = undefined
})
}
return restartPromise
}
let server: ViteDevServer
let restartPromise: Promise<void> | undefined
async function startServer(isRestart = true) {
server = await createServer(root, argv, restartServer, config)
// isRestart keeps vite from reopening the browser
await server.listen(undefined, isRestart)
logVersion(server.config.logger)
server.printUrls()
bindShortcuts(server, restartServer)
}
createDevServer(false).catch(
logErrorAndExit.bind(null, `failed to start server. error:`)
)
} else if (command === 'init') {
createLogger().info('', { clear: true })
init(argv.root)
} else {
if (command === 'build') {
build(root, argv).catch(logErrorAndExit.bind(null, `build error:`))
} else if (command === 'serve' || command === 'preview') {
serve(argv).catch(
logErrorAndExit.bind(null, `failed to start server. error:`)
)
} else {
logErrorAndExit(`unknown command "${command}".`)
// the config watcher and the r shortcut can both ask at once
function restartServer() {
restartPromise ??= restart().finally(() => {
restartPromise = undefined
})
return restartPromise
}
async function restart() {
try {
config = await resolveConfig(root, argv)
} catch (err: any) {
logError(`failed to resolve config. error:`, err)
return
}
disposeMdItInstance()
clearCache()
await server.close()
await startServer()
}
await startServer(false)
}
function logErrorAndExit(message: string, err?: any): never {

Loading…
Cancel
Save