Package Local Web as Electron
Package existing web content; do not rewrite its visual product unless packaging exposes a concrete compatibility issue.
Inspect and choose the input
Run scripts/inspect_web_app.sh <project-dir> first. Treat a standalone .html file as a static input. For a framework project, use its existing production build command and package the build output, never its development server.
Read references/packaging-matrix.md before selecting targets or release settings.
Stop and explain the limitation if the site requires a server-side API, database, OAuth callback, CDN-only assets, or secret. Local Electron packaging cannot make those dependencies offline by itself.
Create the Electron shell
- Add Electron and
electron-builderto the project, preserving existing package tooling. - Create a minimal main process which creates one
BrowserWindowand loads the selected local HTML withloadFile. - Set
contextIsolation: true,sandbox: true, andnodeIntegration: false. Add a preload bridge only for explicitly required local capabilities; validate every input exposed through it. - Add
start,dist, and platform-specific package scripts. Configureelectron-builderwith app name, identifier, output directory, files allowlist, and an icon. - Keep all first-party static assets within the packaged files. Surface any remaining network requests to the user.
Give every app an icon
Use a user-provided icon when available. Otherwise, generate a simple, high-contrast default icon that reflects the app's purpose; never leave the Electron default icon in a deliverable.
- On macOS, run
scripts/generate_default_icon_macos.sh <output-dir>to createicon.svgandicon.icns. - Set
build.mac.iconto the generated.icns. On Windows, provide a matching.ico; use a PNG/SVG only where the target accepts it. - Verify the built application's
Contents/Resourcescontains the intended icon. Record whether it is a generated fallback or a user-supplied brand asset.
Preflight the toolchain
- Run
npm installand confirm that Electron's platform binary actually downloaded; a successful dependency-resolution phase alone is insufficient. - Select the artifact architecture explicitly (
arm64,x64, oruniversalon macOS). Match it to the user's intended devices. - If Electron's binary download is unavailable, look for the exact Electron version and architecture in
~/Library/Caches/electron/. Use the cached-runtime fallback only when they match; do not relabel a different architecture or version as the requested release. - If
electron-builderfails before producing artifacts, retain its complete log and report the blocker. On macOS, usescripts/package_cached_electron_macos.shonly for an available matching cached Electron runtime.
Add local SQLite storage
Keep SQLite in the Electron main process. Place the database at path.join(app.getPath('userData'), '<app>.sqlite'); never write it beside renderer files or under Contents/Resources.
- Prefer a compatible SQLite runtime for the selected Electron version. For
node:sqlite, verify the bundled Electron Node version supports it; otherwise choose and package a compatible dependency. - Create schema migrations with
CREATE TABLE IF NOT EXISTSor a versioned migration table. - Expose narrow, validated IPC handlers (
task:add,task:list), then expose only those methods through preload. Do not expose generic SQL execution to the renderer. - Package every renderer page and its relative assets;
loadFileand normal relative links work for static multi-page navigation.
Build and verify
- Run the existing web build, when applicable, then run Electron locally before packaging.
- Build native artifacts on their native host whenever possible. On macOS, produce
.dmgand.zip; on Windows, produce NSIS.exeand optionally portable.exe. - Verify an
.appwithcodesign --verify --deep --strict. Treat this as an integrity check, not Gatekeeper approval. Runspctl --assess --type executeand report its result. - For SQLite projects, create a record, close the app, reopen it, and verify the record survives. Confirm the database resides in
userDataand not inside the app bundle. - Use unsigned or ad-hoc output only for local testing unless the user supplies signing credentials. Do not claim a distributable signed build without Apple notarization or Windows code signing.
- Report exact artifact paths, target architecture, signing and notarization status, test result, and all online dependencies found.
Regression cases
Run scripts/run_fixture_checks.sh whenever changing the inspection or packaging workflow. Read references/test-cases.md before packaging a multi-page or data-persisting project. Treat its acceptance criteria as release gates, not suggestions.
For local storage, keep mutable data in app.getPath('userData'), never inside the packaged app. Expose storage through a narrow preload API; do not enable renderer Node access. For a remote backend, stop and identify the service, credentials, connectivity, and offline behavior that must be decided before packaging.
Resources
scripts/inspect_web_app.sh: enumerate likely entry points, package scripts, and remote asset/API references.scripts/package_cached_electron_macos.sh: assemble a locally testable.appfrom an exact cached Electron archive when normal binary acquisition is unavailable.scripts/generate_default_icon_macos.sh: create a high-contrast fallback SVG and macOS.icnsicon.scripts/run_fixture_checks.sh: generate and inspect static, local-storage, and remote-backend fixtures.references/packaging-matrix.md: target selection and signing constraints.references/test-cases.md: packaging test cases and acceptance criteria.
