Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot build Windows app #796

Closed
chrisveness opened this issue Oct 5, 2016 · 6 comments
Closed

Cannot build Windows app #796

chrisveness opened this issue Oct 5, 2016 · 6 comments
Labels

Comments

@chrisveness
Copy link

I'm sure there must be something simple I am missing with electron-builder / Sqiurrel.Windows; when
I open the built setup.exe file, nothing happens other than an animated splash screen. (I have
no experience of electron.builder or Squirrel.Windows, but I've been googling all I can).

I'm using Electron 1.4.2, electron-builder 7.10.2, using a two-package.json approach. The app being
built is a Koa app.

There is a very simple app which illustrates the problem on github.com/chrisveness/electron-koa-app.

My main.js is:

const { app, BrowserWindow } = require('electron'); // www.npmjs.com/package/electron
const spawn = require('child_process').spawn;       // nodejs.org/api/child_process.html
const path = require('path');                       // nodejs.org/api/path.html

let win = null; // keep global reference to window object to avoid automatic closing on JS GC

function createWindow() {
    if (handleSquirrelCommand()) return;

    console.log('createWindow');
    app.server = require('./app/app.js');                  // instantiate Koa app
    win = new BrowserWindow({ width: 1024, height: 768 }); // create browser window
    win.loadURL('http://localhost:3001');                  // load koa-app home page
    win.on('closed', () => { win = null; });               // dereference window object
}

app.on('ready', createWindow); // create window after Electron initialisation complete

app.on('window-all-closed', () => {               // quit when all windows are closed
    if (process.platform != 'darwin') app.quit(); // (except leave MacOS app active until Cmd+Q)
});

app.on('activate', () => { // re-recreate window when dock icon is clicked and no other windows open
    if (win == null) createWindow();                     
});


// qv www.npmjs.com/package/electron-windows-installer
function handleSquirrelCommand() {
    if (process.platform != 'win32') return false; // only applies to Windows (win32 is both 32- & 64-bit)

    const command = process.argv[1];
    const target = path.basename(process.execPath);

    switch (command) {
        case '--squirrel-install':
        case '--squirrel-updated':
            update(['--createShortcut=' + target + ''], app.quit);
            return true;
        case '--squirrel-uninstall':
            update(['--removeShortcut=' + target + ''], app.quit);
            return true;
        case '--squirrel-obsolete':
            app.quit();
            return true;
    }

    return false;
}

function update(args, done) {
    const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe');
    spawn(updateExe, args, { detached: true }).on('close', done);
}

It may be clear what's missing just from reviewing the code, but otherwise, to replicate,

git clone https://github.com/chrisveness/electron-koa-app.git
cd electron-koa-app
npm install

Then running

npm start

opens the app perfectly well in Electron; but if I build a distributable (on Windows) with

npm run dist

then when I open the generated dist\win\koa-hello-world Setup 0.0.0.exe, nothing happens after the
animated splash screen.

Also, if I open %LocalAppData%\koahelloworld\app-0.0.0\koahelloworld.exe, I get an EADDRINUSE
error, which doesn't happen when I run the app using npm start.

What am I missing?

@eriedl
Copy link

eriedl commented Oct 7, 2016

The main issue is that you are missing the entry point for electron into your app when it's running as a standalone build. The reason for this is that your main.js, which represents the main process, resides outside of the app directory. Only the sources in that directory are packaged unless you have a process/script in place that "assembles" all necessary sources from other locations and puts them together for the packager. The start script in the root package.json tells electron where the entrypoint is and that's why it works with npm start and not when packaged: "start": "electron main.js",.

So to fix this, you need to make the following changes:

  • Change in the root package.json the start script to: "start": "electron app/main.js",
  • Move main.js to the app/ folder
  • Change the main script in app/package.json to: "main": "main.js",
  • Ensure that you handle the Squirrel commands before your app does anything else like starting a server. That is, move if (handleSquirrelCommand()) return; to the top of your main script.
  • Change the path to your app.js in the createWindow function: app.server = require('./app.js');
  • Optional: Remove the scripts property from app/package.json. There are no scripts to run when your app is running. Your app is just launched based on what you put into the main property.
  • Optional: Ensure that your app quits when Squirrel installs it. The reason for this is that Squirrel starts the app during installation and you have to handle that. See PR for an example
  • Strongly recommended: Ensure that your app also quits properly when it crashes and cleans up any connections it might have opened. I know, easier said than done. I just had a few instances where the server would still run although the app had crashed and I had to kill the process from the task manager.
  • (I took the liberty of adding a .gitignore file)

I hope this is helpful and helps you get started with electron-builder. They've done an excellent job so far!

@develar
Copy link
Member

develar commented Oct 7, 2016

Also, consider to use NSIS target instead of Squirrel.Windows.

@chrisveness
Copy link
Author

Thanks so much for that. I was definitely mixed up about the location for main.js, but that makes sense.

I still don't understand a return statement when there's no function to return from, but it works!

I hadn't even discovered app.makeSingleInstance(), that's really good.

So it all looks good now, thanks.

@chrisveness
Copy link
Author

I was trying to look into the differences between NSIS and Squirrel.Windows, and which might be preferred, but got very lost, and assumed the default should be the best option.

Could you point me to something which gives clear info on the pros & cons? Would I put "target": "nsis" in the build section of the development package.json?

@eriedl
Copy link

eriedl commented Oct 7, 2016

Yes, you'd add "target": ["nsis"] to the win build section.

In regards to Squirrel vs. NSIS: There seem to be a few issues with Squirrel and to paraphrase @develar: "I'm tired fixing it"
See: szwacz/electron-boilerplate#172 (comment)
and the referenced issue #472 (comment)

For me a good cross-platform auto-updating functionality is more important than the actual installer. So, I'm really excited about the NSIS auto-updater (issue #529) functionality and how that will work across Mac and Windows at least. (EDIT: The electron-builder autoUpdater API I mean. I know NSIS is a Windows installer)

@chrisveness
Copy link
Author

Thanks for that guidance @eriedl. My 'hello world' trial is working, though I feel there's quite a bit of (little documented) boilerplate in main.js, and I'm not quite sure how much of it is squirrel-specific. Once I can pause for breath, I may put together another issue on the subject to reach out for a bit more advice :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants