DEV Community

Michael De Abreu
Michael De Abreu

Posted on • Edited on

Integrating an Angular-CLI application with Electron - The seed

Integrate your project with Electron

Electron is a platform to develop desktop applications using web technologies like HTML, CSS and JS. Integrate a ng-cli application with Electron is more straightforward that it may seems.

Electron's two package structure

If you are familiarized with Electron you may remember the two package structure. We will use a similar structure, but with a key difference: In a regular two package structure, the /app/ folder will contains the Electron app. We will name this folder /electron/ and another /app/ folder inside will contains our compiled Angular application.

It may seem like we are using the two package structure, but we are just separating the Electron part from the rest of the application.

Changes in the app configuration

  • Create a script in our Angular application package.json.
"electron:start": "ng build --watch -op=electron/app"
Enter fullscreen mode Exit fullscreen mode

This will build the Angular app inside an app folder inside our Electron folder app, and will rebuild on every change.

  • Add the new output folder into .gitignore, in #compiled output section, /electron/app.
  • Modify the base tag of the index.html of our Angular app, as follow:
<base href="./">
Enter fullscreen mode Exit fullscreen mode

Adding a dot before the slash will allow Electron to find the served files, and without a 404 error will be threw.

This will be all the modifications that we need to integrate the application with Electron.

Creating our Electron app

  • We need to create a electron folder inside our project. Inside we are going to run npm init command to create the Electron package.json. This folder will be our Electron root folder.
  • We add Electron as a development dependency.
npm install -D electron
Enter fullscreen mode Exit fullscreen mode
  • We create the entry point for our Electron program.

index.js

const { app, BrowserWindow } = require('electron');
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 win;

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

  // and load the index.html of the app.
  win.loadURL(
    url.format({
      pathname: path.join(__dirname, 'app', 'index.html'),
      protocol: 'file:',
      slashes: true,
    }),
  );

  // Open the DevTools.
  win.webContents.openDevTools();

  // Emitted when the window is closed.
  win.on('closed', () => {
    // 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.
    win = 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', () => {
  // On macOS 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.quit();
  }
});

app.on('activate', () => {
  // 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 (win === null) {
    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

Running the app

  • Open a terminal and move to the Angular project, and run npm run electron:start to start the Angular application.

  • Open a second terminal and move to the electron folder inside the project, and run electron . to start the electron application.

You should see a window with the Angular app running inside of it.

Moving forward

We now have a very simple Angular application running inside of the Electron renderer process. If we modify something of either, the Angular app, or the Electron app, we need to close the Electron window and run the electron . again. This could be optimize using plugins and build systems, but this is the out-the-box behavior of Electron.

You may notice that the entry file of the Electron application is written in vanilla Javascript. This is because Electron runs only vanilla Javascript, and in order to run other language such Typescript, you should use a plugin, such ts-node, or a build system.

Series

Top comments (3)

Collapse
 
ruipimentel profile image
ruipimentel

Hi Michael, thank you for your guide.

Probably, however, in your tutorial Angular may only be able to use standard browser APIs. Electron, as you surely know, relies on a "special" version of Chromium which has access to a lot of other APIs.

That said, to allow an Angular app to access Electron's "superpowers" (like Tray Menu, Global Shortcuts and so on), it would be necessary to compile it along with "@types/electron" ("npm install --save-dev @types/electron", then "import { some electron lib } from 'electron';"). Unfortunately, @angular/cli messes around with "require()" during compilation, due to it's internal webpack "target" config not being set to "electron-renderer".

How to set up @angular/cli to compile accordingly? Thanks in advance!

Collapse
 
michaeljota profile image
Michael De Abreu

Hi @ruipimentel . I'm glad you'd found it helpful. I'm just writing another post about calling functions in Electron main thread using ipc in Angular. When I have it ready, I'll update this with the link. Thanks.

Collapse
 
bvandenbon profile image
Bram Vandenbon • Edited

ng build --watch -op=electron/app is replaced by
ng build --watch --output-path electron/app