fix(hmr): don't load config twice on server restart

pull/4827/merge
Divyansh Singh 1 month ago
parent d3a15673bd
commit d1a8061eb4

@ -1,9 +1,16 @@
import minimist from 'minimist'
import c from 'picocolors'
import { createLogger, type Logger } from 'vite'
import { build, createServer, serve } from '.'
import {
build,
createServer,
disposeMdItInstance,
resolveConfig,
serve
} from '.'
import { version } from '../../package.json'
import { init } from './init/init'
import { clearCache } from './markdownToVue'
import { bindShortcuts } from './shortcuts'
if (process.env.DEBUG) {
@ -40,30 +47,38 @@ if (!command || command === 'dev') {
argv.optimizeDeps = { force: true }
}
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, async () => {
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
})
}
await server.listen(undefined, isRestart)
logVersion(server.config.logger)
server.printUrls()
bindShortcuts(server, createDevServer)
bindShortcuts(server, restartServer)
}
createDevServer(false).catch((err) => {
createLogger().error(
`${c.red(`failed to start server. error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})
createDevServer(false).catch(
logErrorAndExit.bind(null, `failed to start server. error:`)
)
} else if (command === 'init') {
createLogger().info('', { clear: true })
init(argv.root)
@ -74,21 +89,30 @@ if (!command || command === 'dev') {
onAfterConfigResolve(siteConfig) {
logVersion(siteConfig.logger)
}
}).catch((err) => {
createLogger().error(
`${c.red(`build error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})
}).catch(logErrorAndExit.bind(null, `build error:`))
} else if (command === 'serve' || command === 'preview') {
serve(argv).catch((err) => {
createLogger().error(
`${c.red(`failed to start server. error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})
serve(argv).catch(
logErrorAndExit.bind(null, `failed to start server. error:`)
)
} else {
createLogger().error(c.red(`unknown command "${command}".`))
process.exit(1)
logErrorAndExit(`unknown command "${command}".`)
}
}
function logErrorAndExit(message: string, err?: any): never {
logError(message, err)
process.exit(1)
}
function logError(message: string, err?: any) {
const logger = createLogger()
logger.error(
[
c.red(message),
err && 'message' in err && err.message,
err && 'stack' in err && err.stack
]
.filter(Boolean)
.join('\n')
)
}

@ -18,13 +18,7 @@ import {
SITE_DATA_REQUEST_PATH,
resolveAliases
} from './alias'
import {
isAdditionalConfigFile,
resolvePages,
resolveUserConfig,
type SiteConfig
} from './config'
import { disposeMdItInstance } from './markdown/markdown'
import { isAdditionalConfigFile, resolvePages, type SiteConfig } from './config'
import {
clearCache,
createMarkdownToVueRenderFn,
@ -76,7 +70,7 @@ export async function createVitePressPlugin(
ssr = false,
pageToHashMap?: Record<string, string>,
clientJSMap?: Record<string, string>,
recreateServer?: () => Promise<void>
restartServer?: () => Promise<void>
) {
const {
srcDir,
@ -354,18 +348,6 @@ export async function createVitePressPlugin(
if (this.environment.name !== 'client') return
const relativePath = path.posix.relative(srcDir, file)
if (themeRE.test(relativePath) && type !== 'update') {
siteConfig.themeDir =
type === 'create' ? path.posix.dirname(file) : DEFAULT_THEME_PATH
siteConfig.logger.info(c.green('page reload ') + c.dim(relativePath), {
clear: true,
timestamp: true
})
this.environment.moduleGraph.invalidateAll()
this.environment.hot.send({ type: 'full-reload' })
return []
}
// update pages, dynamicRoutes and rewrites on md file creation / deletion
if (file.endsWith('.md') && type !== 'update') {
await resolvePages(siteConfig)
@ -387,17 +369,19 @@ export async function createVitePressPlugin(
{ clear: true, timestamp: true }
)
try {
await resolveUserConfig(siteConfig.root, 'serve', 'development')
} catch (err: any) {
siteConfig.logger.error(err)
return
}
return restartServer?.()
}
disposeMdItInstance()
clearCache()
await recreateServer?.()
return
if (themeRE.test(relativePath) && type !== 'update') {
siteConfig.themeDir =
type === 'create' ? path.posix.dirname(file) : DEFAULT_THEME_PATH
siteConfig.logger.info(c.green('page reload ') + c.dim(relativePath), {
clear: true,
timestamp: true
})
this.environment.moduleGraph.invalidateAll()
this.environment.hot.send({ type: 'full-reload' })
return []
}
}
}

@ -1,25 +1,24 @@
import { createServer as createViteServer, type ServerOptions } from 'vite'
import { resolveConfig } from './config'
import { resolveConfig, type SiteConfig } from './config'
import { createVitePressPlugin } from './plugin'
export async function createServer(
root: string = process.cwd(),
root: string = process.cwd(), // for backwards compatibility
serverOptions: ServerOptions & { base?: string } = {},
recreateServer?: () => Promise<void>
restartServer?: () => Promise<void>,
config?: SiteConfig // new code should pass config directly
) {
const config = await resolveConfig(root)
config ??= await resolveConfig(root)
if (serverOptions.base) {
config.site.base = serverOptions.base
delete serverOptions.base
}
const { base, ...server } = serverOptions
config.site.base = base ?? config.site.base
return createViteServer({
root: config.srcDir,
base: config.site.base,
cacheDir: config.cacheDir,
plugins: await createVitePressPlugin(config, false, {}, {}, recreateServer),
server: serverOptions,
plugins: await createVitePressPlugin(config, false, {}, {}, restartServer),
server,
customLogger: config.logger,
configFile: config.vite?.configFile
})

@ -1,22 +1,19 @@
import c from 'picocolors'
import type { ViteDevServer } from 'vite'
import { disposeMdItInstance } from './markdown/markdown'
import { clearCache } from './markdownToVue'
type CreateDevServer = () => Promise<void>
import type { Awaitable } from './shared'
export type CLIShortcut = {
key: string
description: string
action(
server: ViteDevServer,
createDevServer: CreateDevServer
): void | Promise<void>
restartServer: () => Promise<void>
): Awaitable<void>
}
export function bindShortcuts(
server: ViteDevServer,
createDevServer: CreateDevServer
restartServer: () => Promise<void>
): void {
if (!server.httpServer || !process.stdin.isTTY || process.env.CI) {
return
@ -59,7 +56,7 @@ export function bindShortcuts(
if (!shortcut) return
actionRunning = true
await shortcut.action(server, createDevServer)
await shortcut.action(server, restartServer)
actionRunning = false
}
@ -77,15 +74,12 @@ const SHORTCUTS: CLIShortcut[] = [
{
key: 'r',
description: 'restart the server',
async action(server, createDevServer) {
async action(server, restartServer) {
server.config.logger.info(c.green(`restarting server...\n`), {
clear: true,
timestamp: true
})
disposeMdItInstance()
clearCache()
await server.close()
await createDevServer()
await restartServer()
}
},
{

Loading…
Cancel
Save