De gecombineerde kracht van NodeJS en Angular

Het viel mij op dat er steeds meer en meer “desktop” applicaties toch stiekem ook web applicaties zijn. Een goed (en populair) voorbeeld hiervan is Discord (https://discordapp.com). Het is bij Discord zelfs zo dat je de developer tools van je browser gewoon kan openen (bijv. in Google Chrome is dit: ctrl+shift+i). Onder de motorkap blijken NodeJS en Angular samen te werken, blijkbaar een bruikbare en krachtige combinatie voor het maken van cross platform apps.
ElectronJS
Nu blijkt het dat er voor NodeJS een module is genaamd ElectronJS (https://electronjs.org) en toen ging er een wereld voor mij open. ElectronJS maakt de combinatie met NodeJS en Angular zo enorm sterk, dat je in een handomdraai een webapp EN desktop app in elkaar kan zetten.
Ervan uitgaande dat er geen ts-node gebruikt wordt, kun je eenvoudig een Electron browser window bouwen door:
const { BrowserWindow } = require(‘Electron’);
~~~~
function createWindow() {
win = new BrowserWindow({
width: 900,
height: 700,
//frame: false,
transparent: true
});
win.loadURL(`file://${__dirname}/index.html`);
}
~~~~
app.on(‘ready’, createWindow);
BrowserWindow is een onderdeel van Electron, je kan hierin de standaard width en height doorgeven. Vanaf hier kan je via een loadURL een pagina laden. Weet wel dat er in de webwereld een groot verschil is tussen lokaal laden (dus met file://) en het laden van een website. Met name rondom de Content Security Policy (CSP) is hier een groot verschil. Gezien node de source hashed zou je een CSP header moeten sturen die de nonce of de hash zet voor je type/javascript. Zie https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src voor meer informatie hierover.
Onderstaand volgen nog enkele handige tidbits …
Preload script injection
Met een webapp is het vrij lastig om direct met een browser te praten zonder een aanpak via sockets/react/etc. Met Electron is dit eenvoudig te realiseren middels het injecteren van een preload script, welke de events opvangt van de backend en deze direct doorgeeft aan de frontend.
Om met preload te werken is het noodzakelijk om in BrowserWindow de webPreferences aan te passen:
win = new BrowserWindow({
width: 900,
height: 700,
webPreferences: {
nodeIntegration: true,
preload: path.join(__dirname, ‘preload.js’)
},
//frame: false,
transparent: true
});
Nu heb je in je preload.js gewoon toegang tot events dat de maincode afvuurt:
const ipcRenderer = require(‘Electron’).ipcRenderer;
const remote = require(‘Electron’).remote;
ipcRenderer.on(’test’, (event, args) => {
const testElement document.getElementById(‘test’);
testElement.innerHTML = “test”;
});
Zodra de maincode de event “test” afvuurt, zal het preload script ervoor zorgen dat in het element “test” het woord test komt te staan.
Angular ng module
Voor Angular is tegenwoordig de tool “ng” beschikbaar (de module “angular-cli”). Hiermee is het niet meer noodzakelijk zelf een workspace in te richten; dit kun eenvoudig met een ‘ng new’ doen.
StackBlitz
Tijdens mijn search ben ik ook tegen StackBlitz (https://stackblitz.com/) aangelopen, een online editor voor onder andere Angular. Met de gratis versie kan je al veel, alleen moet alles publiekelijk. Voor $9 per maand heb je al toegang tot private projects en repos.