From 3fc3e7f793f5c354c5aba06093abef339d6be6bd Mon Sep 17 00:00:00 2001 From: kricsleo Date: Sat, 19 Jul 2025 16:59:53 +0800 Subject: [PATCH 1/3] feat(preload): support bundling multiple preload scripts without requiring `sandbox: false` --- src/build.ts | 26 ++++++++++++++------------ src/config.ts | 50 ++++++++++++++++++++++++++++++-------------------- src/server.ts | 20 ++++++++++++++------ 3 files changed, 58 insertions(+), 38 deletions(-) diff --git a/src/build.ts b/src/build.ts index ec24d10..cff9ce6 100644 --- a/src/build.ts +++ b/src/build.ts @@ -1,5 +1,5 @@ import { build as viteBuild } from 'vite' -import { type InlineConfig, resolveConfig } from './config' +import { type InlineConfig, resolveConfig, type InlineUserConfig } from './config' /** * Bundles the electron app for production. @@ -10,24 +10,26 @@ export async function build(inlineConfig: InlineConfig = {}): Promise { if (config.config) { const mainViteConfig = config.config?.main if (mainViteConfig) { - if (mainViteConfig.build?.watch) { - mainViteConfig.build.watch = null - } - await viteBuild(mainViteConfig) + await _build(mainViteConfig) } const preloadViteConfig = config.config?.preload if (preloadViteConfig) { - if (preloadViteConfig.build?.watch) { - preloadViteConfig.build.watch = null + if (Array.isArray(preloadViteConfig)) { + await Promise.all(preloadViteConfig.map(_build)) + } else { + await _build(preloadViteConfig) } - await viteBuild(preloadViteConfig) } const rendererViteConfig = config.config?.renderer if (rendererViteConfig) { - if (rendererViteConfig.build?.watch) { - rendererViteConfig.build.watch = null - } - await viteBuild(rendererViteConfig) + _build(rendererViteConfig) } } } + +async function _build(config: InlineUserConfig): Promise { + if (config.build?.watch) { + config.build.watch = null + } + await viteBuild(config) +} diff --git a/src/config.ts b/src/config.ts index 69d836a..dcfcb8d 100644 --- a/src/config.ts +++ b/src/config.ts @@ -25,25 +25,27 @@ import { isObject, isFilePathESM } from './utils' export { defineConfig as defineViteConfig } from 'vite' +export type InlineUserConfig = ViteConfig & { configFile?: string | false } + export interface UserConfig { /** * Vite config options for electron main process * * https://vitejs.dev/config/ */ - main?: ViteConfig & { configFile?: string | false } + main?: InlineUserConfig /** * Vite config options for electron renderer process * * https://vitejs.dev/config/ */ - renderer?: ViteConfig & { configFile?: string | false } + renderer?: InlineUserConfig /** * Vite config options for electron preload files * * https://vitejs.dev/config/ */ - preload?: ViteConfig & { configFile?: string | false } + preload?: InlineUserConfig | InlineUserConfig[] } export interface ElectronViteConfig { @@ -64,7 +66,7 @@ export interface ElectronViteConfig { * * https://vitejs.dev/config/ */ - preload?: ViteConfigExport + preload?: ViteConfigExport | ViteConfigExport[] } export type InlineConfig = Omit & { @@ -160,22 +162,30 @@ export async function resolveConfig( } if (loadResult.config.preload) { - const preloadViteConfig: ViteConfig = mergeConfig(loadResult.config.preload, deepClone(config)) - - preloadViteConfig.mode = inlineConfig.mode || preloadViteConfig.mode || defaultMode - - if (outDir) { - resetOutDir(preloadViteConfig, outDir, 'preload') + if (Array.isArray(loadResult.config.preload)) { + loadResult.config.preload = loadResult.config.preload.map(normalizePreloadViteConfig) + } else { + loadResult.config.preload = normalizePreloadViteConfig(loadResult.config.preload) } - mergePlugins(preloadViteConfig, [ - ...electronPreloadVitePlugin({ root }), - assetPlugin(), - importMetaPlugin(), - esmShimPlugin() - ]) - loadResult.config.preload = preloadViteConfig - loadResult.config.preload.configFile = false + function normalizePreloadViteConfig(preloadConfig: InlineUserConfig): InlineUserConfig { + const preloadViteConfig: InlineUserConfig = mergeConfig(preloadConfig, deepClone(config)) + + preloadViteConfig.mode = inlineConfig.mode || preloadViteConfig.mode || defaultMode + preloadViteConfig.configFile = false + + if (outDir) { + resetOutDir(preloadViteConfig, outDir, 'preload') + } + mergePlugins(preloadViteConfig, [ + ...electronPreloadVitePlugin({ root }), + assetPlugin(), + importMetaPlugin(), + esmShimPlugin() + ]) + + return preloadViteConfig + } } if (loadResult.config.renderer) { @@ -299,8 +309,8 @@ export async function loadConfigFromFile( if (config.preload) { const preloadViteConfig = config.preload preloadConfig = await (typeof preloadViteConfig === 'function' ? preloadViteConfig(configEnv) : preloadViteConfig) - if (!isObject(preloadConfig)) { - throw new Error(`preload config must export or return an object`) + if (!isObject(preloadConfig) && (!Array.isArray(preloadConfig) || !preloadConfig.every(isObject))) { + throw new Error(`preload config must export or return an object or an array of objects`) } } else { configRequired.push('preload') diff --git a/src/server.ts b/src/server.ts index 5a72de7..3c236dd 100644 --- a/src/server.ts +++ b/src/server.ts @@ -1,6 +1,5 @@ import type { ChildProcess } from 'node:child_process' import { - type UserConfig as ViteConfig, type ViteDevServer, createServer as viteCreateServer, build as viteBuild, @@ -8,7 +7,7 @@ import { mergeConfig } from 'vite' import colors from 'picocolors' -import { type InlineConfig, resolveConfig } from './config' +import { type InlineConfig, resolveConfig, type InlineUserConfig } from './config' import { resolveHostname } from './utils' import { startElectron } from './electron' @@ -53,7 +52,14 @@ export async function createServer( if (preloadViteConfig && !options.rendererOnly) { logger.info(colors.gray(`\n-----\n`)) + let resolvedCount = 0 const watchHook = (): void => { + resolvedCount++ + if (Array.isArray(preloadViteConfig) && resolvedCount < preloadViteConfig.length) { + // Only resolve when all preload scripts are built + return + } + logger.info(colors.green(`\nrebuild the electron preload files successfully`)) if (server) { @@ -63,7 +69,11 @@ export async function createServer( } } - await doBuild(preloadViteConfig, watchHook, errorHook) + if (Array.isArray(preloadViteConfig)) { + await Promise.all(preloadViteConfig.map(config => doBuild(config, watchHook, errorHook))) + } else { + await doBuild(preloadViteConfig, watchHook, errorHook) + } logger.info(colors.green(`\nbuild the electron preload files successfully`)) } @@ -110,9 +120,7 @@ export async function createServer( } } -type UserConfig = ViteConfig & { configFile?: string | false } - -async function doBuild(config: UserConfig, watchHook: () => void, errorHook: (e: Error) => void): Promise { +async function doBuild(config: InlineUserConfig, watchHook: () => void, errorHook: (e: Error) => void): Promise { return new Promise(resolve => { if (config.build?.watch) { let firstBundle = true From f9a82f6076b1b4d811ba301035b784374ff9feb3 Mon Sep 17 00:00:00 2001 From: kricsleo Date: Fri, 1 Aug 2025 12:07:06 +0800 Subject: [PATCH 2/3] feat: warning for `build.emptyOutDir` when mutiple preload scripts --- src/config.ts | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/config.ts b/src/config.ts index dcfcb8d..8f2342b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -163,17 +163,41 @@ export async function resolveConfig( if (loadResult.config.preload) { if (Array.isArray(loadResult.config.preload)) { - loadResult.config.preload = loadResult.config.preload.map(normalizePreloadViteConfig) + const shouldNotEmptyOutDir = loadResult.config.preload.length > 1 ? true : undefined + loadResult.config.preload = loadResult.config.preload.map(config => + normalizePreloadViteConfig(config, shouldNotEmptyOutDir) + ) } else { loadResult.config.preload = normalizePreloadViteConfig(loadResult.config.preload) } - function normalizePreloadViteConfig(preloadConfig: InlineUserConfig): InlineUserConfig { + function normalizePreloadViteConfig( + preloadConfig: InlineUserConfig, + shouldNotEmptyOutDir?: boolean + ): InlineUserConfig { const preloadViteConfig: InlineUserConfig = mergeConfig(preloadConfig, deepClone(config)) preloadViteConfig.mode = inlineConfig.mode || preloadViteConfig.mode || defaultMode preloadViteConfig.configFile = false + if (shouldNotEmptyOutDir) { + preloadViteConfig.build ||= {} + + if (preloadViteConfig.build.emptyOutDir === true) { + throw new Error( + "The electron vite preload config `build.emptyOutDir` should be set to `false` when multiple preload scripts are used to prevent overwriting each other's output files." + ) + } else if (preloadViteConfig.build.emptyOutDir === undefined) { + createLogger(config.logLevel).info( + colors.gray( + "The electron vite preload config `build.emptyOutDir` will be set to `false` when multiple preload scripts are used to prevent overwriting each other's output files." + ) + ) + } + + preloadViteConfig.build.emptyOutDir = false + } + if (outDir) { resetOutDir(preloadViteConfig, outDir, 'preload') } From 1fbf66dd2b8e3db01d635d3ed11fe5c1a939c8dc Mon Sep 17 00:00:00 2001 From: kricsleo Date: Mon, 4 Aug 2025 10:25:06 +0800 Subject: [PATCH 3/3] chore: remove redundant logs --- src/config.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/config.ts b/src/config.ts index 8f2342b..b63bb70 100644 --- a/src/config.ts +++ b/src/config.ts @@ -187,12 +187,6 @@ export async function resolveConfig( throw new Error( "The electron vite preload config `build.emptyOutDir` should be set to `false` when multiple preload scripts are used to prevent overwriting each other's output files." ) - } else if (preloadViteConfig.build.emptyOutDir === undefined) { - createLogger(config.logLevel).info( - colors.gray( - "The electron vite preload config `build.emptyOutDir` will be set to `false` when multiple preload scripts are used to prevent overwriting each other's output files." - ) - ) } preloadViteConfig.build.emptyOutDir = false