DEV Community

asaf g
asaf g

Posted on • Originally published at turtle-techies.com on

Multi Platform Desktop App With Electron

Written by Andres Acevedo

Slack, Visual Studio Code, and Skype among others have shown us that writing performant eye-catching multi-platform apps with web technologies is not only possible but that they can compete with apps made using different frameworks as native libraries or Java.

Today we will create a basic app that allows reading a text file into a text area.

This functionality is at the core of several apps like word processors, and code editors among others.

Pre Requisites

A solid understanding of how HTML, CSS, and Javascript work together on a web page.

Ability to code on Javascript.

Node and Npm (or Yarn installed).

Know how to install node packages.

Installing Electron

Run

npm init
Enter fullscreen mode Exit fullscreen mode

to initialize a new node application and fill the information requested in the terminal.

Then run

npm install --save-dev electron
Enter fullscreen mode Exit fullscreen mode

Hello Electron

Now we will create a basic app that displays "Hello Electron" just to see the electron framework working.

Create a new main.js file and write the following on it:

// We need to use require instead of import because this code runs on a node environment. 
const { app, BrowserWindow } = require('electron')

function createWindow () {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: { nodeIntegration: true }
  })

  // and load the index.html of the app.
  win.loadFile('index.html')
}

app.whenReady().then(createWindow)

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


Enter fullscreen mode Exit fullscreen mode

Now create a very simple index.html file:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello Hello Electron!</title>
  </head>
  <body>
    <h1>Hello Electron!</h1>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode

Now, let's run the npx electron command on your shell to see our first electron app running.

electron running hello

This is very nice, but can give us the impression that Electron is just a wrapper that we use on our websites to convert them to desktop applications.

Once we add some more functionality to our app, we will see that there are specific Electron topics that we need to take care of in order to create a useful piece of software.

Electron File Loader

Let's change our HTML so we have an input file control and a textarea element:

<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="styles.css">
  <title>Text File Loader</title>
</head>

<body>
  <main>
    <h1>Text File Loader</h1>
    <form action="">
      <input type="file" name="fileLoader" id="fileLoader">
      <textarea name="loadedText" id="loadedText" cols="30" rows="20"></textarea>
    </form>
  </main>
</body>

</html>

Enter fullscreen mode Exit fullscreen mode

We will also need some simple CSS style, so create a new file called styles.css and put the following content on it:

main {
    margin: 2rem;;
}
textarea {
    width: 100%;
    margin: auto;
    display: block;
}
Enter fullscreen mode Exit fullscreen mode

At this moment, when you run your app it should look something like this:

electron text file loader

We have the visual elements, now we need to make them interactive with Javascript. For this, we need to call a script inside our HTML using the script tag. Put it at the end of the file, just after closing the body tag:


</body>
<script type="module" src="./renderer.js"></script>


Enter fullscreen mode Exit fullscreen mode

Of course, we need to create this new renderer.js file. There we will add an event listener to detect that a file has been selected by the user:

document.getElementById("fileLoader").addEventListener("change", fileSelected);

Enter fullscreen mode Exit fullscreen mode

Now, the code for the event handler:

const { ipcRenderer } = require('electron');

async function  fileSelected(e){    
    const loadedFilePath = e.target.files[0]?.path
    let data = await window.electron.ipcRenderer.invoke('read-file', loadedFilePath)
}

Enter fullscreen mode Exit fullscreen mode

This kind of function should be familiar if you are a web Javascript developer, except for this line:


let data = await window.electron.ipcRenderer.invoke('read-file', loadedFilePath)

Enter fullscreen mode Exit fullscreen mode

Usually, the code of Electron apps runs in two different isolated contexts:

The rendered context is the JavaScript code that is interpreted by a WebView provided by Electron and the main context is a node environment where you can make use of some native desktop functionalities (like loading files from the filesystem).

ipcRenderer is an EventEmitter. It provides a few methods so you can send synchronous and asynchronous messages from the render process (web page) to the main process.

We are sending the 'read-file' message, but we need another piece of code to receive this message, right?

Of course! That is what the next code is about, write it into your app.js file:


ipcMain.handle('read-file', async (ipcEvent, path) => {
    if (path != undefined) {
        console.log('Load: ' + path)        
        //Here we will add the necessary code for loading the file.
    }
})


Enter fullscreen mode Exit fullscreen mode

Don't forget to require ipcMain from electron at the beginning of the main.js file

const { app, BrowserWindow, ipcMain } = require("electron");
Enter fullscreen mode Exit fullscreen mode

If you check in the console (your terminal as the handle is executed in the main context).

You will see that it prints out the name of the file that we have selected.

Loading and returning the file contents is a two-liner using promises along with async and await:


ipcMain.handle('read-file', async (ipcEvent, path) => {
    if (path != undefined) {
        console.log('Load: ' + path)        
        let loadedText = await fs.readFile(path, 'utf-8')
        return loadedText
    }
})


Enter fullscreen mode Exit fullscreen mode

Don't forget to require the promise ready version of the fs module at the beginning of main.js .

Now that we have our data, let's go back to our renderer.js file and show them in the text area adding the following line to our fileSelected function:


async function fi
<a href="/electron-1/text-file.png" target="_blank"><img src="/electron-1/text-file.png" alt="electron text file loader" class="screenshot"></a>leSelected(e){    
    const loadedFilePath = e.target.files[0]?.path
    let data = await ipcRenderer.invoke('read-file', loadedFilePath)
    document.getElementById("loadedText").value = data
}

Enter fullscreen mode Exit fullscreen mode

Voilà! You have coded a simple but functional app with Electron.

a working electron text file loader

You can check out the source code of this example on:

https://github.com/mran3/Text-File-Loader

Top comments (0)