import type { ChildProcess } from 'node:child_process' import { type UserConfig as ViteConfig, type ViteDevServer, createServer as ViteCreateServer, build as viteBuild, createLogger, mergeConfig } from 'vite' import colors from 'picocolors' import { type InlineConfig, resolveConfig } from './config' import { resolveHostname } from './utils' import { startElectron } from './electron' export async function createServer( inlineConfig: InlineConfig = {}, options: { rendererOnly?: boolean } ): Promise { process.env.NODE_ENV_ELECTRON_VITE = 'development' const config = await resolveConfig(inlineConfig, 'serve', 'development') if (config.config) { const logger = createLogger(inlineConfig.logLevel) let server: ViteDevServer | undefined let ps: ChildProcess | undefined const mainViteConfig = config.config?.main if (mainViteConfig && !options.rendererOnly) { const watchHook = (): void => { logger.info(colors.green(`\nrebuild the electron main process successfully`)) if (ps) { logger.info(colors.cyan(`\n waiting for electron to exit...`)) ps.removeAllListeners() ps.kill() ps = startElectron(inlineConfig.root) logger.info(colors.green(`\nrestart electron app...`)) } } await doBuild(mainViteConfig, watchHook) logger.info(colors.green(`\nbuild the electron main process successfully`)) } const preloadViteConfig = config.config?.preload if (preloadViteConfig && !options.rendererOnly) { logger.info(colors.gray(`\n-----\n`)) const watchHook = (): void => { logger.info(colors.green(`\nrebuild the electron preload files successfully`)) if (server) { logger.info(colors.cyan(`\n trigger renderer reload`)) server.ws.send({ type: 'full-reload' }) } } await doBuild(preloadViteConfig, watchHook) logger.info(colors.green(`\nbuild the electron preload files successfully`)) } if (options.rendererOnly) { logger.warn( `\n${colors.yellow(colors.bold('warn'))}:${colors.yellow( ' you have skipped the main process and preload scripts building' )}` ) } const rendererViteConfig = config.config?.renderer if (rendererViteConfig) { logger.info(colors.gray(`\n-----\n`)) server = await ViteCreateServer(rendererViteConfig) if (!server.httpServer) { throw new Error('HTTP server not available') } await server.listen() const conf = server.config.server const protocol = conf.https ? 'https:' : 'http:' const host = resolveHostname(conf.host) const port = conf.port process.env.ELECTRON_RENDERER_URL = `${protocol}//${host}:${port}` const slogger = server.config.logger slogger.info(colors.green(`dev server running for the electron renderer process at:\n`), { clear: !slogger.hasWarned && !options.rendererOnly }) server.printUrls() } ps = startElectron(inlineConfig.root) logger.info(colors.green(`\nstart electron app...\n`)) } } type UserConfig = ViteConfig & { configFile?: string | false } async function doBuild(config: UserConfig, watchHook: () => void): Promise { return new Promise(resolve => { if (config.build?.watch) { let firstBundle = true const closeBundle = (): void => { if (firstBundle) { firstBundle = false resolve() } else { watchHook() } } config = mergeConfig(config, { plugins: [ { name: 'vite:electron-watcher', closeBundle } ] }) } viteBuild(config).then(() => { if (!config.build?.watch) { resolve() } }) }) }