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 minimist from 'minimist'
import c from 'picocolors' import c from 'picocolors'
import { createLogger, type Logger } from 'vite' import { createLogger, type Logger } from 'vite'
import { build, createServer, serve } from '.' import {
build,
createServer,
disposeMdItInstance,
resolveConfig,
serve
} from '.'
import { version } from '../../package.json' import { version } from '../../package.json'
import { init } from './init/init' import { init } from './init/init'
import { clearCache } from './markdownToVue'
import { bindShortcuts } from './shortcuts' import { bindShortcuts } from './shortcuts'
if (process.env.DEBUG) { if (process.env.DEBUG) {
@ -40,30 +47,38 @@ if (!command || command === 'dev') {
argv.optimizeDeps = { force: true } 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 createDevServer = async (isRestart = true) => {
const server = await createServer(root, argv, async () => { const server = await createServer(root, argv, restartServer, config)
function restartServer() {
if (!restartPromise) { if (!restartPromise) {
restartPromise = (async () => { 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 server.close()
await createDevServer() await createDevServer()
})().finally(() => { })().finally(() => {
restartPromise = undefined restartPromise = undefined
}) })
} }
return restartPromise return restartPromise
}) }
await server.listen(undefined, isRestart) await server.listen(undefined, isRestart)
logVersion(server.config.logger) logVersion(server.config.logger)
server.printUrls() server.printUrls()
bindShortcuts(server, createDevServer) bindShortcuts(server, restartServer)
} }
createDevServer(false).catch((err) => { createDevServer(false).catch(
createLogger().error( logErrorAndExit.bind(null, `failed to start server. error:`)
`${c.red(`failed to start server. error:`)}\n${err.message}\n${err.stack}` )
)
process.exit(1)
})
} else if (command === 'init') { } else if (command === 'init') {
createLogger().info('', { clear: true }) createLogger().info('', { clear: true })
init(argv.root) init(argv.root)
@ -74,21 +89,30 @@ if (!command || command === 'dev') {
onAfterConfigResolve(siteConfig) { onAfterConfigResolve(siteConfig) {
logVersion(siteConfig.logger) logVersion(siteConfig.logger)
} }
}).catch((err) => { }).catch(logErrorAndExit.bind(null, `build error:`))
createLogger().error(
`${c.red(`build error:`)}\n${err.message}\n${err.stack}`
)
process.exit(1)
})
} else if (command === 'serve' || command === 'preview') { } else if (command === 'serve' || command === 'preview') {
serve(argv).catch((err) => { serve(argv).catch(
createLogger().error( logErrorAndExit.bind(null, `failed to start server. error:`)
`${c.red(`failed to start server. error:`)}\n${err.message}\n${err.stack}` )
)
process.exit(1)
})
} else { } else {
createLogger().error(c.red(`unknown command "${command}".`)) logErrorAndExit(`unknown command "${command}".`)
process.exit(1)
} }
} }
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, SITE_DATA_REQUEST_PATH,
resolveAliases resolveAliases
} from './alias' } from './alias'
import { import { isAdditionalConfigFile, resolvePages, type SiteConfig } from './config'
isAdditionalConfigFile,
resolvePages,
resolveUserConfig,
type SiteConfig
} from './config'
import { disposeMdItInstance } from './markdown/markdown'
import { import {
clearCache, clearCache,
createMarkdownToVueRenderFn, createMarkdownToVueRenderFn,
@ -76,7 +70,7 @@ export async function createVitePressPlugin(
ssr = false, ssr = false,
pageToHashMap?: Record<string, string>, pageToHashMap?: Record<string, string>,
clientJSMap?: Record<string, string>, clientJSMap?: Record<string, string>,
recreateServer?: () => Promise<void> restartServer?: () => Promise<void>
) { ) {
const { const {
srcDir, srcDir,
@ -354,18 +348,6 @@ export async function createVitePressPlugin(
if (this.environment.name !== 'client') return if (this.environment.name !== 'client') return
const relativePath = path.posix.relative(srcDir, file) 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 // update pages, dynamicRoutes and rewrites on md file creation / deletion
if (file.endsWith('.md') && type !== 'update') { if (file.endsWith('.md') && type !== 'update') {
await resolvePages(siteConfig) await resolvePages(siteConfig)
@ -387,17 +369,19 @@ export async function createVitePressPlugin(
{ clear: true, timestamp: true } { clear: true, timestamp: true }
) )
try { return restartServer?.()
await resolveUserConfig(siteConfig.root, 'serve', 'development') }
} catch (err: any) {
siteConfig.logger.error(err)
return
}
disposeMdItInstance() if (themeRE.test(relativePath) && type !== 'update') {
clearCache() siteConfig.themeDir =
await recreateServer?.() type === 'create' ? path.posix.dirname(file) : DEFAULT_THEME_PATH
return 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 { createServer as createViteServer, type ServerOptions } from 'vite'
import { resolveConfig } from './config' import { resolveConfig, type SiteConfig } from './config'
import { createVitePressPlugin } from './plugin' import { createVitePressPlugin } from './plugin'
export async function createServer( export async function createServer(
root: string = process.cwd(), root: string = process.cwd(), // for backwards compatibility
serverOptions: ServerOptions & { base?: string } = {}, 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) { const { base, ...server } = serverOptions
config.site.base = serverOptions.base config.site.base = base ?? config.site.base
delete serverOptions.base
}
return createViteServer({ return createViteServer({
root: config.srcDir, root: config.srcDir,
base: config.site.base, base: config.site.base,
cacheDir: config.cacheDir, cacheDir: config.cacheDir,
plugins: await createVitePressPlugin(config, false, {}, {}, recreateServer), plugins: await createVitePressPlugin(config, false, {}, {}, restartServer),
server: serverOptions, server,
customLogger: config.logger, customLogger: config.logger,
configFile: config.vite?.configFile configFile: config.vite?.configFile
}) })

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

Loading…
Cancel
Save