1 | # Electron Installer
|
2 |
|
3 | [![AppVeyor Build status](https://ci.appveyor.com/api/projects/status/bq6c06suq5abb66s/branch/master?svg=true)](https://ci.appveyor.com/project/electron-bot/windows-installer/branch/master)
|
4 | [![CircleCI](https://circleci.com/gh/electron/windows-installer.svg?style=svg)](https://circleci.com/gh/electron/windows-installer)
|
5 |
|
6 | NPM module that builds Windows installers for
|
7 | [Electron](https://github.com/electron/electron) apps using
|
8 | [Squirrel](https://github.com/Squirrel/Squirrel.Windows).
|
9 |
|
10 | ## Installing
|
11 |
|
12 | ```sh
|
13 | npm install --save-dev electron-winstaller
|
14 | ```
|
15 |
|
16 | ## Usage
|
17 |
|
18 | Require the package:
|
19 |
|
20 | ```javascript
|
21 | const electronInstaller = require('electron-winstaller');
|
22 | ```
|
23 |
|
24 | Then do a build like so..
|
25 |
|
26 | ```javascript
|
27 | // NB: Use this syntax within an async function, Node does not have support for
|
28 | // top-level await as of Node 12.
|
29 | try {
|
30 | await electronInstaller.createWindowsInstaller({
|
31 | appDirectory: '/tmp/build/my-app-64',
|
32 | outputDirectory: '/tmp/build/installer64',
|
33 | authors: 'My App Inc.',
|
34 | exe: 'myapp.exe'
|
35 | });
|
36 | console.log('It worked!');
|
37 | } catch (e) {
|
38 | console.log(`No dice: ${e.message}`);
|
39 | }
|
40 | ```
|
41 |
|
42 | After running you will have an `.nupkg`, a
|
43 | `RELEASES` file, and a `.exe` installer file in the `outputDirectory` folder
|
44 | for each multi task target given under the config entry.
|
45 |
|
46 | There are several configuration settings supported:
|
47 |
|
48 | | Config Name | Required | Description |
|
49 | | --------------------- | -------- | ----------- |
|
50 | | `appDirectory` | Yes | The folder path of your Electron app |
|
51 | | `outputDirectory` | No | The folder path to create the `.exe` installer in. Defaults to the `installer` folder at the project root. |
|
52 | | `loadingGif` | No | The local path to a `.gif` file to display during install. |
|
53 | | `authors` | Yes | The authors value for the nuget package metadata. Defaults to the `author` field from your app's package.json file when unspecified. |
|
54 | | `owners` | No | The owners value for the nuget package metadata. Defaults to the `authors` field when unspecified. |
|
55 | | `exe` | No | The name of your app's main `.exe` file. This uses the `name` field in your app's package.json file with an added `.exe` extension when unspecified. |
|
56 | | `description` | No | The description value for the nuget package metadata. Defaults to the `description` field from your app's package.json file when unspecified. |
|
57 | | `version` | No | The version value for the nuget package metadata. Defaults to the `version` field from your app's package.json file when unspecified. |
|
58 | | `title` | No | The title value for the nuget package metadata. Defaults to the `productName` field and then the `name` field from your app's package.json file when unspecified. |
|
59 | | `name` | No | Windows Application Model ID (appId). Defaults to the `name` field in your app's package.json file. |
|
60 | | `certificateFile` | No | The path to an Authenticode Code Signing Certificate |
|
61 | | `certificatePassword` | No | The password to decrypt the certificate given in `certificateFile` |
|
62 | | `signWithParams` | No | Params to pass to signtool. Overrides `certificateFile` and `certificatePassword`. |
|
63 | | `iconUrl` | No | A URL to an ICO file to use as the application icon (displayed in Control Panel > Programs and Features). Defaults to the Atom icon. |
|
64 | | `setupIcon` | No | The ICO file to use as the icon for the generated Setup.exe |
|
65 | | `skipUpdateIcon` | No | Disables setting the icon of `Update.exe`. This can solve installation errors with the following message: "This application could not be started", when the setup is built on a non-Windows system. |
|
66 | | `setupExe` | No | The name to use for the generated Setup.exe file |
|
67 | | `setupMsi` | No | The name to use for the generated Setup.msi file |
|
68 | | `noMsi` | No | Should Squirrel.Windows create an MSI installer? |
|
69 | | `noDelta` | No | Should Squirrel.Windows delta packages? (disable only if necessary, they are a Good Thing) |
|
70 | | `remoteReleases` | No | A URL to your existing updates. If given, these will be downloaded to create delta updates |
|
71 | | `remoteToken` | No | Authentication token for remote updates |
|
72 | | `frameworkVersion` | No | Set the required .NET framework version, e.g. `net461` |
|
73 |
|
74 | ## Sign your installer or else bad things will happen
|
75 |
|
76 | For development / internal use, creating installers without a signature is okay, but for a production app you need to sign your application. Internet Explorer's SmartScreen filter will block your app from being downloaded, and many anti-virus vendors will consider your app as malware unless you obtain a valid cert.
|
77 |
|
78 | Any certificate valid for "Authenticode Code Signing" will work here, but if you get the right kind of code certificate, you can also opt-in to [Windows Error Reporting](http://en.wikipedia.org/wiki/Windows_Error_Reporting). [This MSDN page](http://msdn.microsoft.com/en-us/library/windows/hardware/hh801887.aspx) has the latest links on where to get a WER-compatible certificate. The "Standard Code Signing" certificate is sufficient for this purpose.
|
79 |
|
80 | ## Handling Squirrel Events
|
81 |
|
82 | Squirrel will spawn your app with command line flags on first run, updates,
|
83 | and uninstalls. it is **very** important that your app handle these events as _early_
|
84 | as possible, and quit **immediately** after handling them. Squirrel will give your
|
85 | app a short amount of time (~15sec) to apply these operations and quit.
|
86 |
|
87 | The [electron-squirrel-startup](https://github.com/mongodb-js/electron-squirrel-startup) module will handle
|
88 | the most common events for you, such as managing desktop shortcuts. Add the following to the top
|
89 | of your `main.js` and you're good to go:
|
90 |
|
91 | ```javascript
|
92 | if (require('electron-squirrel-startup')) return;
|
93 | ```
|
94 |
|
95 | You should handle these events in your app's `main` entry point with something
|
96 | such as:
|
97 |
|
98 | ```javascript
|
99 | const app = require('app');
|
100 |
|
101 | // this should be placed at top of main.js to handle setup events quickly
|
102 | if (handleSquirrelEvent()) {
|
103 | // squirrel event handled and app will exit in 1000ms, so don't do anything else
|
104 | return;
|
105 | }
|
106 |
|
107 | function handleSquirrelEvent() {
|
108 | if (process.argv.length === 1) {
|
109 | return false;
|
110 | }
|
111 |
|
112 | const ChildProcess = require('child_process');
|
113 | const path = require('path');
|
114 |
|
115 | const appFolder = path.resolve(process.execPath, '..');
|
116 | const rootAtomFolder = path.resolve(appFolder, '..');
|
117 | const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
|
118 | const exeName = path.basename(process.execPath);
|
119 |
|
120 | const spawn = function(command, args) {
|
121 | let spawnedProcess, error;
|
122 |
|
123 | try {
|
124 | spawnedProcess = ChildProcess.spawn(command, args, {detached: true});
|
125 | } catch (error) {}
|
126 |
|
127 | return spawnedProcess;
|
128 | };
|
129 |
|
130 | const spawnUpdate = function(args) {
|
131 | return spawn(updateDotExe, args);
|
132 | };
|
133 |
|
134 | const squirrelEvent = process.argv[1];
|
135 | switch (squirrelEvent) {
|
136 | case '--squirrel-install':
|
137 | case '--squirrel-updated':
|
138 | // Optionally do things such as:
|
139 | // - Add your .exe to the PATH
|
140 | // - Write to the registry for things like file associations and
|
141 | // explorer context menus
|
142 |
|
143 | // Install desktop and start menu shortcuts
|
144 | spawnUpdate(['--createShortcut', exeName]);
|
145 |
|
146 | setTimeout(app.quit, 1000);
|
147 | return true;
|
148 |
|
149 | case '--squirrel-uninstall':
|
150 | // Undo anything you did in the --squirrel-install and
|
151 | // --squirrel-updated handlers
|
152 |
|
153 | // Remove desktop and start menu shortcuts
|
154 | spawnUpdate(['--removeShortcut', exeName]);
|
155 |
|
156 | setTimeout(app.quit, 1000);
|
157 | return true;
|
158 |
|
159 | case '--squirrel-obsolete':
|
160 | // This is called on the outgoing version of your app before
|
161 | // we update to the new version - it's the opposite of
|
162 | // --squirrel-updated
|
163 |
|
164 | app.quit();
|
165 | return true;
|
166 | }
|
167 | };
|
168 | ```
|
169 |
|
170 | Notice that the first time the installer launches your app, your app will see a `--squirrel-firstrun` flag. This allows you to do things like showing up a splash screen or presenting a settings UI. Another thing to be aware of is that, since the app is spawned by squirrel and squirrel acquires a file lock during installation, you won't be able to successfully check for app updates till a few seconds later when squirrel releases the lock.
|
171 |
|
172 | ## Debugging this package
|
173 |
|
174 | You can get debug messages from this package by running with the environment variable `DEBUG=electron-windows-installer:main` e.g.
|
175 |
|
176 | ```shell
|
177 | DEBUG=electron-windows-installer:main node tasks/electron-winstaller.js
|
178 | ```
|