feat(config): add build.externalizeDeps and build.bytecode config options to replace externalizeDepsPlugin and bytecodePlugin

This commit is contained in:
alex8088 2025-10-31 01:03:34 +08:00
parent 3e9ded666c
commit 08be346407
2 changed files with 100 additions and 8 deletions

View File

@ -7,6 +7,8 @@ import {
type UserConfig as ViteConfig, type UserConfig as ViteConfig,
type ConfigEnv, type ConfigEnv,
type PluginOption, type PluginOption,
type Plugin,
type BuildEnvironmentOptions as ViteBuildOptions,
type LogLevel, type LogLevel,
createLogger, createLogger,
mergeConfig, mergeConfig,
@ -28,7 +30,9 @@ import importMetaPlugin from './plugins/importMeta'
import esmShimPlugin from './plugins/esmShim' import esmShimPlugin from './plugins/esmShim'
import modulePathPlugin from './plugins/modulePath' import modulePathPlugin from './plugins/modulePath'
import isolateEntriesPlugin from './plugins/isolateEntries' import isolateEntriesPlugin from './plugins/isolateEntries'
import { isObject, isFilePathESM, deepClone } from './utils' import { type ExternalOptions, externalizeDepsPlugin } from './plugins/externalizeDeps'
import { type BytecodeOptions, bytecodePlugin } from './plugins/bytecode'
import { isObject, isFilePathESM, deepClone, asyncFlatten } from './utils'
export { defineConfig as defineViteConfig } from 'vite' export { defineConfig as defineViteConfig } from 'vite'
@ -46,11 +50,45 @@ interface IsolatedEntriesOption {
isolatedEntries?: boolean isolatedEntries?: boolean
} }
export interface MainViteConfig extends ViteConfig {} interface ExternalizeDepsMixin {
/**
* Options pass on to `externalizeDeps` plugin in electron-vite.
*
* Automatically externalize dependencies.
*
* @default true
*/
externalizeDeps?: boolean | ExternalOptions
}
export interface PreloadViteConfig extends ViteConfig, IsolatedEntriesOption {} interface BytecodeMixin {
/**
* Options pass on to `bytecode` plugin in electron-vite.
* https://electron-vite.org/guide/source-code-protection#bytecodeplugin-options
*
* Compile source code to v8 bytecode.
*/
bytecode?: boolean | BytecodeOptions
}
export interface RendererViteConfig extends ViteConfig, IsolatedEntriesOption {} interface MainBuildOptions extends ViteBuildOptions, ExternalizeDepsMixin, BytecodeMixin {}
interface PreloadBuildOptions extends ViteBuildOptions, ExternalizeDepsMixin, BytecodeMixin {}
interface RendererBuildOptions extends ViteBuildOptions {}
interface BaseViteConfig<T> extends Omit<ViteConfig, 'build'> {
/**
* Build specific options
*/
build?: T
}
export interface MainViteConfig extends BaseViteConfig<MainBuildOptions> {}
export interface PreloadViteConfig extends BaseViteConfig<PreloadBuildOptions>, IsolatedEntriesOption {}
export interface RendererViteConfig extends BaseViteConfig<RendererBuildOptions>, IsolatedEntriesOption {}
export interface UserConfig { export interface UserConfig {
/** /**
@ -157,6 +195,8 @@ export async function resolveConfig(
resetOutDir(mainViteConfig, outDir, 'main') resetOutDir(mainViteConfig, outDir, 'main')
} }
const configDrivenPlugins: PluginOption[] = await resolveConfigDrivenPlugins(mainViteConfig)
const builtInMainPlugins: PluginOption[] = [ const builtInMainPlugins: PluginOption[] = [
electronMainConfigPresetPlugin({ root }), electronMainConfigPresetPlugin({ root }),
electronMainConfigValidatorPlugin(), electronMainConfigValidatorPlugin(),
@ -165,13 +205,20 @@ export async function resolveConfig(
modulePathPlugin( modulePathPlugin(
mergeConfig( mergeConfig(
{ {
plugins: [electronMainConfigPresetPlugin({ root }), assetPlugin(), importMetaPlugin(), esmShimPlugin()] plugins: [
electronMainConfigPresetPlugin({ root }),
assetPlugin(),
importMetaPlugin(),
esmShimPlugin(),
...configDrivenPlugins
]
}, },
mainViteConfig mainViteConfig
) )
), ),
importMetaPlugin(), importMetaPlugin(),
esmShimPlugin() esmShimPlugin(),
...configDrivenPlugins
] ]
mainViteConfig.plugins = builtInMainPlugins.concat(mainViteConfig.plugins || []) mainViteConfig.plugins = builtInMainPlugins.concat(mainViteConfig.plugins || [])
@ -188,12 +235,15 @@ export async function resolveConfig(
resetOutDir(preloadViteConfig, outDir, 'preload') resetOutDir(preloadViteConfig, outDir, 'preload')
} }
const configDrivenPlugins: PluginOption[] = await resolveConfigDrivenPlugins(preloadViteConfig)
const builtInPreloadPlugins: PluginOption[] = [ const builtInPreloadPlugins: PluginOption[] = [
electronPreloadConfigPresetPlugin({ root }), electronPreloadConfigPresetPlugin({ root }),
electronPreloadConfigValidatorPlugin(), electronPreloadConfigValidatorPlugin(),
assetPlugin(), assetPlugin(),
importMetaPlugin(), importMetaPlugin(),
esmShimPlugin() esmShimPlugin(),
...configDrivenPlugins
] ]
if (preloadViteConfig.isolatedEntries) { if (preloadViteConfig.isolatedEntries) {
@ -205,7 +255,8 @@ export async function resolveConfig(
electronPreloadConfigPresetPlugin({ root }), electronPreloadConfigPresetPlugin({ root }),
assetPlugin(), assetPlugin(),
importMetaPlugin(), importMetaPlugin(),
esmShimPlugin() esmShimPlugin(),
...configDrivenPlugins
] ]
}, },
preloadViteConfig preloadViteConfig
@ -278,6 +329,38 @@ function resetOutDir(config: ViteConfig, outDir: string, subOutDir: string): voi
} }
} }
async function resolveConfigDrivenPlugins(config: MainViteConfig | PreloadViteConfig): Promise<PluginOption[]> {
const userPlugins = (await asyncFlatten(config.plugins || [])).filter(Boolean) as Plugin[]
const configDrivenPlugins: PluginOption[] = []
const hasExternalizeDepsPlugin = userPlugins.some(p => p.name === 'vite:externalize-deps')
if (!hasExternalizeDepsPlugin) {
const externalOptions = config.build?.externalizeDeps ?? true
if (externalOptions) {
isOptions<ExternalOptions>(externalOptions)
? configDrivenPlugins.push(externalizeDepsPlugin(externalOptions))
: configDrivenPlugins.push(externalizeDepsPlugin())
}
}
const hasBytecodePlugin = userPlugins.some(p => p.name === 'vite:bytecode')
if (!hasBytecodePlugin) {
const bytecodeOptions = config.build?.bytecode
if (bytecodeOptions) {
isOptions<BytecodeOptions>(bytecodeOptions)
? configDrivenPlugins.push(bytecodePlugin(bytecodeOptions))
: configDrivenPlugins.push(bytecodePlugin())
}
}
return configDrivenPlugins
}
function isOptions<T extends object>(value: boolean | T): value is T {
return typeof value === 'object' && value !== null
}
const CONFIG_FILE_NAME = 'electron.vite.config' const CONFIG_FILE_NAME = 'electron.vite.config'
export async function loadConfigFromFile( export async function loadConfigFromFile(

View File

@ -111,3 +111,12 @@ export function deepClone<T>(value: T): DeepWritable<T> {
} }
return value as DeepWritable<T> return value as DeepWritable<T>
} }
type AsyncFlatten<T extends unknown[]> = T extends (infer U)[] ? Exclude<Awaited<U>, U[]>[] : never
export async function asyncFlatten<T extends unknown[]>(arr: T): Promise<AsyncFlatten<T>> {
do {
arr = (await Promise.all(arr)).flat(Infinity) as any
} while (arr.some((v: any) => v?.then))
return arr as unknown[] as AsyncFlatten<T>
}