Compare commits

..

9 Commits

10 changed files with 141 additions and 148 deletions

View File

@ -1,63 +1,85 @@
### v6.0.0-beta.7 (_2026-10-08_) ### v6.0.0 (_2026-10-15_)
- fix(bytecode): unable to obtain the bytecode build session in Node.js 24
### v6.0.0-beta.6 (_2026-10-07_)
- refactor!: invoke the bytecode compiler only once to compile all code
- refactor: use pipe stdio for spawn Electron bytecode compliler and append stderr error
- chore: improve jsdoc for bytecode options (#898)
### v6.0.0-beta.5 (_2026-09-29_)
- feat(bytecode): support RegExp for chunkAlias option ([#885](https://github.com/alex8088/electron-vite/issues/885)) - feat(bytecode): support RegExp for chunkAlias option ([#885](https://github.com/alex8088/electron-vite/issues/885))
- refactor: share and normalize build output resolution
- refactor: inline bytecode build plugin name
- refactor!: invoke the bytecode compiler only once to compile all code
- refactor: use pipe stdio for spawn Electron bytecode compliler and append stderr error
- refactor: use rolldown instead of esbuild to bundle config file
- refactor: compile bytecode using the Electron main process or renderer process rather then via the `ELECTRON_RUN_AS_NODE`
- refactor!: simplify resolve config and isolate user config for sub-builds
- refactor: `?modulePath` sub-build output strategy
- perf(swcPlugin): skip redundant minification when using Oxc ([#922](https://github.com/alex8088/electron-vite/issues/922))
- perf: skip Babel loading in development and builds without bytecode
- perf: short-circuit bytecode detection in builds
- perf: setup rollupOption compatibility via config factory
- perf: build compatibility target for Electron 42, 43, 44
- fix(asset): use consistent file paths for asset cache lookups
- fix(bytecode): unable to obtain the bytecode build session in Node.js 24 ([#928](https://github.com/alex8088/electron-vite/issues/928))
- fix(dev): exit non-zero when Electron is killed by a signal ([#918](https://github.com/alex8088/electron-vite/issues/918)) - fix(dev): exit non-zero when Electron is killed by a signal ([#918](https://github.com/alex8088/electron-vite/issues/918))
- fix(dev): forward termination signals to Electron child ([#900](https://github.com/alex8088/electron-vite/issues/900)) - fix(dev): forward termination signals to Electron child ([#900](https://github.com/alex8088/electron-vite/issues/900))
- fix(dev): improve Electron process signal handling - fix(dev): improve Electron process signal handling
- fix(bytecode): set the regular expression's `lastIndex` to 0 to perform a global match for chunkAlias option - fix(bytecode): set the regular expression's `lastIndex` to 0 to perform a global match for chunkAlias option
### v6.0.0-beta.4 (_2026-09-28_)
- fix(esmShim)!: use `this.parse` to find the last static import ([#906](https://github.com/alex8088/electron-vite/issues/906)) - fix(esmShim)!: use `this.parse` to find the last static import ([#906](https://github.com/alex8088/electron-vite/issues/906))
### v6.0.0-beta.3 (_2026-09-27_)
- fix(deps)!: downgraded @babel/* to v7 due to Node requirements - fix(deps)!: downgraded @babel/* to v7 due to Node requirements
### v6.0.0-beta.2 (_2026-09-27_)
- refactor: use rolldown instead of esbuild to bundle config file
- refactor: compile bytecode using the Electron main process or renderer process rather then via the `ELECTRON_RUN_AS_NODE`
- perf: setup rollupOption compatibility via config factory
- perf: build compatibility target for Electron 42, 43, 44
- fix: remove useless preset config - fix: remove useless preset config
- fix(swcPlugin): also disable oxc on Vite 8 ([#920](https://github.com/alex8088/electron-vite/issues/920)) - fix(swcPlugin): also disable oxc on Vite 8 ([#920](https://github.com/alex8088/electron-vite/issues/920))
- fix: clone config without plugins [#902](https://github.com/alex8088/electron-vite/issues/902) - fix: clone config without plugins [#902](https://github.com/alex8088/electron-vite/issues/902)
- fix(deps)!: update magic-string to v1 - fix(deps)!: update magic-string to v1
- fix(deps)!: update @babel/* to v8 - fix(deps)!: update @babel/* to v8
- chore(deps): update all non-major dependencies
- chore(deps): update lint-staged to v17
### v6.0.0-beta.1 (_2026-04-12_)
- refactor!: simplify resolve config and isolate user config for sub-builds
- fix!: compatible with rollupOptions and rolldownOptions - fix!: compatible with rollupOptions and rolldownOptions
- fix: chunk filename is wrong in ES mode - fix: chunk filename is wrong in ES mode
### v6.0.0-beta.0 (_2026-04-09_)
- refactor: `?modulePath` sub-build output strategy
- fix(asset): isolate asset caches per environment - fix(asset): isolate asset caches per environment
- fix: use the environment api in plugins - fix: use the environment api in plugins
- fix: skip TTY terminal manipulations in CI environments - fix: skip TTY terminal manipulations in CI environments
- fix(deps)!: update vite to v8 ([#894](https://github.com/alex8088/electron-vite/issues/894)) - fix(deps)!: update vite to v8 ([#894](https://github.com/alex8088/electron-vite/issues/894))
- fix: Typescript compiler option 'outDir' must be located inside Rollup 'dir' option - fix: Typescript compiler option 'outDir' must be located inside Rollup 'dir' option
- fix(isolateEntries): handle non-TTY stdout in build reporter (#887) - fix(isolateEntries): handle non-TTY stdout in build reporter (#887)
- chore: simplify bytecode compiler initialization
- chore: improve jsdoc for bytecode options ([#898](https://github.com/alex8088/electron-vite/issues/898))
- chore(deps): update all non-major dependencies
- chore(deps): update lint-staged to v17
- chore(deps): update cac to v7 - chore(deps): update cac to v7
- chore(deps): update globals to v17 - chore(deps): update globals to v17
- chore(deps): update eslint and @eslint/js to v10 - chore(deps): update eslint and @eslint/js to v10
- chore(deps): update all non-major dependencies - chore(deps): update all non-major dependencies
### v6.0.0-beta.8 (_2026-10-11_)
See [v6.0.0-beta.8 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.8/CHANGELOG.md)
### v6.0.0-beta.7 (_2026-10-08_)
See [v6.0.0-beta.7 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.7/CHANGELOG.md)
### v6.0.0-beta.6 (_2026-10-07_)
See [v6.0.0-beta.6 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.6/CHANGELOG.md)
### v6.0.0-beta.5 (_2026-09-29_)
See [v6.0.0-beta.5 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.5/CHANGELOG.md)
### v6.0.0-beta.4 (_2026-09-28_)
See [v6.0.0-beta.4 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.4/CHANGELOG.md)
### v6.0.0-beta.3 (_2026-09-27_)
See [v6.0.0-beta.3 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.3/CHANGELOG.md)
### v6.0.0-beta.2 (_2026-09-27_)
See [v6.0.0-beta.2 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.2/CHANGELOG.md)
### v6.0.0-beta.1 (_2026-04-12_)
See [v6.0.0-beta.1 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.1/CHANGELOG.md)
### v6.0.0-beta.0 (_2026-04-09_)
See [v6.0.0-beta.0 changelog](https://github.com/alex8088/electron-vite/blob/v6.0.0-beta.0/CHANGELOG.md)
### v5.0.0 (_2025-12-07_) ### v5.0.0 (_2025-12-07_)
- feat(config): add `build.externalizeDeps` and `build.bytecode` config options to replace `externalizeDepsPlugin` and `bytecodePlugin` - feat(config): add `build.externalizeDeps` and `build.bytecode` config options to replace `externalizeDepsPlugin` and `bytecodePlugin`

View File

@ -1,6 +1,6 @@
{ {
"name": "electron-vite", "name": "electron-vite",
"version": "6.0.0-beta.7", "version": "6.0.0",
"description": "Electron build tooling based on Vite", "description": "Electron build tooling based on Vite",
"type": "module", "type": "module",
"main": "./dist/index.js", "main": "./dist/index.js",

View File

@ -1,10 +1,11 @@
import { build as viteBuild, mergeConfig } from 'vite' import { build as viteBuild, mergeConfig } from 'vite'
import { type InlineConfig, type MainViteConfig, type PreloadViteConfig, resolveConfig } from './config' import { type InlineConfig, type MainViteConfig, type PreloadViteConfig, resolveConfig } from './config'
import { BytecodeBuild, bytecodeBuildPluginName } from './bytecode/build' import { BytecodeCompiler } from './bytecodeCompiler'
import { asyncFlatten } from './utils' import { asyncFlatten } from './utils'
async function useBytecode(config?: MainViteConfig | PreloadViteConfig): Promise<boolean> { async function usesBytecode(config?: MainViteConfig | PreloadViteConfig): Promise<boolean> {
if (!config) return false if (!config) return false
if (config.build?.bytecode) return true
const plugins = await asyncFlatten(config.plugins || []) const plugins = await asyncFlatten(config.plugins || [])
return plugins.some(plugin => plugin && typeof plugin === 'object' && plugin.name === 'vite:bytecode') return plugins.some(plugin => plugin && typeof plugin === 'object' && plugin.name === 'vite:bytecode')
} }
@ -15,10 +16,10 @@ async function useBytecode(config?: MainViteConfig | PreloadViteConfig): Promise
export async function build(inlineConfig: InlineConfig = {}): Promise<void> { export async function build(inlineConfig: InlineConfig = {}): Promise<void> {
process.env.NODE_ENV_ELECTRON_VITE = 'production' process.env.NODE_ENV_ELECTRON_VITE = 'production'
const bytecodeBuild = new BytecodeBuild() const bytecodeCompiler = new BytecodeCompiler()
const config = await resolveConfig( const config = await resolveConfig(
mergeConfig(inlineConfig, { mergeConfig(inlineConfig, {
plugins: [{ name: bytecodeBuildPluginName, api: { build: bytecodeBuild } }] plugins: [{ name: 'vite:electron-bytecode-build', api: { compiler: bytecodeCompiler } }]
}), }),
'build', 'build',
'production' 'production'
@ -28,9 +29,7 @@ export async function build(inlineConfig: InlineConfig = {}): Promise<void> {
return return
} }
const mainBytecode = await useBytecode(config.config.main) const hasBytecode = (await usesBytecode(config.config.main)) || (await usesBytecode(config.config.preload))
const preloadBytecode = await useBytecode(config.config.preload)
const hasBytecode = mainBytecode || preloadBytecode
const buildTargets = async (): Promise<void> => { const buildTargets = async (): Promise<void> => {
// Build targets in order: main -> preload -> renderer // Build targets in order: main -> preload -> renderer
@ -49,9 +48,9 @@ export async function build(inlineConfig: InlineConfig = {}): Promise<void> {
if (!hasBytecode) return buildTargets() if (!hasBytecode) return buildTargets()
try { try {
await bytecodeBuild.start() await bytecodeCompiler.start()
await buildTargets() await buildTargets()
} finally { } finally {
await bytecodeBuild.stop() await bytecodeCompiler.stop()
} }
} }

View File

@ -1,25 +0,0 @@
import { type Plugin } from 'vite'
import { BytecodeCompiler, type BytecodeCompileResult, type BytecodeTarget } from './compiler'
export const bytecodeBuildPluginName = 'vite:electron-bytecode-build'
export class BytecodeBuild {
private readonly compiler = new BytecodeCompiler()
start(): Promise<void> {
return this.compiler.start()
}
compile(target: BytecodeTarget, code: string): Promise<BytecodeCompileResult> {
return this.compiler.compile(target, code)
}
stop(): Promise<void> {
return this.compiler.stop()
}
}
export function getBytecodeBuild(plugins: readonly Plugin[]): BytecodeBuild | undefined {
const plugin = plugins.find(plugin => plugin.name === bytecodeBuildPluginName)
return (plugin?.api as { build?: BytecodeBuild } | undefined)?.build
}

View File

@ -1,7 +1,7 @@
import { type ChildProcess, spawn } from 'node:child_process' import { type ChildProcess, spawn } from 'node:child_process'
import path from 'node:path' import path from 'node:path'
import { createRequire } from 'node:module' import { createRequire } from 'node:module'
import { getElectronPath } from '../electron' import { getElectronPath } from './electron'
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url)
const RPC_TIMEOUT = 30_000 const RPC_TIMEOUT = 30_000

View File

@ -67,7 +67,7 @@ export default function assetPlugin(): Plugin {
referenceId = `__VITE_NODE_PUBLIC_ASSET__${hash}__` referenceId = `__VITE_NODE_PUBLIC_ASSET__${hash}__`
} else { } else {
const cache = assetCache.get(this.environment)! const cache = assetCache.get(this.environment)!
const cached = cache.get(id) const cached = cache.get(file)
if (cached) { if (cached) {
referenceId = cached referenceId = cached
} else { } else {

View File

@ -1,22 +1,30 @@
import path from 'node:path' import path from 'node:path'
import { randomBytes } from 'node:crypto' import { randomBytes } from 'node:crypto'
import { createRequire } from 'node:module'
import colors from 'picocolors' import colors from 'picocolors'
import { type Plugin, type LibraryOptions, type Rolldown, normalizePath } from 'vite' import { type Plugin, type Rolldown, normalizePath } from 'vite'
import * as babel from '@babel/core' import type * as Babel from '@babel/core'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { toRelativePath } from '../utils' import { toRelativePath, resolveBuildOutputs } from '../utils'
import { type BytecodeBuild, getBytecodeBuild } from '../bytecode/build' import type { BytecodeCompiler, BytecodeTarget } from '../bytecodeCompiler'
import { type BytecodeTarget } from '../bytecode/compiler'
// Inspired by https://github.com/bytenode/bytenode // Inspired by https://github.com/bytenode/bytenode
const require = createRequire(import.meta.url)
let babel: typeof Babel | undefined
function getBytecodeCompiler(plugins: readonly Plugin[]): BytecodeCompiler | undefined {
const plugin = plugins.find(plugin => plugin.name === 'vite:electron-bytecode-build')
return (plugin?.api as { compiler?: BytecodeCompiler } | undefined)?.compiler
}
// Versioned envelope: magic/version (8), UTF-16 source length (4), module ID (16), V8 cache. // Versioned envelope: magic/version (8), UTF-16 source length (4), module ID (16), V8 cache.
// Keep our metadata separate from the private V8 cache header. // Keep our metadata separate from the private V8 cache header.
async function compileToBytecode(build: BytecodeBuild, target: BytecodeTarget, code: string): Promise<Buffer> { async function compileToBytecode(compiler: BytecodeCompiler, target: BytecodeTarget, code: string): Promise<Buffer> {
const id = randomBytes(16) const id = randomBytes(16)
// Reserve enough source space for an untruncated, per-artifact placeholder identity. // Reserve enough source space for an untruncated, per-artifact placeholder identity.
const source = code + '\n/*' + id.toString('hex') + '*/' const source = code + '\n/*' + id.toString('hex') + '*/'
const result = await build.compile(target, source) const result = await compiler.compile(target, source)
const header = Buffer.alloc(28) const header = Buffer.alloc(28)
header.write('EVBC0001', 0, 'ascii') header.write('EVBC0001', 0, 'ascii')
header.writeUInt32LE(result.sourceLength, 8) header.writeUInt32LE(result.sourceLength, 8)
@ -93,14 +101,14 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
return _chunkAlias.length === 0 || _chunkAlias.some(alias => alias === chunkName) return _chunkAlias.length === 0 || _chunkAlias.some(alias => alias === chunkName)
} }
const plugins: babel.PluginItem[] = [] const plugins: Babel.PluginItem[] = []
if (transformArrowFunctions) { if (transformArrowFunctions) {
plugins.push('@babel/plugin-transform-arrow-functions') plugins.push('@babel/plugin-transform-arrow-functions')
} }
if (protectedStrings.length > 0) { if (protectedStrings.length > 0) {
plugins.push([protectStringsPlugin as babel.PluginTarget, { protectedStrings: new Set(protectedStrings) }]) plugins.push([protectStringsPlugin as Babel.PluginTarget, { protectedStrings: new Set(protectedStrings) }])
} }
const shouldTransformBytecodeChunk = plugins.length !== 0 const shouldTransformBytecodeChunk = plugins.length !== 0
@ -109,6 +117,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
code: string, code: string,
sourceMaps: boolean = false sourceMaps: boolean = false
): { code: string; map?: Rolldown.SourceMapInput } | null => { ): { code: string; map?: Rolldown.SourceMapInput } | null => {
babel ??= require('@babel/core') as typeof Babel
const re = babel.transformSync(code, { plugins, sourceMaps }) const re = babel.transformSync(code, { plugins, sourceMaps })
return re ? { code: re.code || '', map: re.map as Rolldown.SourceMapInput } : null return re ? { code: re.code || '', map: re.map as Rolldown.SourceMapInput } : null
} }
@ -118,14 +127,14 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
let supported = false let supported = false
let isPreload = false let isPreload = false
let bytecodeBuild: BytecodeBuild | undefined let bytecodeCompiler: BytecodeCompiler | undefined
return { return {
name: 'vite:bytecode', name: 'vite:bytecode',
apply: 'build', apply: 'build',
enforce: 'post', enforce: 'post',
configResolved(config): void { configResolved(config): void {
bytecodeBuild = getBytecodeBuild(config.plugins) bytecodeCompiler = getBytecodeCompiler(config.plugins)
if (supported) { if (supported) {
return return
} }
@ -136,10 +145,9 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
return return
} }
const build = config.build const build = config.build
const resolvedOutputs = resolveBuildOutputs(build.rolldownOptions.output, build.lib) const outputs = resolveBuildOutputs(build.rolldownOptions.output, build.lib)
if (resolvedOutputs) {
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
const output = outputs[0] const output = outputs[0]
if (output) {
if (output.format === 'es') { if (output.format === 'es') {
config.logger.warn( config.logger.warn(
colors.yellow( colors.yellow(
@ -184,8 +192,8 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
const bundles = Object.keys(output) const bundles = Object.keys(output)
if (!bytecodeBuild) { if (!bytecodeCompiler) {
throw new Error('Bytecode compilation requires an electron-vite build session') throw new Error('Bytecode compilation requires an electron-vite build')
} }
for (const name of bundles) { for (const name of bundles) {
const chunk = output[name] const chunk = output[name]
@ -207,7 +215,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
} }
} }
if (bytecodeChunks.includes(name)) { if (bytecodeChunks.includes(name)) {
const bytecodeBuffer = await compileToBytecode(bytecodeBuild, isPreload ? 'preload' : 'main', _code) const bytecodeBuffer = await compileToBytecode(bytecodeCompiler, isPreload ? 'preload' : 'main', _code)
this.emitFile({ this.emitFile({
type: 'asset', type: 'asset',
fileName: name + 'c', fileName: name + 'c',
@ -276,25 +284,14 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null {
} }
} }
function resolveBuildOutputs( interface ProtectStringsPluginState extends Babel.PluginPass {
outputs: Rolldown.OutputOptions | Rolldown.OutputOptions[] | undefined,
libOptions: LibraryOptions | false
): Rolldown.OutputOptions | Rolldown.OutputOptions[] | undefined {
if (libOptions && !Array.isArray(outputs)) {
const libFormats = libOptions.formats || []
return libFormats.map(format => ({ ...outputs, format }))
}
return outputs
}
interface ProtectStringsPluginState extends babel.PluginPass {
opts: { protectedStrings: Set<string> } opts: { protectedStrings: Set<string> }
} }
function protectStringsPlugin(api: typeof babel & babel.ConfigAPI): babel.PluginObj<ProtectStringsPluginState> { function protectStringsPlugin(api: typeof Babel & Babel.ConfigAPI): Babel.PluginObj<ProtectStringsPluginState> {
const { types: t } = api const { types: t } = api
function createFromCharCodeFunction(value: string): babel.types.CallExpression { function createFromCharCodeFunction(value: string): Babel.types.CallExpression {
const charCodes = Array.from(value).map(s => s.charCodeAt(0)) const charCodes = Array.from(value).map(s => s.charCodeAt(0))
const charCodeLiterals = charCodes.map(code => t.numericLiteral(code)) const charCodeLiterals = charCodes.map(code => t.numericLiteral(code))

View File

@ -2,9 +2,9 @@ import path from 'node:path'
import fs from 'node:fs' import fs from 'node:fs'
import { builtinModules } from 'node:module' import { builtinModules } from 'node:module'
import colors from 'picocolors' import colors from 'picocolors'
import { type Plugin, type LibraryOptions, type Rolldown, type UserConfig, mergeConfig, normalizePath } from 'vite' import { type Plugin, type UserConfig, mergeConfig, normalizePath } from 'vite'
import { getElectronNodeTarget, getElectronChromeTarget, supportESM } from '../electron' import { getElectronNodeTarget, getElectronChromeTarget, supportESM } from '../electron'
import { loadPackageData } from '../utils' import { loadPackageData, resolveBuildOutputs } from '../utils'
export interface ElectronPluginOptions { export interface ElectronPluginOptions {
root?: string root?: string
@ -38,17 +38,6 @@ function processEnvDefine(): Record<string, string> {
} }
} }
function resolveBuildOutputs(
outputs: Rolldown.OutputOptions | Rolldown.OutputOptions[] | undefined,
libOptions: LibraryOptions | false
): Rolldown.OutputOptions | Rolldown.OutputOptions[] | undefined {
if (libOptions && !Array.isArray(outputs)) {
const libFormats = libOptions.formats || []
return libFormats.map(format => ({ ...outputs, format }))
}
return outputs
}
export function electronMainConfigPresetPlugin(options?: ElectronPluginOptions): Plugin { export function electronMainConfigPresetPlugin(options?: ElectronPluginOptions): Plugin {
return { return {
name: 'vite:electron-main-config-preset', name: 'vite:electron-main-config-preset',
@ -148,16 +137,15 @@ export function electronMainConfigValidatorPlugin(): Plugin {
) )
} }
const resolvedOutputs = resolveBuildOutputs(rolldownOptions.output, libOptions) const outputs = resolveBuildOutputs(rolldownOptions.output, libOptions)
if (resolvedOutputs) { if (outputs.length > 0) {
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
if (outputs.length > 1) { if (outputs.length > 1) {
throw new Error('The electron vite main config does not support multiple outputs.') throw new Error('The electron vite main config does not support multiple outputs.')
} else { } else {
const outpout = outputs[0] const output = outputs[0]
if (['es', 'cjs'].includes(outpout.format || '')) { if (['es', 'cjs'].includes(output.format || '')) {
if (outpout.format === 'es' && !supportESM()) { if (output.format === 'es' && !supportESM()) {
throw new Error( throw new Error(
'The electron vite main config output format does not support "es", ' + 'The electron vite main config output format does not support "es", ' +
'you can upgrade electron to the latest version or switch to "cjs" format.' 'you can upgrade electron to the latest version or switch to "cjs" format.'
@ -232,12 +220,9 @@ export function electronPreloadConfigPresetPlugin(options?: ElectronPluginOption
const buildConfig = mergeConfig(defaultConfig.build, build) const buildConfig = mergeConfig(defaultConfig.build, build)
config.build = buildConfig config.build = buildConfig
const resolvedOutputs = resolveBuildOutputs(config.build.rolldownOptions!.output, config.build.lib || false) const outputs = resolveBuildOutputs(config.build.rolldownOptions!.output, config.build.lib)
if (resolvedOutputs) { if (outputs.some(({ format }) => format === 'es')) {
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
if (outputs.find(({ format }) => format === 'es')) {
if (Array.isArray(config.build.rolldownOptions!.output)) { if (Array.isArray(config.build.rolldownOptions!.output)) {
config.build.rolldownOptions!.output.forEach(output => { config.build.rolldownOptions!.output.forEach(output => {
if (output.format === 'es') { if (output.format === 'es') {
@ -252,7 +237,6 @@ export function electronPreloadConfigPresetPlugin(options?: ElectronPluginOption
: path.posix.join(build.assetsDir || defaultConfig.build.assetsDir, '[name]-[hash].mjs') : path.posix.join(build.assetsDir || defaultConfig.build.assetsDir, '[name]-[hash].mjs')
} }
} }
}
config.define = config.define || {} config.define = config.define || {}
config.define = { ...processEnvDefine(), ...config.define } config.define = { ...processEnvDefine(), ...config.define }
@ -302,16 +286,15 @@ export function electronPreloadConfigValidatorPlugin(): Plugin {
) )
} }
const resolvedOutputs = resolveBuildOutputs(rolldownOptions.output, libOptions) const outputs = resolveBuildOutputs(rolldownOptions.output, libOptions)
if (resolvedOutputs) { if (outputs.length > 0) {
const outputs = Array.isArray(resolvedOutputs) ? resolvedOutputs : [resolvedOutputs]
if (outputs.length > 1) { if (outputs.length > 1) {
throw new Error('The electron vite preload config does not support multiple outputs.') throw new Error('The electron vite preload config does not support multiple outputs.')
} else { } else {
const outpout = outputs[0] const output = outputs[0]
if (['es', 'cjs'].includes(outpout.format || '')) { if (['es', 'cjs'].includes(output.format || '')) {
if (outpout.format === 'es' && !supportESM()) { if (output.format === 'es' && !supportESM()) {
throw new Error( throw new Error(
'The electron vite preload config output format does not support "es", ' + 'The electron vite preload config output format does not support "es", ' +
'you can upgrade electron to the latest version or switch to "cjs" format.' 'you can upgrade electron to the latest version or switch to "cjs" format.'

View File

@ -105,7 +105,7 @@ export function swcPlugin(options: SwcOptions = {}): Plugin {
} }
}, },
async renderChunk(code, chunk): Promise<null | { code: string; map: SourceMap }> { async renderChunk(code, chunk): Promise<null | { code: string; map: SourceMap }> {
if (!minify || minify === 'terser') { if (!minify || minify === 'terser' || minify === 'oxc') {
return null return null
} }
const result = await transformWithSWC(code, chunk.fileName, { const result = await transformWithSWC(code, chunk.fileName, {

View File

@ -3,7 +3,7 @@ import path from 'node:path'
import fs from 'node:fs' import fs from 'node:fs'
import { createHash } from 'node:crypto' import { createHash } from 'node:crypto'
import { createRequire } from 'node:module' import { createRequire } from 'node:module'
import { loadEnv as viteLoadEnv } from 'vite' import { type LibraryOptions, type Rolldown, loadEnv as viteLoadEnv } from 'vite'
export function isObject(value: unknown): value is Record<string, unknown> { export function isObject(value: unknown): value is Record<string, unknown> {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === '[object Object]'
@ -32,6 +32,23 @@ export function toRelativePath(filename: string, importer: string): string {
return relPath.startsWith('.') ? relPath : `./${relPath}` return relPath.startsWith('.') ? relPath : `./${relPath}`
} }
/**
* Resolve configured build outputs into an array.
*/
export function resolveBuildOutputs(
outputs: Rolldown.OutputOptions | Rolldown.OutputOptions[] | undefined,
libOptions: LibraryOptions | false | undefined
): Rolldown.OutputOptions[] {
if (Array.isArray(outputs)) {
return outputs
}
if (libOptions) {
const libFormats = libOptions.formats || []
return libFormats.map(format => ({ ...outputs, format }))
}
return outputs ? [outputs] : []
}
/** /**
* Load `.env` files within the `envDir` (default: `process.cwd()`) . * Load `.env` files within the `envDir` (default: `process.cwd()`) .
* By default, only env variables prefixed with `VITE_`, `MAIN_VITE_`, `PRELOAD_VITE_` and * By default, only env variables prefixed with `VITE_`, `MAIN_VITE_`, `PRELOAD_VITE_` and