diskvakt og min erfaring med Electron


Mitt første og antagelig siste Electron program på en stund.



diskvakt er et SMART/diskdata-helse overvåkingsprogram som kan lastes ned og installeres fra sin egen produktside.
Jeg tester samtidig en betalingsløsning og lisensopplegg for programvare på det, med tilfeldig prislapp på 55 NOK for et år.



Electron

Alle som har holdt på med systemutvikling en stund har før eller senere støtt på begrensninger og hodebry rundt grafiske grensesnitt. Populære programmer som Spotify, Steam, Discord o.l. overkommer dette ved å benytte HTML og CSS for layout og JavaScript for funksjon i en embedded Chromium motor for kommunikasjon mot Node.js som backend som til slutt ender i en helhetlig skrivebords-applikasjon. Rammeverket heter Electron og har vært under utvikling i en hel del år. For å utvikle i Electron/Electron-Forge lastet jeg ned node.js og git og trengte deretter kun dokumentasjon og verktøyene npx,npm for initialisering og kompilering. Jeg brydde meg ikke om distribusjon da jeg foretrekker Inno til det meste av installasjon og oppsett.

Mens man veldig enkelt kan oppnå nesten hva som helst av kreative grensesnitt via Electron i nesten ren webutvikler-stil, er det også relativt ytelseskrevende og oppblåst pga. Chromium motoren som backend som i praksis er som å ha en ekstra nettleser gående og alt som hører med. Bare for noe så enkelt som diskvakt, kreves det 229MB lagringsplass og over 100MB RAM, hvor hjertet av programmet kun tar 290kB og kunne kanskje vært distribuert totalt under 5MB i sin helhet dersom jeg gikk for et enklere C/C++ grensesnitt. Heldigvis trenger ikke mitt program kjøre hele tiden. Noen vil nok argumentere med at det ikke er betydelig i dag med TB disker og mange GB RAM som standard, men likevel, ting akkumulerer seg og jeg vurderer ting relativt. Det er også mange små avhengigheter involvert og tillit til tredjeparter som skal vedlikeholde dem (pakker via NPM osv. under utvikling) som det ofte er med åpen kildekode. Jeg kommer ikke til å ta utgangspunkt i å bruke Electron til hva som helst, og lagde diskvakt i det kun for å få erfaring med det som var veldig overkill. For store og kompliserte grensesnitt som tidligere nevnt er det ikke så rart at de har gått for løsningen, da de praktiske utvikler-fordelene er ganske store i forhold til avhengigheter og ytelse. Men for min egen del skal det et rimelig stort prosjekt til før jeg velger å bruke det igjen.



Videre følger noen notater på engelsk jeg gjorde meg under utvikling.


Getting started with Electron on Windows

Some quick notes while trying out Electron/Node.js. Been on the bucket list a while, waiting for it to mature.

Installed node.js and git.
Created a project folder anywhere and entered it in CMD.
> npm init (to configure a package.json file, tip: use UNLICENSED on license option.
> npm install electron --save-dev

Created a index.js file with some test code, e.g. console.log('hello world!');
Add "start": "electron ." to the scripts section in package.json.
> npm run start (to see your example). Ran fine.

Created index.html and started designing a simple front end.

Packaging

// Creating the binaries for me to publish however I want.
npm install --save-dev @electron-forge/cli
npx electron-forge import
npm run make


Multithreading

// Starting a worker somewhere in index.html or one of its script files.
var w = new Worker('worker1.js');

// Attach a function listener for feedback from it.
w.onmessage = (e) => {
	console.log(e.data);
}

// Post a message to start it.
w.postMessage("foo");

worker.js
onmessage = (e) => {
	for (var n=0; n<10; n++)
		postMessage('I did a lot of work with '+ e.data +', I promise!');
}


IPC - Inter Process Communication

index.js
const { app, BrowserWindow, ipcMain } = require('electron');
var spawn = require('child_process').spawn;
ipcMain.handle('cmdtest', async () => {
	var cmdtest = spawn("cmd.exe", [
		"/c",
		"pause"
		],
		{
			shell: true,
			detached: true
		}
	);

	// If process is not detached/shell, I can get output here.
	cmdtest.stdout.on("data", (data) => {
		console.log(data.toString());
	});
	cmdtest.stderr.on("data", (err) => {
		console.log(err.toString());
	});
	cmdtest.on("exit", (code) => {
		console.log('cmdtest exited.');
	});

	// Return something to the caller.
	return 'Have started cmd process.';
});
Should also look into UtilityProcess vs child_process I used: https://www.electronjs.org/docs/latest/tutorial/process-model#the-utility-process

preload.js
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('nodecom', {
	cmdtest: () => ipcRenderer.invoke('cmdtest')
});

renderer.js
document.getElementById('SomeButtonOrLink').addEventListener('click', async () => {
	var r = await window.nodecom.cmdtest();
	console.log(r);
});


Content-Security-Policy

Put 'unsafe-inline' in the Content-Security-Policy meta tags like below, to be able to do e.g. style="" on tags and other attributes.
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline'">


Other minor things


dev/release relative pathing with path.join
An annoying thing to deal with in the beginning as a newbie is the fact that while you're playing around in the same folder, the files will be local. But after packaging (in my case with electron forge) those files will be placed in resources/app instead. This threw me off on a few batch files I was calling with child_process. Path.join is gold and solves this. Examples:
path.join(__dirname, 'preload.js')
spawn(path.join(__dirname, 'OpprettPlanlagtOppgave.cmd')

// joining __dirname with file, will respectively choose correct location when used via npm run start in dev folder or resources/app if from release binary.


Require administrator rights on executable
// forge.config.js
module.exports = {
	packagerConfig: {
		"win32metadata": {
			"requested-execution-level": "requireAdministrator"
		},


Setting icon using electron forge
// forge.config.js
module.exports = {
	packagerConfig: { icon: 'varsel' }, // electron setter på .ico selv for windows.

// index.js
const createWindow = () => {
	const win = new BrowserWindow({
	icon: 'varsel.ico'


Hiding developer console (ctrl+shift+i) when releasing.
// index.js
const createWindow = () => {
	const win = new BrowserWindow({
		webPreferences: {
			devTools: false


Preventing drag and select of elements for a more native feel.
// Default for all elements.
*, *::after, *::before {
	-webkit-user-select: none;
	-webkit-user-drag: none;
	-webkit-app-region: no-drag;
}

// Then just override as needed.


Compressing resources on installed release to a single app.asar file (seems to be the default by now):
// forge.config.js
module.exports = {
	packagerConfig: {
		asar: true
	},
	plugins: [
		{
			name: '@electron-forge/plugin-auto-unpack-natives',
			config: {},
		},
	],



Publisert: 23.aug.2023 12:33 | Oppdatert: 7.sep.2023 11:04.
Windows Programvare

Erklæring om bruk av informasjonskapsler/cookies

Ditt personvern er ivaretatt; Informasjonskapsler brukes kun for funksjon.

Tredjeparter som har sine egne erklæringer:
Site Stats
OK / Skjul