mcpField
E
electrobun-distribution

electrobun-distribution

github.com/rajavijayachDevelopment1173 installsUpdated 36w ago
Repository

About electrobun-distribution

electrobun-distribution is a guide for Electrobun developers preparing desktop applications for release. It covers production builds, signing, installers, auto-updates, and CI/CD workflows.

Key features

  1. 01Production build configuration
  2. 02macOS and Windows code signing
  3. 03Apple app notarization
  4. 04Auto-updater and delta updates
  5. 05DMG, Windows, and Linux packages
  6. 06GitHub Actions release workflow

Use cases

  1. 01Preparing an Electrobun app for release
  2. 02Signing and notarizing macOS builds
  3. 03Publishing app updates and installers

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/rajavijayach/electrobun-skills --skill electrobun-distribution

After installing, type/electrobun-distributionin Claude Code to confirm it loaded.

Details

From the project README

Electrobun Distribution

Complete guide to packaging, signing, and distributing Electrobun applications.

Production Build

Basic Build Configuration

electrobun.config.ts:

import { defineConfig } from "electrobun";

export default defineConfig({
  app: {
    name: "My Application",
    version: "1.0.0",
    identifier: "com.mycompany.myapp",
    description: "My desktop application",
    author: "My Company",
  },
  
  build: {
    main: "src/bun/main.ts",
    views: {
      mainview: "src/views/mainview/index.ts",
      settings: "src/views/settings/index.ts",
    },
    output: "dist",
  },
  
  icons: {
    mac: "assets/icon.icns",    // macOS: 1024x1024 .icns
    win: "assets/icon.ico",     // Windows: .ico with multiple sizes
    linux: "assets/icon.png",   // Linux: 512x512 .png
  },
  
  updates: {
    provider: "generic",
    url: "https://updates.myapp.com",
  },
});
Build Commands
# Development build
bun run dev

# Production build
bun run build

# Build for specific platform
bun run build --platform=mac
bun run build --platform=win
bun run build --platform=linux

# Build for all platforms
bun run build --all

Code Signing

macOS Code Signing
Setup Certificates
# List available certificates
security find-identity -v -p codesigning

# Import Developer ID certificate
# Get certificate from Apple Developer Portal
# Double-click .p12 file or:
security import cert.p12 -k ~/Library/Keychains/login.keychain
Sign Application

electrobun.config.ts:

export default defineConfig({
  // ...
  mac: {
    identity: "Developer ID Application: Your Name (TEAM_ID)",
    entitlements: "entitlements.mac.plist",
    entitlementsInherit: "entitlements.mac.plist",
    hardenedRuntime: true,
    gatekeeperAssess: false,
  },
});

entitlements.mac.plist:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <!-- Allow JIT for Bun runtime -->
  <key>com.apple.security.cs.allow-jit</key>
  <true/>
  
  <!-- Allow unsigned executable memory -->
  <key>com.apple.security.cs.allow-unsigned-executable-memory</key>
  <true/>
  
  <!-- Disable library validation -->
  <key>com.apple.security.cs.disable-library-validation</key>
  <true/>
  
  <!-- Network client access -->
  <key>com.apple.security.network.client</key>
  <true/>
  
  <!-- Optional: Network server -->
  <key>com.apple.security.network.server</key>
  <true/>
  
  <!-- Optional: Camera access -->
  <key>com.apple.security.device.camera</key>
  <true/>
  
  <!-- Optional: Microphone access -->
  <key>com.apple.security.device.audio-input</key>
  <true/>
</dict>
</plist>
Apple Notarization
# Notarize the app
xcrun notarytool submit dist/MyApp.dmg \
  --apple-id "[email protected]" \
  --team-id "TEAM_ID" \
  --password "app-specific-password" \
  --wait

# Check notarization status
xcrun notarytool log <submission-id> \
  --apple-id "[email protected]" \
  --team-id "TEAM_ID" \
  --password "app-specific-password"

# Staple notarization to DMG
xcrun stapler staple dist/MyApp.dmg

# Verify stapling
xcrun stapler validate dist/MyApp.dmg

Automated notarization:

// In electrobun.config.ts
export default defineConfig({
  // ...
  mac: {
    identity: "Developer ID Application: Your Name (TEAM_ID)",
    notarize: {
      teamId: process.env.APPLE_TEAM_ID,
      appleId: process.env.APPLE_ID,
      appleIdPassword: process.env.APPLE_APP_PASSWORD,
    },
  },
});
Windows Code Signing
Get Certificate
# Import certificate
certutil -importpfx cert.pfx

# Or specify password
certutil -f -p PASSWORD -importpfx cert.pfx
Sign Application

electrobun.config.ts:

export default defineConfig({
  // ...
  win: {
    certificateFile: "cert.pfx",
    certificatePassword: process.env.WIN_CERT_PASSWORD,
    signWithParams: "/tr http://timestamp.digicert.com /td sha256 /fd sha256",
  },
});

Manual signing:

# Sign executable
signtool sign /f cert.pfx /p PASSWORD /tr http://timestamp.digicert.com /td sha256 /fd sha256 MyApp.exe

# Verify signature
signtool verify /pa MyApp.exe

Auto-Updater

Update Server Setup

updates.json:

{
  "version": "1.0.1",
  "releaseDate": "2026-02-21T00:00:00Z",
  "platforms": {
    "darwin": {
      "url": "https://updates.myapp.com/MyApp-1.0.1-mac.zip",
      "signature": "MC0CFQCf...",
      "size": 15728640
    },
    "win32": {
      "url": "https://updates.myapp.com/MyApp-1.0.1-win.exe",
      "signature": "30820...",
      "size": 12582912
    },
    "linux": {
      "url": "https://updates.myapp.com/MyApp-1.0.1-linux.AppImage",
      "signature": "30440...",
      "size": 18874368
    }
  },
  "releaseNotes": "Bug fixes and performance improvements"
}
Client Implementation

src/bun/main.ts:

import { Updater, dialog } from "electrobun/bun";

class UpdateManager {
  private updater: Updater;
  private updateAvailable = false;
  
  constructor() {
    this.updater = new Updater({
      url: "https://updates.myapp.com/updates.json",
      autoCheck: true,
      interval: 4 * 60 * 60 * 1000, // Check every 4 hours
    });
    
    this.setupHandlers();
  }
  
  private setupHandlers() {
    this.updater.on("update-available", async (info) => {
      this.updateAvailable = true;
      
      const result = await dialog.showMessageBox({
        type: "info",
        title: "Update Available",
        message: `Version ${info.version} is available`,
        detail: info.releaseNotes,
        buttons: ["Download Now", "Later"],
        defaultId: 0,
      });
      
      if (result.response === 0) {
        this.updater.downloadAndInstall();
      }
    });
    
    this.updater.on("update-not-available", () => {
      console.log("App is up to date");
    });
    
    this.updater.on("download-progress", (progress) => {
      console.log(`Download progress: ${progress.percent}%`);
      // Update UI with progress
      mainWindow.rpc.updateDownloadProgress(progress);
    });
    
    this.updater.on("update-downloaded", async () => {
      const result = await dialog.showMessageBox({
        type: "info",
        title: "Update Ready",
        message: "Update has been downloaded",
        detail: "The app will restart to apply the update",
        buttons: ["Restart Now", "Later"],
        defaultId: 0,
      });
      
      if (result.response === 0) {
        this.updater.quitAndInstall();
      }
    });
    
    this.updater.on("error", (error) => {
      console.error("Update error:", error);
      dialog.showMessageBox({
        type: "error",
        title: "Update Error",
        message: "Failed to check for updates",
        detail: error.message,
      });
    });
  }
  
  checkForUpdates() {
    this.updater.checkForUpdates();
  }
  
  isUpdateAvailable() {
    return this.updateAvailable;
  }
}

const updateManager = new UpdateManager();

// Expose to window RPC
win.defineRpc({
  handlers: {
    checkForUpdates: async () => {
      updateManager.checkForUpdates();
    },
    isUpdateAvailable: async () => {
      return updateManager.isUpdateAvailable();
    }
  }
});
Delta Updates

Electrobun uses bsdiff for tiny delta updates (~14KB):

// Automatically handled by Updater
// Just ensure update server provides:
// - Full package for new installs
// - Delta patches for updates

// Update server structure:
// /updates.json
// /v1.0.0/MyApp-mac.zip (full)
// /v1.0.1/MyApp-mac.zip (full)
// /v1.0.1/delta-1.0.0-to-1.0.1-mac.patch (delta)

Creating Installers

macOS DMG
# Create DMG with background and app arrangement
create-dmg dist/MyApp.app dist/ \
  --overwrite \
  --window-size 660 400 \
  --icon-size 160 \
  --icon "MyApp.app" 180 170 \
  --hide-extension "MyApp.app" \
  --app-drop-link 480 170 \
  --background "installer-background.png"

# Result: dist/MyApp-1.0.0.dmg
Windows Installer

Using NSIS:

; installer.nsi
!include "MUI2.nsh"

Name "My Application"
OutFile "MyApp-Setup.exe"
InstallDir "$PROGRAMFILES\My Application"

!insertmacro MUI_PAGE_WELCOME
!insertmacro MUI_PAGE_DIRECTORY
!insertmacro MUI_PAGE_INSTFILES
!insertmacro MUI_PAGE_FINISH

!insertmacro MUI_LANGUAGE "English"

Section "Install"
  SetOutPath "$INSTDIR"
  
  File /r "dist\*.*"
  
  CreateDirectory "$SMPROGRAMS\My Application"
  CreateShortcut "$SMPROGRAMS\My Application\My Application.lnk" "$INSTDIR\MyApp.exe"
  CreateShortcut "$DESKTOP\My Application.lnk" "$INSTDIR\MyApp.exe"
  
  WriteUninstaller "$INSTDIR\Uninstall.exe"
  
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp" "DisplayName" "My Application"
  WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp" "UninstallString" "$INSTDIR\Uninstall.exe"
SectionEnd

Section "Uninstall"
  Delete "$INSTDIR\*.*"
  RMDir /r "$INSTDIR"
  Delete "$SMPROGRAMS\My Application\*.*"
  RMDir "$SMPROGRAMS\My Application"
  Delete "$DESKTOP\My Application.lnk"
  DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\MyApp"
SectionEnd
Linux Packages

AppImage (recommended):

# Create AppImage
appimagetool dist/MyApp-linux-x64 dist/MyApp.AppImage

# Make executable
chmod +x dist/MyApp.AppImage

Debian package:

# Create .deb structure
mkdir -p myapp_1.0.0/DEBIAN
mkdir -p myapp_1.0.0/usr/bin
mkdir -p myapp_1.0.0/usr/share/applications
mkdir -p myapp_1.0.0/usr/share/icons/hicolor/512x512/apps

# Copy files
cp dist/MyApp myapp_1.0.0/usr/bin/
cp myapp.desktop myapp_1.0.0/usr/share/applications/
cp icon.png myapp_1.0.0/usr/share/icons/hicolor/512x512/apps/

# Create control file
cat > myapp_1.0.0/DEBIAN/control << EOF
Package: myapp
Version: 1.0.0
Section: utils
Priority: optional
Architecture: amd64
Maintainer: Your Name <[email protected]>
Description: My Application
 A desktop application built with Electrobun
EOF

# Build .deb
dpkg-deb --build myapp_1.0.0

CI/CD Integration

GitHub Actions

.github/workflows/build.yml:

name: Build and Release

on:
  push:
    tags:
      - 'v*'

jobs:
  build-mac:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Bun
        uses: oven-sh/setup-bun@v1
        
      - name: Install dependencies
        run: bun install
        
      - name: Import signing certificate
        env:
          CERTIFICATE_BASE64: ${{ secrets.MAC_CERTIFICATE }}
          CERTIFICATE_PASSWORD: ${{ secrets.MAC_CERT_PASSWORD }}
        run: |
          echo $CERTIFICATE_BASE64 | base64 --decode > certificate.p12
          security import certificate.p12 -P $CERTIFICATE_PASSWORD
          
      - name: Build app
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
        run: bun run build --platform=mac
        
      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: mac-build
          path: dist/*.dmg

  build-windows:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Bun
        uses: oven-sh/setup-bun@v1
        
      - name: Install dependencies
        run: bun install
        
      - name: Build app
        env:
          WIN_CERT_PASSWORD: ${{ secrets.WIN_CERT_PASSWORD }}
        run: bun run build --platform=win
        
      - name: Upload artifact
        uses: actions/upload-artifact@v3
        with:
          name: win-build
          path: dist/*.exe

  release:
    needs: [build-mac, build-windows]
    runs-on: ubuntu-latest
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v3
        
      - name: Create Release
        uses: softprops/action-gh-release@v1
        with:
          files: |
            mac-build/*
            win-build/*
          draft: false
          prerelease: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Best Practices

Version Management
// Use semantic versioning
const version = "1.2.3"; // MAJOR.MINOR.PATCH

// Update package.json and electrobun.config.ts together
// Automate with script:
import { writeFileSync, readFileSync } from "fs";

function updateVersion(newVersion: string) {
  // Update package.json
  const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
  pkg.version = newVersion;
  writeFileSync("package.json", JSON.stringify(pkg, null, 2));
  
  // Update config
  const config = readFileSync("electrobun.config.ts", "utf-8");
  const updated = config.replace(
    /version:\s*"[^"]+"/,
    `version: "${newVersion}"`
  );
  writeFileSync("electrobun.config.ts", updated);
}
Testing Before Release
// Pre-release checklist
const checklist = [
  "All tests passing",
  "No console errors",
  "Auto-updater tested",
  "Code signed and notarized",
  "Installer tested on clean system",
  "Release notes written",
  "Documentation updated",
];

Resources

For more on Electrobun:

Comments

Markdown supported