Automate Electron App Packaging for Windows and macOS with Gulp

This tutorial walks through a complete, automated workflow for turning an Electron project into installable Windows .exe/.msi and macOS .dmg packages, covering directory structure, configuration, building, code signing, installer creation, and release steps using Gulp and related tools.

CoolHome R&D Department
CoolHome R&D Department
CoolHome R&D Department
Automate Electron App Packaging for Windows and macOS with Gulp

Introduction

Many articles teach how to start an Electron project, but turning the code into a distributable product requires additional steps. This is the second article in the Electron series, focusing on automating the build process so that a single npm run xxx command produces an installable package.

The guide assumes you want to create desktop applications for both Windows and macOS, and it emphasizes a pragmatic, repeatable workflow rather than claiming to be the ultimate solution.

Why Automation Matters

Unlike web apps, desktop apps are downloaded and run locally, so you must produce installers for each target platform. Automation lets developers focus on features instead of repetitive manual packaging tasks.

Project Directory Structure

The recommended layout uses a dual package.json approach: a root package.json for development dependencies and scripts, and an app/package.json for the Electron application itself.

/ (project root)
├── app/                # Application source code
│   ├── assets/         # Images, icons, etc.
│   ├── config/        # Environment‑specific config files
│   ├── consts/        # Constants (e.g., IPC channels)
│   ├── lib/           # Third‑party libraries (e.g., jQuery)
│   ├── plugins/       # Platform‑specific plugins (e.g., Flash)
│   ├── utils/         # Utility functions
│   ├── view/          # HTML/CSS/JS UI files
│   ├── app_config.js  # Merged configuration for the current build
│   ├── main.js        # Application entry point
│   ├── package.json   # App version, dependencies, etc.
│   └── yarn.lock
├── build_resource/    # Build scripts, icons, and other resources
├── config/            # Template config files for dev, alpha, beta, prod
├── deploy/            # Deployment scripts (e.g., upload to OSS)
├── dist/              # Build output (installers)
├── release/           # Final distributable packages
├── gulpfile.js        # Gulp tasks that orchestrate the workflow
└── package.json       # Development dependencies and scripts

Workflow Overview

Configuration : Parse command‑line arguments, generate platform‑specific config files, and copy required assets into app/.

Packaging : Use electron-packager (or electron-builder) to create platform binaries.

Code Signing : Sign the binaries on Windows (using signtool) and macOS (using electron-osx-sign).

Installer Creation : Build a Windows installer with Inno Setup and a macOS .dmg with appdmg.

Release : Rename the installers according to a naming convention and upload them to a cloud storage service.

1. Configuration Phase

We use yargs to read three parameters: platform (darwin, win32, win64), arch (x64, ia32), and sign (boolean). These values can also be derived from the environment.

const platform = argv.platform || detectPlatform() || 'win32';
const arch = platform === 'darwin' ? 'x64' : argv.arch || 'ia32';
const needSign = argv.sign || process.env.NODE_ENV === 'prod' || platform === 'darwin';

Configuration templates live in config/ (e.g., dev.js, alpha.js, prod.js). Gulp tasks replace placeholders with the actual version and app name, then write the final files into app/config/.

2. Packaging Phase

Two example option objects illustrate how to call electron-packager for macOS and Windows:

// macOS
const macOptions = {
  dir: './app',
  name: 'YourAppName',
  platform: 'darwin',
  arch,
  overwrite: true,
  appVersion: '1.0.0',
  asar: { unpackDir: 'plugins' },
  out: './dist',
  icon: './build_resource/logo.icns'
};

// Windows
const winOptions = {
  dir: './app',
  platform: 'win32',
  arch,
  overwrite: true,
  asar: { unpackDir: 'plugins' },
  out: './dist',
  icon: './build_resource/logo.ico'
};

On macOS we set the name field directly; on Windows we rely on the productName field in app/package.json because the executable’s FileDescription determines the displayed name.

3. Code‑Signing Phase

Code signing assures users and the operating system that the binary is trustworthy.

Windows

Purchase a code‑signing certificate (e.g., from Symantec) and use signtool to sign the .exe and .msi files. The process can be wrapped in a Gulp task that runs the appropriate signtool commands for SHA‑1 and SHA‑256 signatures.

macOS

Obtain a “Developer ID Application” certificate from Apple. Use electron-osx-sign (or the codesign CLI) to sign the .app bundle and the final .dmg. Example command:

codesign --deep --force --verify --verbose \
  --sign "Developer ID Application: Your Company" \
  "MyApp.app"

4. Installer Creation

Windows – Inno Setup

Inno Setup is a mature, Unicode‑compatible installer builder used by VS Code. Create an .iss script (template filled by Gulp) and run the Inno Setup compiler. The script defines sections such as [Setup], [Files], and [Run]. You can also add a Chinese language file and Pascal scripting for advanced customisation.

macOS – appdmg

Use the appdmg Node module to generate a .dmg. The configuration includes the window title, background image, icon, and the placement of the .app bundle inside the DMG. Example:

appdmg({
  target: 'dist/MyApp.dmg',
  basepath: __dirname,
  specification: {
    title: 'MyApp',
    icon: 'MyApp.icns',
    background: 'bg.png',
    'icon-size': 96,
    window: { size: { width: 550, height: 320 } },
    contents: [
      { x: 400, y: 128, type: 'link', path: '/Applications' },
      { x: 150, y: 128, type: 'file', path: 'MyApp.app' }
    ]
  },
  'code-sign': { 'signing-identity': 'Developer ID Application: Your Company' }
});

5. Release Phase

Rename the installer files to a consistent pattern (e.g., MyApp-1.0.0-win32.exe or MyApp-1.0.0-darwin.dmg) and upload them to your chosen object storage (OSS, S3, etc.). Organise the storage by release stage (dev, alpha, beta, prod) to simplify version management and access control.

6. Gulpfile Overview

The gulpfile.js orchestrates the entire pipeline: env: Parses arguments and sets global variables. dev: Runs the app in development mode ( electron app --debug). pack: Calls electron-packager for the selected platform. sign-pack: Executes Windows or macOS signing based on the platform. build: Creates the installer (Inno Setup or appdmg). release: Renames the installer and triggers the upload script.

Package.json scripts provide shortcuts such as npm run packDev or npm run releaseProd, passing platform, architecture, and signing flags as needed.

Conclusion

With this automated workflow you can reliably turn an Electron codebase into signed, installable packages for both Windows and macOS, ready for distribution. The next step is to focus on the actual application features and possibly add auto‑update support.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

cross-platformAutomationElectronpackagingCode Signinggulp
CoolHome R&D Department
Written by

CoolHome R&D Department

Official account of CoolHome R&D Department, sharing technology and innovation.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.