Skip to content

feat: add electron-forge bundle CLI command#4164

Draft
bglgwyng wants to merge 2 commits intoelectron:mainfrom
bglgwyng:feat/bundle-command
Draft

feat: add electron-forge bundle CLI command#4164
bglgwyng wants to merge 2 commits intoelectron:mainfrom
bglgwyng:feat/bundle-command

Conversation

@bglgwyng
Copy link
Copy Markdown

@bglgwyng bglgwyng commented Mar 13, 2026

Motivation

Currently, running a production bundling step (webpack/vite) requires running electron-forge package, which also invokes @electron/packager to download Electron binaries, copy source files, and produce a native app bundle. This is slow and unnecessary when you only need the bundled output — for example:

  • E2E testing with Playwright: Run production bundles via electron . to test against realistic builds, without the overhead of full packaging.
  • Bundle validation in CI: Quickly verify that the webpack/vite production build doesn't break, without downloading Electron binaries.
  • Custom packaging pipelines: Produce bundle output to feed into external packaging tools.

Summary

Add a standalone bundle command that runs only the bundling step (generateAssets + prePackage hooks) without invoking @electron/packager.

electron-forge bundle
electron-forge bundle --arch x64
electron-forge bundle --platform darwin --arch arm64

Open questions

1. Should the command include a post-bundling cleanup step?

The webpack plugin's prePackage hook moves build output from .webpack/ into .webpack/{arch}/ (e.g. .webpack/x64/main/). This is designed so @electron/packager can copy all arch builds at once and later extract the correct one per target via packageAfterCopy.

Without the packager, the output stays at .webpack/{arch}/main/, which doesn't match package.json's main: ".webpack/main" — so electron . won't work directly after bundle.

Options:

  • (a) Leave as-is — bundle only runs the hooks, users handle the output structure themselves
  • (b) Add a postBundle hook so plugins can clean up their own output (e.g. flatten .webpack/{arch}/.webpack/), keeping plugin internals encapsulated
  • (c) Have bundle invoke packageAfterCopy — but this hook is designed for a different context (packager's copied build path, not the source project)

2. Does the {arch} subfolder strategy make sense for bundle?

The {arch}/ subfolder pattern in the webpack plugin was designed for multi-arch packaging where all arches coexist before the packager copies them out. For bundle (especially for e2e testing on the current machine), this intermediate structure adds complexity. However, changing prePackage behavior based on the calling context would require plumbing new information through the hook system.

3. Should --arch and --platform be kept?

These flags are passed through to prePackage and behave identically to package. For the primary use case (e2e testing), only the host arch is needed. Removing them would simplify the command but break consistency with other commands (package, make).

Test plan

  • Verify electron-forge bundle runs generateAssets + prePackage hooks with webpack plugin
  • Verify electron-forge bundle runs generateAssets + prePackage hooks with vite plugin
  • Verify --arch and --platform flags are passed through correctly
  • Verify bundle output structure matches expectations

  • I have read the contribution documentation for this project.
  • I agree to follow the code of conduct that this project follows, as appropriate.
  • The changes are appropriately documented (if applicable).
  • The changes have sufficient test coverage (if applicable).
  • The testsuite passes successfully on my local machine (if applicable).

🤖 Generated with Claude Code

Add a standalone `bundle` command that runs only the bundling step
(generateAssets + prePackage hooks) without invoking @electron/packager.
This ensures the same webpack/vite config is used as `package` while
allowing users to produce bundle output independently.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@bglgwyng bglgwyng requested a review from a team as a code owner March 13, 2026 07:39
@bglgwyng bglgwyng marked this pull request as draft March 16, 2026 07:31
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@MarshallOfSound
Copy link
Copy Markdown
Member

I don't think this API surface makes sense, it feels like an arbitrary list of hooks are called in a sequence that doesn't match reality in a production build.

If you want to e2e test something you should be e2e testing the actual asset, not an asset spoof-built to be close to that asset.

I'm a -1 on landing this as API surface

@bglgwyng
Copy link
Copy Markdown
Author

I appreciate the criticism, and I agree that the current implementation has issues — that's why I left the open questions in the PR description.

That said, the underlying need still stands: there's no stable way to run the same webpack/vite build that Forge runs internally without going through the full package command. Calling webpack/vite separately outside of Forge is fragile since it depends on plugin internals that can change at any time.

Beyond e2e testing, there's a practical gap in Forge's current workflow. Forge already goes beyond pure build tooling — it provides electron-forge start for dev, package for packaging, and publish for distribution. But there's no way to inspect the production bundle as an intermediate artifact before packaging. You can run a dev build or produce a fully packaged app, but you can't verify what the production bundler actually outputs on its own.

I'm aware the current design of this PR doesn't cleanly solve this — that's exactly why I outlined the alternative approaches in the open questions. Before I invest more time into the implementation details, I'd like to align on whether this is a problem worth solving within Forge. Do you agree there's a gap here, even if this particular API shape isn't the right answer?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants