Packaging and Deploying Your Electron Application across Platforms


GitHub's Electron platform is pretty sweet! Electron allows developers to write cross platform desktop applications using the web stack of HTML, CSS and JavaScript. If you have experience building web apps, then building desktop apps with Electron is simply an extension of what you already do on the web. You can bring in all your favorite libraries and frameworks like jQuery, Angular, Meteor, etc. without much work. And the learning curve for using Electron's Node APIs to interact with native OS resources is very small. Save for a few places, like menu creation, the APIs  provide a unified interface across the 3 supported platforms (Mac, Windows and Linux). The underlying node.js system handles the platform differences for you.

All in all, the experience of developing Electron apps is sublime. That is until you get to packaging and deployment. While development is easy, deployment is hard.

During development, to run your app you simply run the command npm start or electron app in your project folder. However, in production you cannot expect your users to clone your git / bitbucket repo, install the dependencies and launch the app via shell commands. You need to provide executables native to each platform.

The manual way of doing packaging and deployment as prescribed in the Application Distribution tutorial on GitHub is to:

  • For Windows/Linux, 
    • create a directory for the target platform (I will call this $ELECTRON_HOME)
    • get the electron executable for each target platform and place it in $ELECTRON_HOME
    • create the following directory structure under $ELECTRON_HOME:
    • place your source code (e.g. package.json, main.js, index.html, etc) inside the app directory
    • Rename the electron executable to your application's name
    • On Windows, you can edit the app icon using a tool like rcedit or ResEdit
    • On Linux, if you are targeting Debian derivatives, you'll need to create a .desktop file to set the icon and then deploy the app and .desktop file using a deploy script.
  • For Mac OS X
    • get the electron executable 
    • open up the directory by selecting "Show Package Contents" from the right-click menu and the navigate to
    • create a directory called app/ inside of Resources/
    • place your source code (e.g. package.json, main.js, index.html, etc) inside the app directory
    • rename to your application's name
    • rename the CFBundleDisplayName, CFBundleIdentifier and CFBundleName fields in following files:
    • place your custom icon (icns) file in the directory and change the value of the CFBundleIconFile field in the file
    • optionally: rename the Electron helper app's executable file's name and then the Electron itself to your application's name
These steps may not seem like much, but having to do them manually every time you want to do a build for three different platforms can get pretty tedious. And in a continuous delivery environment, this is a none starter. It would be nice if there was a way to automate this process. And there is, it's called gulp-electron.

Gulp-electron is a gulp plugin that helps to automate the creation of electron-based application executables. Once a gulp task is defined, building executables with gulp-electron is as simple as running the command gulp electron. The gulp electron command automates the process of downloading the Electron distributable for each platform specified, packaging your application within the correct directory structure, modifying all plist files as needed, setting up your application's icon, and packaging the whole shebang into zip files per platform.

Here's an example of the definition of a gulp-electron task. This code should be placed in a file called gulpfile.js in the root of your project folder.

'use strict';
/* jshint node:true */

var electron = require('gulp-electron');
var gulp = require('gulp');

var packageJson = require('./src/package.json');

process.NODE_ENV = 'test';

gulp.task('electron', function() {

        src: './src',
        packageJson: packageJson,
        release: './release',
        cache: './cache',
        version: 'v0.35.2',
        rebuild: false,
        packaging: true,
        asar: false,
        platforms: ['linux-ia32', 'linux-x64', 'win32-ia32', 'darwin-x64'],
        platformResources: {
            darwin: {
                CFBundleVersion: packageJson.version,
                icon: './resources/cheatsheet.icns'
            win: {
                "version-string": packageJson.version,
                "file-version": packageJson.version,
                "product-version": packageJson.version,
                "icon": './resources/cheatsheet.ico'

gulp.task('default', ['electron']);

For a detailed explanation of what each property means; checkout the gulp-electron

A couple of things to note about gulp-electron as of the time of this writing are:
  1. Your application code needs to be in source folder under the project root. The source folder can be called anything (typically 'src'). It lets gulp-electron know what needs to be distributed to
  2.  The cache folder is where the platform specific distributables are downloaded to and the release folder is where your packaged application is created in. These folders should not be checked into version control. If you are using git you'll want to add them to your .gitignore file.
  3. Creation of the custom application icon for windows did not work for me. I'm investigating this and I'll update this post when I have some new information. If anyone has had success with it please let me know in the comments.
  4. At this time, there isn't support for signing an application for distribution in the Mac App Store. Check out the Mac App Store Submission Guide for details on how to do this.

For further reference on packaging and deployment with gulp-electron, check out my Cheat Sheet project on GitHub.

You Might Also Like