Electron Adventures: Episode 3: What Can Backend Code Even Do?

Let's do something that frontend code can't do on its own - run shell commands.

Run a single command

Electron on the backend is basically node process, with some extras for communicating with the browser.

Now it would much prefer you to use complicated async system with proper error handling and so on, but we don't need this complexity - we'll just use child_process.execSync to run a command and capture its output.

We need to do two small things with the result. First we need to convert Buffer into String - this isn't done automatically, as the output could be some binary like an image, not a valid UTF-8 String. And then we'll trim extra newline.

let child_process = require("child_process")

let runCommand = (command) => {
  return child_process.execSync(command).toString().trim()
}

Gather information about operating system

Let's run a bunch of random commands to get system information

let sysInfo = {
  os: runCommand("uname -s"),
  cpu: runCommand("uname -m"),
  hostname: runCommand("hostname -s"),
  ip: runCommand("ipconfig getifaddr en0"),
}

Ship this information to the frontend

We can now ship this information to the frontend. There are many more complex ways, and we'll absolutely get there, but for now, let's jut use the simplest one and pass a query string.

Weirdly Javascript still doesn't have a way to turn an Object into a query string, so we'll need to roll our own!

let toQueryString = (obj) => {
  let q = []
  for (let key in obj) {
    q.push(`${encodeURIComponent(key)}=${encodeURIComponent(obj[key])}`)
  }
  return q.join("&")
}

We used loadFile function before, but that doesn't have any easy way of passing an query string. But we can do a little trick, and use loadURL with file: protocol instead.

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

function createWindow() {
  let win = new BrowserWindow({})
  win.maximize()
  win.loadURL(`file:${__dirname}/index.html?${toQueryString(sysInfo)}`)
}

app.on("ready", createWindow)

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

Parse this on the frontend

Javascript has a way to parse a query string, but it's not very convenient. But let's give it a go the hard way with just browser APIs:

let data = new URLSearchParams(document.location.search)

let info = document.querySelector("#info")

for (const [key, value] of data) {
  let p = document.createElement("p")
  p.append(`${key} = ${value}`)
  info.append(p)
}

We absolutely do not want to be writing bigger apps this way of course, so we'll get to using libraries soon.

For now let's just add this simple HTML, and we have a simple app:

<!DOCTYPE html>
<html>
  <body>
    <h1>System information!</h1>
    <div id="info"></div>
    <script src="app.js"></script>
  </body>
</html>

The result

And here's what we got:

electron-adventures-03-screenshot.png

All the code for the episode is here.

See you in the next episode!