DEV Community

Željko Šević
Željko Šević

Posted on • Originally published at sevic.dev on

Publishing Electron apps to GitHub with Electron Forge

Releasing Electron desktop apps can be automated with Electron Forge and GitHub Actions. This post covers the main steps for automation.

Prerequisites

  • bootstrapped Electron app
  • GitHub personal access token (with repo and write:packages permissions) as a GitHub Action secret (GH_TOKEN)

Setup

Run the following commands to configure Electron Forge for the app release.

npm i @electron-forge/cli @electron-forge/publisher-github -D
npx electron-forge import
Enter fullscreen mode Exit fullscreen mode

The last command should install the necessary dependencies and add a configuration file.

Update the forge.config.js file with the bin field containing the app name and ensure the GitHub publisher points to the right repository.

Put Windows and MacOS icons paths in the packagerConfig.icon field, Windows supports ico files with 256x256 resolution, and MacOS supports icns icons with 512x512 resolution (1024x1024 for Retina displays). Linux supports png icons with 512x512 resolution, also include its path in the BrowserWindow constructor config within the icon field.

// forge.config.js
const path = require('path');

module.exports = {
  packagerConfig: {
    asar: true,
    icon: path.join(process.cwd(), 'main', 'build', 'icon'),
  },
  rebuildConfig: {},
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {
        bin: 'Electron Starter'
      }
    },
    {
      name: '@electron-forge/maker-dmg',
      config: {
        bin: 'Electron Starter'
      }
    },
    {
      name: '@electron-forge/maker-deb',
      config: {
        bin: 'Electron Starter',
        options: {
          icon: path.join(process.cwd(), 'main', 'build', 'icon.png'),
        },
      }
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {
        bin: 'Electron Starter',
        icon: path.join(process.cwd(), 'main', 'build', 'icon.png'),
      }
    }
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {}
    }
  ],
  publishers: [
    {
      name: '@electron-forge/publisher-github',
      config: {
        repository: {
          owner: 'delimitertech',
          name: 'electron-starter'
        },
        prerelease: true
      }
    }
  ]
};
Enter fullscreen mode Exit fullscreen mode

Upgrade the package version before releasing the app. The npm script for publishing should use publish command. Set productName field to the app name.

// package.json
{
  // ...
  "version": "1.0.1",
  "scripts": {
    // ...
    "publish": "electron-forge publish"
  },
  "productName": "Electron Starter"
}
Enter fullscreen mode Exit fullscreen mode

GitHub Action workflow for manually releasing the app for Linux, Windows, and MacOS should contain the below configuration.

# .github/workflows/release.yml
name: Release app

on:
  workflow_dispatch:

jobs:
  build:
    strategy:
      matrix:
        os:
          [
            { name: 'linux', image: 'ubuntu-latest' },
            { name: 'windows', image: 'windows-latest' },
            { name: 'macos', image: 'macos-latest' },
          ]

    runs-on: ${{ matrix.os.image }}

    steps:
      - name: Github checkout
        uses: actions/checkout@v4

      - name: Use Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - run: npm ci

      - name: Publish app
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
        run: npm run publish
Enter fullscreen mode Exit fullscreen mode

Windows startup events

Add the following code in the main process to prevent Squirrel.Windows launches your app multiple times during the installation/updating/uninstallation.

// main/index.js
if (require('electron-squirrel-startup') === true) app.quit();
Enter fullscreen mode Exit fullscreen mode

Boilerplate

Here is the link to the boilerplate I use for the development. It contains the examples mentioned above with more details.

Top comments (0)