Skip to main content

I'm a self-employed web developer, family man, nerd, scuba diver, and author of many fine books. Manager/maintainer of the Elgg community site, and core Elgg development team member.


Ordering by numbers is harder than it looks

You know what I mean @NHL ?


Ha! Take that, sql injection vulnerabilities!



Roadmap to web development in 2017

Sometimes I feel like an imposter "tricking" people into thinking I know what I'm doing, but then I see something like this and realize just how far down this crazy rabbit hole I've dug myself.  I've gone through a ton of learning curves over the years...

Roadmap to web development in 2017

Ionic 2 + Electron

5 min read

On a whim (as almost all my self-enforced learning curves tend to be) I decided to try getting Ionic 2 running inside of Electron.  I’ve never used Electron before, but had previously read the docs and had a vague understanding of it.  That said, I did the easy thing and googled for any ready-made solutions.  Mostly what I got were threads of people trying to get it working and either failing and giving up, or never posting again.  The few examples I found where people did get it working no longer worked at the time of this writing (Ionic 2.2.0).

After some trial and error with different suggestions cobbled together from different sources I finally got the Ionic 2 tutorial project running in Electron!  It complained about the lack of cordova.js in the console log, but that’s not technically required for the tutorial… a minor inconvenience for now.


Ionic tutorial running in electron


Note, I apologize, but I didn’t keep track of each reference/site I found nuggets of info on to get me to this point.  Just be aware that most of this was figured out by people smarter than me and I just managed to aggregate the right things in the right order to get somewhere.  Sorry if you were my source and you’re upset about not being mentioned…


Anyway, getting this far gave me hope, so I copied my considerably larger and more complicated project and got to work.

In the project root create a file "electron.copy.js"

// this is a custom dictionary to make it easy to extend/override
// provide a name for an entry, it can be anything such as 'copyAssets' or 'copyFonts'
// then provide an object with a `src` array of globs and a `dest` string

module.exports = {
  copyAssets: {
    src: ['{{SRC}}/assets/**/*'],
    dest: '{{WWW}}/assets'
  copyIndexContent: {
    src: ['{{SRC}}/index.html', '{{SRC}}/manifest.json'],
    dest: '{{WWW}}'
  copyFonts: {
    src: ['{{ROOT}}/node_modules/ionicons/dist/fonts/**/*', '{{ROOT}}/node_modules/ionic-angular/fonts/**/*'],
    dest: '{{WWW}}/assets/fonts'
  copyPolyfills: {
    src: ['{{ROOT}}/node_modules/ionic-angular/polyfills/polyfills.js'],
    dest: '{{BUILD}}'
  copySwToolbox: {
    src: ['{{ROOT}}/node_modules/sw-toolbox/sw-toolbox.js'],
    dest: '{{BUILD}}'



In the project root create a file "main.js"

const electron = require('electron');
// Module to control application life.
const app =;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;

const path = require('path');
const url = require('url');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

function createWindow () {
  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});

  // and load the index.html of the app.
    pathname: path.join(__dirname, "www/index.html"),
    protocol: "file:",
    slashes: true

  // Open the DevTools.

  // Emitted when the window is closed.
  mainWindow.on("closed", function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on("ready", createWindow);

// Quit when all windows are closed.
app.on("window-all-closed", function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== "darwin") {

app.on("activate", function () {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.


Edit package.json and add to dev dependencies:   

"electron": "^1.6.2"


  Edit package.json and change the build script

"scripts": {
    "start": "electron .",
    "clean": "ionic-app-scripts clean",
    "build": "ionic-app-scripts build",
    "electron": "ionic-app-scripts build --copy electron.copy.js",
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"

Edit package.json and add the main.js

"main": "main.js"

Install Electron and dependencies

$ npm install


Build the project

$ npm run electron

Start the application

$ npm start


and we have a working application!  I clicked around and tested a few things.  It appears to be working, making calls to the external API and getting correct responses.  Cool!



Still some things to figure out, like whether I should get cordova loaded or not, whether it will export as an app nicely, whether there is a good way to do this that can keep the codebase the same and still build for mobile/web, whether I can make this work with a browser production build… those are less interesting details though and can wait for another sleepless learning curve night.  I'll update this post if I find better ways of doing things with this.


[edit 1] - simplified issue with polyfills copying

[edit 2] - created electron-specific build command

[edit 3] - added browser platform and attempted to use browser prod build in ionic - seems to work, but my app needs work with the browser cordova implementation so not sure where issues from that vs electron start/end.

Anyway for that to work I created

ionic build browser --prod
rm -rf www/*
cp -r platforms/browser/www/* www/
npm start

This uses the browser prod build in electron, does so by building for browser prod, then copying the prod files into the local www folder before starting electron.


Kojeon - the saga continues

So Edison has been calling BS on the Christmas Kojeon card because it's a photo-realistic Kojak who is clearly lying on Nick's blanket.  Fine then smart guy, you want to play it that way?  I've got a few things you don't have.

1. Mediocre photoshop skills

2. Google Translate

3. Contacts in Japan with access to the mail system

4. An obsessive compulsion to beat a 6 year old in a battle of wits

Let's see how he reacts when he gets personalized mail from Japan with a Japanese version of Kojeon AND a Kiteon with cartoonized depictions.



git add --all
git commit -m "feature wip"
git push origin feature-branch

*power goes out*
Thank git


Remember 4 months ago when the thing that scared people most was some dumb clowns in the woods?


Hey it works! Oh wait a sec...

What if I just add/subtract a bit of a fudge factor?


BFG Repo Cleaner

This actually saved me today.

The BFG treats you like a reformed alcoholic: you've made some mistakes in the past, but now you've cleaned up your act. Thus the BFG assumes that your latest commit is a good one, with none of the dirty files you want removing from your history still in it. This assumption by the BFG protects your work, and gives you peace of mind knowing that the BFG is only changing your repo history, not meddling with the current files of your project.


BFG Repo Cleaner

Sea lion dive 01/08/2017

Went diving with the sea lions at Hornby Island yesterday.  It was good until one of them stole my light and swam off with it never to be seen again, forcing me to become an enemy of sea lions as a species.