perf(plugin-vite): run production builds in isolated subprocesses#4163
Merged
MarshallOfSound merged 1 commit intonextfrom Mar 13, 2026
Merged
perf(plugin-vite): run production builds in isolated subprocesses#4163MarshallOfSound merged 1 commit intonextfrom
MarshallOfSound merged 1 commit intonextfrom
Conversation
Each main/preload/renderer build target now runs in its own Node subprocess during `forge package`. This prevents Vite's global state (plugin caches, esbuild instances, module graph) from leaking across targets, which previously caused intermittent misresolution when building multiple targets in the same process. The plugin passes a serializable snapshot of the build/renderer config to each worker via env vars. Dev server mode is unchanged — this only affects production (`isProd`) builds.
erickzhao
approved these changes
Mar 13, 2026
Member
erickzhao
left a comment
There was a problem hiding this comment.
overall LGTM, two questions
| FORGE_VITE_INDEX: String(index), | ||
| FORGE_VITE_CONFIG: JSON.stringify(pluginConfig), | ||
| }, | ||
| stdio: ['ignore', 'ignore', 'pipe'], |
Member
There was a problem hiding this comment.
Should we also pipe out stdout back to the parent process in case any logs/warnings are emitted from the Vite build?
| }); | ||
|
|
||
| child.on('error', reject); | ||
| child.on('close', (code) => { |
Member
There was a problem hiding this comment.
Should we handle signal as well here as the second param?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Run each production Vite build target (main, preload, renderer) in its own Node subprocess during
forge package, instead of callingvite.build()in-process for every target concurrently.Why
When all targets share one Node process, concurrent Rollup instances thrash the shared V8 heap and event loop. For apps with many build targets and large bundles, this serializes a lot of work that should be parallel. On one real-world app with a dozen+ targets this cut total Vite build time by ~45–55% — subprocesses can actually saturate multiple CPU cores instead of fighting over one event loop.
Dev mode (
forge start) is unchanged — dev servers and watchers stay in-process.How
subprocess-worker.tsreceives the full plugin config + a target index via env vars, re-resolves the config viaViteConfigGenerator, and runs a singlevite.build()renderer[]list (not just one spec) becausegetBuildDefine()reads it to generate${NAME}_VITE_NAMEdefines for main targetscwd: projectDirso relative entry paths inrollupOptions.input(preload) resolve correctlyconcurrentconfig optionTest plan
subprocess-worker.spec.ts— 7 tests covering main/preload/renderer builds, define injection, non-zero index, and error surfacingforge packagerun on a multi-target app