Shipping an app means packaging it, building installers for each operating system, code signing, and providing updates. This chapter walks through that with Electron Forge, then covers auto-updates and electron-builder.
Forge in three steps: package, make, publish
Electron Forge splits distribution into three steps.
# 1. Build a runnable app for the current platform under out/
npm run package
# 2. Build installers with the configured makers under out/make/
npm run make
# 3. Upload the installers to a target such as GitHub Releases
npm run publish
During package, your app code is bundled into a single ASAR archive by default, which speeds up installs and reads. ASAR is not encryption, so never ship secrets inside your app.
Makers generally run on their target platform (a DMG is built on macOS), so CI pipelines usually run one job each on Windows, macOS, and Linux.
Code signing and notarization
Operating systems warn about or block unsigned apps, so sign every build you ship.
- macOS: join the Apple Developer Program, sign with a Developer ID certificate, and submit the app to Apple's notarization service. Gatekeeper blocks apps that are not notarized.
- Windows: sign with an Authenticode certificate. Its private key now often has to live in a hardware security module or a cloud signing service, so match your setup to Forge's Windows signing options.
In Forge, signing and notarization go in packagerConfig, with secrets passed through environment variables.
// forge.config.js
module.exports = {
packagerConfig: {
asar: true,
icon: 'assets/icon', // without an extension, the right .ico or .icns is picked per platform
osxSign: {},
osxNotarize: {
appleId: process.env.APPLE_ID,
appleIdPassword: process.env.APPLE_PASSWORD, // an app-specific password
teamId: process.env.APPLE_TEAM_ID,
},
},
makers: [
{
name: '@electron-forge/maker-squirrel',
config: {
certificateFile: './cert.pfx',
certificatePassword: process.env.CERTIFICATE_PASSWORD,
},
},
{ name: '@electron-forge/maker-dmg', config: {} },
{ name: '@electron-forge/maker-deb', config: {} },
],
publishers: [
{
name: '@electron-forge/publisher-github',
config: {
repository: { owner: 'my-org', name: 'my-app' },
prerelease: true,
},
},
],
}
The GitHub publisher creates releases using the token in the GITHUB_TOKEN environment variable. The Fuses plugin (@electron/fuses) included in Forge templates hardens the app by switching off features such as ELECTRON_RUN_AS_NODE at package time.
Auto-updates
Electron's built-in, Squirrel-based autoUpdater supports macOS and Windows. On Linux, updates usually come through the package manager or a self-updating format such as AppImage.
For open-source apps that publish releases to a public GitHub repository, the simplest option is the update-electron-app package, which uses the free update.electronjs.org service. On macOS the app must be signed for updates to work.
// main.js
const { updateElectronApp } = require('update-electron-app')
updateElectronApp() // checks at startup and periodically afterwards
If you run your own update server, point autoUpdater at its feed URL.
const { app, autoUpdater } = require('electron')
const server = 'https://updates.example.com'
autoUpdater.setFeedURL({ url: `${server}/update/${process.platform}/${app.getVersion()}` })
// In a real app, ask the user before restarting
autoUpdater.on('update-downloaded', () => autoUpdater.quitAndInstall())
app.whenReady().then(() => autoUpdater.checkForUpdates())
electron-builder
electron-builder is a popular alternative to Forge. One configuration file covers installer formats, code signing, and auto-updates through electron-updater.
npm install --save-dev electron-builder
npx electron-builder --win # Windows: NSIS installer
npx electron-builder --mac # macOS: DMG (run on macOS)
npx electron-builder --linux # Linux: AppImage and others
# electron-builder.yml
appId: com.example.myapp
productName: My App
directories:
output: dist
files: ["main.js", "preload.js", "index.html", "renderer.js"]
mac:
target: dmg
win:
target: nsis
linux:
target: AppImage
publish:
provider: github
// Auto-updates for an app distributed with electron-builder
const { app } = require('electron')
const { autoUpdater } = require('electron-updater')
app.whenReady().then(() => autoUpdater.checkForUpdatesAndNotify())
Forge and electron-builder solve the same problem in different ways; pick one per project.
Summary
- Forge bundles the app with
package, builds installers with make, and uploads them with publish. - Choose installer formats with makers, and build each platform on its own operating system.
- macOS needs signing and notarization, Windows needs Authenticode signing, and secrets belong in environment variables.
- Implement auto-updates with
update-electron-app, the built-in autoUpdater, or electron-builder's electron-updater.
Official documentation
0 comments
Sign in · Sign in to leave a comment.