Progressive Web App and Electron architecture

If you’re wondering why Slack for Desktop looks so similar to slack.com, look no further than Electron. Described as a way to “build cross platform desktop apps with JavaScript, HTML, and CSS”, it’s another step towards the unification of the web and desktop environments.

A Progressive Web App inside Electron.

At Euphoric Adventures, we’re building Euphoria, a Progressive Web App, and packaging it with Electron to create an experience that rocks from iPhone to Google Chrome to OS X. Today I want to talk about how we made it happen and provide some architecture guidance which will make your own cross platform journey easier.

Step 1: Make a Progressive Web App

Progressive Web Apps (PWA) are apps that blur the boundary between the web and native environments. Although there’s no formal definition of what makes a web app progressive, if you meet these criteria we’d happily give you the PWA badge:

Responsive

Make your web app work well and look nice on any screen size by making it responsive. This is best achieved by styling “mobile first” and then adding more style definitions for bigger screens with media queries. For example, hamburger navigation can be fully expanded on load when there’s more screen real estate; images will not be full width and so on.

Offline first

As well as styling “mobile first”, “offline first” is a must for any PWA. This means that the majority of your web app should be usable without an Internet connection, just like good native apps.

You can do this with self-concocted Service Worker code which caches web requests, or if you follow our suggested architecture, everything that Webpack outputs can be safely cached and you can use offline-plugin which backs up Service Workers with the older AppCache method to support iOS. Nice!

Fast and native-feeling

This is pretty vague, but your web app needs to be fast and feel like the native apps you use every day.

Being “offline first” will be a huge first step, avoiding costly new page loads on open. Using something like ui-router will transform the costly page load navigations of 2010 into 2017 ‘state transitions’, using HTML5’s History API to let the user move backwards and forwards as if real pages were visited.

Using a component library like Angular Material will give your UI a native feel and also save significant design and development time.

Step 2: Bundle with Webpack

JavaScript is hot and the tooling is the best the world’s ever seen. Webpack has taken over the world as the de facto bundler and makes it a breeze to package up your PWA as an Electron app. Plugins like offline-plugin, svg-inline-loader and PostCSS Autoprefixer simply reduce the development time and make developers happy. We’d need compelling reasons not to use Webpack.

Step 3: Understand life with Electron

If you’re using Webpack, you get a single directory output of your web app; probably a dist directory.

Before we go ahead and package this directory up with Electron, let me be clear about two ‘drawbacks’:

Accessibility

Most developers have never used system level accessibility features. The advantage of any native app is that accessibility features and tools can easily understand the app’s structure: it’s easy to know a button’s a button (and thus an action) because the button is a real native button. By default, Electron apps don’t have it this easy. Researching how to make accessible web apps is really important! Here are my very limited top tips:

  1. Use semantic elements like <section> and <nav>
  2. Use ARIA attributes to provide semantics where they’re not obvious
  3. Correctly log navigation through routing so the back button works, instead of using jQuery or ng-if (and so on) to provide a user journey
  4. Try a screen reader! Guidance will only go so far. Try and complete your app’s critical path with a screen reader to understand your users’ needs.

Size and Memory

Electron includes a modified copy of the Chromium runtime. This makes even small apps have a significant file size and memory needs. If your users’ machines have a hard time maintaining a lot of Google Chrome tabs, they are going to struggle running your Electron app.

Step 4: Use Electron

Let’s clone a ‘getting started’ repo for our Electron project (side note: I’m a big believer in mono repos so you know the complete state of your project and stack at any given time, but this is your decision).

git clone git@github.com:EpsilonData/electron-getting-started.git;
cd electron-getting-started.git;
npm install;

Let’s get the code running:

npm start;
Our app is running on OS X and looks native!

The repo contains a src directory and within this you’ll see a dist-frontend directory and index.js file.

dist-frontend is the code of your progressive web app that you’re packaging up with Electron. I checked this directory into source control so you could get started, but I encourage you to .gitignore this directory and as part of your build process, copy your PWA’s Webpack dist directory to here. As long as it contains Webpack’s generatedindex.html and the rest, everything will be fine.

index.js is where the magic happens. Let’s take a dive.

You’ll see Electron getting required:

const electron = require('electron')

You’ll see some basic configuration like window size:

const windowSize = [420, 768]
const windowResizable = false
const openDevTools = false
// ...
mainWindow = new electron.BrowserWindow(
{
width: windowSize[0],
height: windowSize[1],

And you’ll see the line that loads your web app:

mainWindow.loadURL(`file://${__dirname}/dist-frontend/index.html`)

Experiment with the rest of the code in index.js — you’ll see some ‘media key’ handling which comes from Euphoria itself. Later we’ll write about how to communicate between Electron and the PWA within it — media key control is a good example.

I’ve included an npm build script too which should give you some mileage towards packaging your Electron app up for distribution:

npm run build

Take a look in the dist directory now — it’s full of goodies.

electron-getting-started.app is a real OS X application you can open like this:

open dist/electron-getting-started.app

electron-getting-started.exe contains a real Windows application you can run. And that’s it!

Euphoria as a PWA and Electron app

Euphoria is a PWA app that works across all modern browsers as well as on Android and iOS. Our optimisations and tweaks to create a native feel on iOS have been minimal — the best is yet to come. With some love and care, you could get an Electron-packaged PWA that looks like this:

They know it’s Christmas now.

Summary

  1. Progressive Web Apps are awesome — let’s make more
  2. Webpack outputs a dist directory which is perfect for Electron
  3. Electron does the heavy lifting of making “native” apps, but watch out for performance and accessibility
  4. Providing a progressive web app and a native app is the way to your users’ hearts ❤