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"
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 theindex.html
of our Angular app, as follow:
<base href="./">
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 runnpm init
command to create the Electronpackage.json
. This folder will be our Electron root folder. - We add Electron as a development dependency.
npm install -D electron
- 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.
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 runelectron .
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.
Top comments (3)
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!
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.
ng build --watch -op=electron/app
is replaced byng build --watch --output-path electron/app