DEV Community

Tomasz Wegrzanowski
Tomasz Wegrzanowski

Posted on

Electron Adventures: Episode 78: Cookie Clicker Game Packaging

In previous episode we created a simple static Cookie Clicker game app. Let's now package it into a standalone app.

There are a few different packagers for Electron. In this episode we'll try Electron Forge.

Install and run import

$ npm install --save-dev @electron-forge/cli
$ npx electron-forge import
Enter fullscreen mode Exit fullscreen mode

Electron Forge comes with an import tool that tries to import an existing app.

We ran into some problems right away:

  • Please set the "version" in your application's package.json - I guess that would be useful for naming the package
  • Error: Unable to find all properties in parent package.json files. Missing props: ["productName","name"] - and same here
  • Error: packageJSON.main must be set to a valid entry point for your Electron app - Electron defaults to index.js if you don't specify it, but Electron Forge need it spelled out explicitly

So reset the process, fix those issues so package.json looks like below, and try again:

{
  "name": "episode-78-cookie-clicker-game-package",
  "version": 0.78,
  "main": "index.js",
  "devDependencies": {
    "electron": "^15.1.1",
    "jquery": "^3.6.0"
  },
  "scripts": {
    "start": "electron ."
  }
}
Enter fullscreen mode Exit fullscreen mode

That actually built the package, but it still didn't work.

The next few issues I needed to fix:

  • I accidentally put version as 0.78 not "0.78" and that led to some extremely baffling and completely ungooglable errors
  • jquery must be in dependencies not devDependencies, or it won't be bundled. While developing it makes no difference, but it decides what's going to get packaged and what won't.
  • I needed to do some tweaks to index.js to use relative path. I also included some boilerplate that supposedly fixes Windows shortcuts, as examples had it.

So after a few iterations between myself and the importer I got to this package.json:

{
  "name": "episode-78-cookie-clicker-game-package",
  "version": "0.78",
  "main": "src/index.js",
  "devDependencies": {
    "@electron-forge/cli": "^6.0.0-beta.61",
    "@electron-forge/maker-deb": "^6.0.0-beta.61",
    "@electron-forge/maker-rpm": "^6.0.0-beta.61",
    "@electron-forge/maker-squirrel": "^6.0.0-beta.61",
    "@electron-forge/maker-zip": "^6.0.0-beta.61",
    "electron": "^15.1.1"
  },
  "scripts": {
    "start": "electron-forge start",
    "package": "electron-forge package",
    "make": "electron-forge make"
  },
  "dependencies": {
    "electron-squirrel-startup": "^1.0.0",
    "jquery": "^3.6.0"
  },
  "config": {
    "forge": {
      "packagerConfig": {},
      "makers": [
        {
          "name": "@electron-forge/maker-squirrel",
          "config": {
            "name": "episode_78_cookie_clicker_game_package"
          }
        },
        {
          "name": "@electron-forge/maker-zip",
          "platforms": [
            "darwin"
          ]
        },
        {
          "name": "@electron-forge/maker-deb",
          "config": {}
        },
        {
          "name": "@electron-forge/maker-rpm",
          "config": {}
        }
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

I also moved the source code to src folder and adjusted imports accordingly.

Here's final src/index.js:

let { app, BrowserWindow } = require("electron")

// Handle creating/removing shortcuts on Windows when installing/uninstalling.
if (require("electron-squirrel-startup")) {
  app.quit()
}

function createWindow() {
  let win = new BrowserWindow({
    webPreferences: {
      preload: `${__dirname}/preload.js`,
    },
  })
  win.loadFile(`${__dirname}/index.html`)
}

app.on("ready", createWindow)

app.on("window-all-closed", () => {
  app.quit()
})
Enter fullscreen mode Exit fullscreen mode

The actual app is just as before.

Results

Here's the results:

Episode 78 Screenshot A

Episode 78 Screenshot B

The whole process was very finicky and with very poor error feedback, but in the end it wasn't too bad. In the next episode we'll setup some more complex SPA app, then we'll try to package that.

As usual, all the code for the episode is here.

Discussion (0)