diff --git a/src/build.ts b/src/build.ts index e1f5165..7754edd 100644 --- a/src/build.ts +++ b/src/build.ts @@ -1,6 +1,6 @@ -import { build as viteBuild } from 'vite' +import { build as viteBuild, mergeConfig } from 'vite' import { type InlineConfig, type MainViteConfig, type PreloadViteConfig, resolveConfig } from './config' -import { BytecodeBuild, runWithBytecodeBuild } from './bytecode/build' +import { BytecodeBuild, bytecodeBuildPluginName } from './bytecode/build' import { asyncFlatten } from './utils' async function useBytecode(config?: MainViteConfig | PreloadViteConfig): Promise { @@ -14,7 +14,15 @@ async function useBytecode(config?: MainViteConfig | PreloadViteConfig): Promise */ export async function build(inlineConfig: InlineConfig = {}): Promise { process.env.NODE_ENV_ELECTRON_VITE = 'production' - const config = await resolveConfig(inlineConfig, 'build', 'production') + + const bytecodeBuild = new BytecodeBuild() + const config = await resolveConfig( + mergeConfig(inlineConfig, { + plugins: [{ name: bytecodeBuildPluginName, api: { build: bytecodeBuild } }] + }), + 'build', + 'production' + ) if (!config.config) { return @@ -22,7 +30,7 @@ export async function build(inlineConfig: InlineConfig = {}): Promise { const mainBytecode = await useBytecode(config.config.main) const preloadBytecode = await useBytecode(config.config.preload) - const bytecodeBuild = mainBytecode || preloadBytecode ? new BytecodeBuild() : undefined + const hasBytecode = mainBytecode || preloadBytecode const buildTargets = async (): Promise => { // Build targets in order: main -> preload -> renderer @@ -38,11 +46,11 @@ export async function build(inlineConfig: InlineConfig = {}): Promise { } } - if (!bytecodeBuild) return buildTargets() + if (!hasBytecode) return buildTargets() try { await bytecodeBuild.start() - await runWithBytecodeBuild(bytecodeBuild, buildTargets) + await buildTargets() } finally { await bytecodeBuild.stop() } diff --git a/src/bytecode/build.ts b/src/bytecode/build.ts index 5ba65dd..3d21668 100644 --- a/src/bytecode/build.ts +++ b/src/bytecode/build.ts @@ -1,8 +1,7 @@ -import { AsyncLocalStorage } from 'node:async_hooks' +import { type Plugin } from 'vite' import { BytecodeCompiler, type BytecodeCompileResult, type BytecodeTarget } from './compiler' -// Nested isolated-entry builds inherit the compilation session from the parent build. -const activeBuild = new AsyncLocalStorage() +export const bytecodeBuildPluginName = 'vite:electron-bytecode-build' export class BytecodeBuild { private readonly compiler = new BytecodeCompiler() @@ -20,10 +19,7 @@ export class BytecodeBuild { } } -export function runWithBytecodeBuild(build: BytecodeBuild, callback: () => Promise): Promise { - return activeBuild.run(build, callback) -} - -export function getBytecodeBuild(): BytecodeBuild | undefined { - return activeBuild.getStore() +export function getBytecodeBuild(plugins: readonly Plugin[]): BytecodeBuild | undefined { + const plugin = plugins.find(plugin => plugin.name === bytecodeBuildPluginName) + return (plugin?.api as { build?: BytecodeBuild } | undefined)?.build } diff --git a/src/plugins/bytecode.ts b/src/plugins/bytecode.ts index 7222962..090cf92 100644 --- a/src/plugins/bytecode.ts +++ b/src/plugins/bytecode.ts @@ -12,11 +12,11 @@ import { type BytecodeTarget } from '../bytecode/compiler' // 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. -async function compileToBytecode(builder: BytecodeBuild, target: BytecodeTarget, code: string): Promise { +async function compileToBytecode(build: BytecodeBuild, target: BytecodeTarget, code: string): Promise { const id = randomBytes(16) // Reserve enough source space for an untruncated, per-artifact placeholder identity. const source = code + '\n/*' + id.toString('hex') + '*/' - const result = await builder.compile(target, source) + const result = await build.compile(target, source) const header = Buffer.alloc(28) header.write('EVBC0001', 0, 'ascii') header.writeUInt32LE(result.sourceLength, 8) @@ -118,12 +118,14 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null { let supported = false let isPreload = false + let bytecodeBuild: BytecodeBuild | undefined return { name: 'vite:bytecode', apply: 'build', enforce: 'post', configResolved(config): void { + bytecodeBuild = getBytecodeBuild(config.plugins) if (supported) { return } @@ -182,8 +184,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null { const bundles = Object.keys(output) - const compiler = getBytecodeBuild() - if (!compiler) { + if (!bytecodeBuild) { throw new Error('Bytecode compilation requires an electron-vite build session') } for (const name of bundles) { @@ -206,7 +207,7 @@ export function bytecodePlugin(options: BytecodeOptions = {}): Plugin | null { } } if (bytecodeChunks.includes(name)) { - const bytecodeBuffer = await compileToBytecode(compiler, isPreload ? 'preload' : 'main', _code) + const bytecodeBuffer = await compileToBytecode(bytecodeBuild, isPreload ? 'preload' : 'main', _code) this.emitFile({ type: 'asset', fileName: name + 'c',