Electron with Serialport

Javascript and Typescript have made a huge impact on the software development industry in the current world. Electron is a trending framework for desktop applications because it is using Node and Chromium web-engine. And it uses javascript and typescript for programming.

In this article, I’m going to explain how to use the serial port with Electron and how to solve errors.

Start a new Electron project

Since this is my first article on Electron installation, I’ll include how to create an Electron + Typescript project with npm or yarn from the scratch. Please note that this guide is continuing with npm after the Electron project creation.

First of all, you need to create a new folder and change directory into the newly created folder.

$ mkdir serial-test
$ cd serialTest

Then run the init command from your package manager to init a new node project.

[TABS_R id=575]

Now install electron package as a dev dependency.

[TABS_R id=577]

I’m going to use typescript in this guide, so install the required packages for typescript.

[TABS_R id=579]

Now create a new file named tsconfig.json in the root directory and enter the following configurations in it.

[TABS_R id=582]

Now let’s create the required build and start scripts in the package.json file.

[TABS_R id=581]

Now your package.json will look like something like follows. Insert any missing part to your package.json from the below.

[TABS_R id=589]

Next, create the index.html file in the root directory with the following content.

<!DOCTYPE html>
<html>
  <head>
    <metacharset="UTF-8"/>
    <title>Hello World!</title>
    <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
    <metahttp-equiv="Content-Security-Policy"content="default-src 'self'; script-src 'self'"/>
    <metahttp-equiv="X-Content-Security-Policy"content="default-src 'self'; script-src 'self'"/>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using Node.js <span id="node-version"></span>, Chromium
    <spanid="chrome-version"></span>, and Electron
    <spanid="electron-version"></span>.
    <!-- You can also require other files to run in this process -->
    <scriptsrc="./dist/renderer.js"></script>
  </body>
</html>

Now create a folder named src in the root directory. Then create a file named preload.ts in the src directory and enter the following code in it.

// All of the Node.js APIs are available in the preload process.
// It has the same sandbox as a Chrome extension.
window.addEventListener("DOMContentLoaded", () => {
  const replaceText = (selector: string, text: string) => {
    const element = document.getElementById(selector);
    if (element) {
      element.innerText = text;
    }
  };

  for (const type of ["chrome", "node", "electron"]) {
    replaceText(`${type}-version`, process.versions[type as keyof NodeJS.ProcessVersions]);
  }
});

Now create a file named main.ts in the src directory and insert the following code in it.

import { app, BrowserWindow } from "electron";
import * as path from "path";

function createWindow() {
  // Create the browser window.
  const mainWindow = new BrowserWindow({
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, "preload.js"),
    },
    width: 800,
  });

  // and load the index.html of the app.
  mainWindow.loadFile(path.join(__dirname, "../index.html"));

  // Open the DevTools.
  mainWindow.webContents.openDevTools();
}

// 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();

  app.on("activate", function () {
    // On macOS 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 (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

// Quit when all windows are closed, except on macOS. There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
  if (process.platform !== "darwin") {
    app.quit();
  }
});

// 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.

Then create a file named renderer.ts in the src directory.

Everything is done. Now run the start command.

[TABS_R id=586]

Install Serial Port

Use the following commands to install serialport package and the type definitions.

$ npm i serialport
$ npm i -D @types/serialport

Now import SerialPort to main.ts and initialize a new port.

import SerialPort from 'serialport'
const port = new SerialPort('/dev/ttyACM0', { baudRate: 115200 })

Now run the start command

$ npm run start

You should get an error message something like below.

A JavaScript error occurred in the main process
Uncaught Exception:
Error: The module '/xxx/serial-npm/node_modules/@serialport/bindings/build/Release/bindings.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 93. This version of Node.js requires
NODE_MODULE_VERSION 98. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).
    at process.func [as dlopen] (node:electron/js2c/asar_bundle:5:1800)
    at Object.Module._extensions..node (node:internal/modules/cjs/loader:1170:18)
    at Object.func [as .node] (node:electron/js2c/asar_bundle:5:1800)
    at Module.load (node:internal/modules/cjs/loader:982:32)
    at Module._load (node:internal/modules/cjs/loader:823:12)
    at Function.c._load (node:electron/js2c/asar_bundle:5:13331)
    at Module.require (node:internal/modules/cjs/loader:1006:19)
    at require (node:internal/modules/cjs/helpers:93:18)
    at bindings (/xxx/serial-npm/node_modules/bindings/bindings.js:112:48)
    at Object. (/xxx/serial-npm/node_modules/@serialport/bindings/lib/linux.js:2:36)

The problem is that some bindings required for the serialport package are compiled against an old version of the node. So we need to recompile the serialport package.

For that first we need to install electron-rebuild package as a dev dependancy.

$ npm i -D electron-rebuild

Then add the following script to your scripts in the package.json file.

"rebuild": "electron-rebuild -f -w serialport"

Then your scripts in the package.json will looks something like below.

"scripts": {
  "build": "tsc",
  "start": "npm run build && electron ./dist/main.js",
  "rebuild": "electron-rebuild -f -w serialport"
}

So now the rebuild script is ready. We just need to execute it.

$ npm run rebuild

Then you’re free to execute the project. It should run without any error.

So that’s it

If you have any suggestions or questions about this guide, comment here or send me an email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top