A minimal Electron demo that compiles, packages, and runs through a GitHub Actions multi-platform build pipeline.
The goal is not to carry business logic, but to preserve the core engineering structure of hagicode-desktop and serve as a fast lane for validating Electron build, packaging, and release workflows.
src/main— Electron main processsrc/preload— Context bridgesrc/renderer— React + Vite home pagescripts— Packaging helpers, artifact preservation, signing verification, and smoke tests.github/workflows— PR checks, entry orchestration workflow, platform reuse workflow, and Release Drafter
npm ci
npm run dev
npm run build:prod
npm run build:linux
npm run build:linux:deb
npm run build:linux:rpm
npm run build:win
npm run build:win:msix
npm run build:mac:x64
npm run build:mac:arm64The renderer home page is now a validation lab for the desktop pm2 scenario.
- It probes whether local
pm2,dotnet, andnodeare visible from the Electron main process. - It lets you run
pm2 start/restart/stop/delete/describe/logs/jlist/pingthrough the preload bridge. - It ships a bundled heartbeat worker at
resources/pm2/heartbeat-worker.cjs, so you can validateElectron -> local pm2 -> packaged resourcebefore switching to a real.NETserver. - It shows PSF-related runtime evidence, including the expected launcher name and whether
config.jsonexists next to the packaged executable.
Recommended validation flow:
- Run
npm run dev. - Use
填充心跳脚本示例, then clickpm2 start,jlist, andlogs. - If the local
pm2chain works, switch to填充 .NET Server 示例, replace the DLL path, and repeat the same actions. - On Windows packaging runs, compare the same flow with and without PSF enabled.
The validation page also supports a dedicated PM2_HOME and an automatic no-space alias for paths that contain spaces, which mirrors the behavior the desktop app needs for reliable pm2 execution.
pr-checks.yml— Install, type check, production build, and Linux dir packaging self-checkbuild.yml— Parallel matrix builds across Linux / Windows / macOS by OS + package format- Linux targets include
AppImage,deb,rpm,tar.gz, andzip - Packaging now uses Electron Forge makers instead of the previous
electron-builderCLI wrapper - Windows targets include
portable,nsis, andmsix - The MSIX path now matches Microsoft's recommended Forge flow more closely: package the app first, generate an explicit
Package.appxmanifest, then let the MSIX maker build from that packaged layout - Tag releases enter the
productionenvironment and upload assets progressively to an already-created GitHub Release as each matrix job finishes - Manual triggers with
production_build=truealso run production builds; they follow production signing checks and only upload workflow artifacts without creating a GitHub Release - For production builds:
- The Windows job uses
windows-2025runners;.exeand.msixartifacts are signed via Azure Artifact Signing v2, and the MSIX manifest readsPublisherfromWINDOWS_PACKAGE_PUBLISHERso it can match the signing certificate subject - If Azure Artifact Signing fails for
msix, the signedwin-msixartifact is skipped and onlywin-msix-unsignedis retained - macOS production builds now import the signing certificate into a temporary keychain, then let Electron Forge packager run
osxSignandosxNotarize - Signed macOS and Windows packages are retained alongside their unsigned counterparts; unsigned artifacts are suffixed with
-unsignedand appear in both workflow artifacts and tag releases
- The Windows job uses
Production tag releases and manual triggers with production_build=true require the following secrets in the repository or production environment:
- Windows signing:
AZURE_CLIENT_ID,AZURE_TENANT_ID,AZURE_SUBSCRIPTION_ID,AZURE_CODESIGN_ENDPOINT,AZURE_CODESIGN_ACCOUNT_NAME,AZURE_CODESIGN_CERTIFICATE_PROFILE_NAME,WINDOWS_PACKAGE_PUBLISHERWINDOWS_PACKAGE_PUBLISHERmust exactly match the Azure Trusted Signing certificate subject because the MSIX manifest uses it as thePublishervalue
- macOS signing certificates:
CSC_LINK,CSC_KEY_PASSWORD - macOS notarization:
- Recommended API key approach:
APPLE_API_KEY,APPLE_API_KEY_ID,APPLE_API_ISSUER - Or Apple ID approach:
APPLE_ID,APPLE_APP_SPECIFIC_PASSWORD,APPLE_TEAM_ID
- Recommended API key approach:
msix remains in the Windows release matrix and is uploaded as a release artifact. The workflow injects WINDOWS_PACKAGE_PUBLISHER so the manifest Publisher matches the signing certificate subject. For msix, production signing is still attempted via Azure Artifact Signing v2, but if that step fails only the unsigned win-msix-unsigned artifact is kept.
Manual production build example: run Build Electron Demo from the Actions page with production_build set to true. This binds to the production environment, executes production-level signing pre-checks, and preserves artifacts in workflow artifacts. Tag-driven releases now assume the GitHub Release already exists and each matrix job uploads its assets directly with gh release upload --clobber.
- resources/msix/Package.appxmanifest.template.xml is the source manifest template. Forge prepares the final file at
.cache/msix/Package.appxmanifestduring Windows packaging. - The demo MSIX manifest now marks the packaged app as an explicit full-trust desktop app by combining
Windows.FullTrustApplication,runFullTrust,uap10:RuntimeBehavior="packagedClassicApp", anduap10:TrustLevel="mediumIL". - The generated manifest pins
Executable="app\\electron-demo.exe", so the MSIX entry point matchespackagerConfig.executableNameinstead of Forge's default app folder name. - Local signing is optional. If
devcert.pfxexists andWINDOWS_CERTIFICATE_PASSWORDis set, Forge signs during MSIX packaging. Otherwise it produces an unsigned MSIX and CI can keep using Azure signing afterward. WINDOWS_KIT_VERSIONis optional now. If you leave it unset, the MSIX tooling falls back to the SDK version implied by the manifestMinVersion, which is closer to the Microsoft guidance for avoiding Windows SDK lookup mismatches.- GitHub Actions now resolves the installed Windows SDK version on the runner before the
msixjob and exports it asWINDOWS_KIT_VERSION, so the build does not depend on the manifestMinVersionmatching the exact SDK version preinstalled onwindows-2025.
The demo now includes an opt-in PSF path for Windows x64 MSIX builds. It is disabled by default so the existing Forge packaging flow stays stable.
Enable it by setting:
ELECTRON_DEMO_ENABLE_PSF=true
ELECTRON_DEMO_PSF_DIR=/absolute/path/to/psfELECTRON_DEMO_PSF_DIR must contain:
PsfLauncher64.exePsfRuntime64.dllProcessLauncherFixup64.dllFileRedirectionFixup64.dll
When enabled:
scripts/prepare-msix.jsrewrites the manifest entry executable toPsfLauncher64.exe.forge.config.jskeeps using Forge, but injects PSF binaries plusconfig.jsoninto the packaged output duringpostPackage.resources/psf/config.template.jsonis rendered so the real app entry remainsapp\\electron-demo.exe, whileProcessLauncherFixup64.dllprevents breakaway on spawned child processes.
Example:
cd repos/electron_demo
ELECTRON_DEMO_ENABLE_PSF=true \
ELECTRON_DEMO_PSF_DIR="C:/tools/psf" \
npm run build:win:msixThis gives the demo a concrete place to verify the claim that Electron can still drive local pm2 correctly inside an MSIX package when PSF is used to keep child-process launches inside the package identity boundary.