Electron + AngularJS - Adding automatic updates

Update: Stuff changed, so I've wrote a series on implementing auto-update with Squirrel.

This is third part of introduction series to create application with Electron and AngularJS.

If you've missed, first create sample application.

One of the requirement for developing desktop application nowadays is ability to provide automatic updates.

Let me tell you a story...

I used NW.js for some time, but I missed this functionality. I went on to see how's Electron doing on that front and found that there is an awesome project in motion to provide those updates - electron-updater.

First thing I found problematic is that repository version of electron-updater is not working for me. It was build with previous Electron in mind, and kept that way. I understand it since Electron is still in active development and is expected to change. So I had to dig in and patch it up myself to work with recent version of Electron.

I also had problems running Sinopia, so avoid some headaches by reading this.

In a nutshell...

So basically electron-updater is using npm infrastructure to organise and fetch your packages and binaries. It is using .npmrc to read url of npm registry (if not present it will default to registry.npmjs.org). It will check to see if there is newer version of package, and if there is, it will download it and apply update on next start.

Sinopia

The idea here is to pack your application files (html, js) and push it in repository. Application should fetch this new version and update it on next start. Sinopia is neat private npm repository which you can run locally. It will also proxy all of the things from official repo. So...

npm install sinopia -g  

Once installed, you can pop up new tab in terminal and run:

sinopia  

This will start Sinopia. Verify that all is working by opening it in browser: http://localhost:4873/.

One thing to remember is to add user so that you'll push your application to it:

npm adduser --registry http://localhost:4873  

Add your username, password and email. With this you can go to browser and log in to get list of your packages.

Setting up .npmrc

If you run...

npm set registry http://localhost:4873  

...it will add registry info to your .npmrc in home directory. And it's ok for developing with NodeJS or running npm command from wherever, but doesn't work with Electron app, specifically electron-updater. Internally, electron-updater is reading content of .npmrc in your project directory and looking for registry url, so we'll put path there as well.

So in your project directory create .npmrc and paste:

; Use Sinopia server
registry=http://localhost:4873

; Empty certificate for use with private NPM repo
ca=  

Check out Sinopia supported features here.

Add electron-updater

Now that we have Sinopia running, we'll use it to install updated version of electron-updater (my patched version instead of one found on npm registry).

Grab the code from my fork. Go to electron-updater root directory and run:

npm pack  
npm publish  

First command should create npm package with all the files needed for electron-updater to work. Second command should publish it to Sinopia. Make sure that Sinopia is running and that your registry is set to be Sinopia server. You can navigate to Sinopia server in browser and verify that you have electron-updater package there.

If all is ok, continue to install electron-updater and its tools:

npm install electron-updater --save  
npm install electron-plugins --save  
npm install electron-updater-tools -g  

So, we're ready to add updater to our code. In main.js:

const updater = require('electron-updater');

updater.on('ready', function() {  
});

updater.on('update-required', function() {  
    app.quit();
});

updater.on('update-available', function() {  
});

updater.start();  

There are couple of events that updater is dispatching and you can (should) react on them:

  • ready - Updater has checked application dependencies and plugins and is good to go, so you would start your application here.
  • update-required - Updater detected that some dependencies or plugins are missing which prevents application from running. Application should quit so that these updates are fetched.
  • update-available - Some plugins or dependencies have newer versions available. You could notify user about it here.

Finally we have to call start() method to run the updater.

If we put it all together (code comments removed):

const electron = require('electron');  
const app = electron.app;  
const BrowserWindow = electron.BrowserWindow;  
const updater = require('electron-updater');

var mainWindow = null;

app.on('window-all-closed', function() {  
    app.quit();
});

app.on('ready', function() {

    updater.on('ready', function() {

        mainWindow = new BrowserWindow({
            name: "ea-todo",
            width: 400,
            height: 600,
            toolbar: false
        });

        mainWindow.loadURL('file://' + __dirname + "/app/index.html");

        mainWindow.on('closed', function() {
            mainWindow = null;
        });

    });

    updater.on('update-required', function() {
        app.quit();
    });

    updater.on('update-available', function() {
        if(mainWindow) {
            mainWindow.webContents.send('update-available');
        }
    });

    updater.start();

});

If you run your app now, it won't work properly. That's because we don't have application package published and updater cannot fetch anything. We'll have to do the same thing like we did with electron-updater - publish npm package.

In project root dir, run once again:

npm pack  
npm publish  

That's it!

You have your automatic updates. When you update your package.json version number you should pack and publish it so that older versions can get this as an update. This is not production ready code of course, but it should give you general image of how things are working.

By using electron-updater not only your app is "updateable", but also you could break it down or extract some code to plugins which can be maintained and updated separately. For more info check electron-plugins.

Finally, read how to properly package and build your application.

About Vjekoslav Ratkajec

Software developer from Zagreb, Croatia. Love programming, running, hiking and biking. Adore nature and animals. Also author of this blog.

Comments