pull/5403/merge
Divyansh Singh 3 days ago committed by GitHub
commit 2eb6480511
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1,6 +1,6 @@
import minimist from 'minimist'
import c from 'picocolors'
import { createLogger } from 'vite'
import { createLogger, type ViteDevServer } from 'vite'
import {
build,
@ -14,8 +14,11 @@ import { clearCache } from './markdownToVue'
import { bindShortcuts } from './shortcuts'
import { logVersion } from './utils/logVersion'
const CLOSE_TIMEOUT = 10000
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 +27,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 +61,98 @@ 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}".`)
// vite's close waits for in-flight transform requests, which never settle
// once the plugin container and dep optimizer are torn down under them. the
// port, the watcher and the ws server are released well before that, so stop
// waiting and let the restart go on
async function closeServer() {
let timer: ReturnType<typeof setTimeout> | undefined
const closed = await Promise.race([
server.close().then(
() => true,
(err: any) => {
logError(`failed to close server. error:`, err)
return true
}
),
new Promise<false>((resolve) => {
timer = setTimeout(resolve, CLOSE_TIMEOUT, false)
})
])
clearTimeout(timer)
if (!closed) {
createLogger().warn(
c.yellow(
`server didn't close in ${CLOSE_TIMEOUT / 1000}s, restarting anyway`
)
)
}
}
// the config watcher and the r shortcut can both ask at once
function restartServer() {
if (!restartPromise) {
// between the two servers nothing references the event loop, so a stall
// anywhere in a restart would drain node into a silent exit(0)
const keepAlive = setInterval(() => {}, 1 << 30)
restartPromise = restart().finally(() => {
clearInterval(keepAlive)
restartPromise = undefined
})
}
return restartPromise
}
async function restart() {
const prevConfig = config
try {
config = await resolveConfig(root, argv)
} catch (err: any) {
logError(`failed to resolve config. error:`, err)
return
}
disposeMdItInstance()
clearCache()
await closeServer()
try {
await startServer()
} catch (err: any) {
logError(`failed to restart server. error:`, err)
// the old server is already closed, so bailing out here leaves the
// session with no server and no watcher — come back up on the last
// known good config so a fix can trigger a fresh restart
config = prevConfig
// the failed attempt may have memoized a half-configured renderer
disposeMdItInstance()
clearCache()
createLogger().warn(c.yellow(`falling back to the previous config`))
await startServer().catch(
logErrorAndExit.bind(null, `failed to restore server. error:`)
)
}
}
// a stray unhandled rejection (from a user config, a theme, or a plugin)
// must not take down a long-lived dev session
process.on('unhandledRejection', (err) => {
logError(`unhandled rejection:`, err)
})
await startServer(false)
}
function logErrorAndExit(message: string, err?: any): never {

Loading…
Cancel
Save