Electron target version

Hi

Is there any way to bump the Electron target’s version and still successfully compile and run an OpenFL app?

openfl build electron currently creates files (and node module structure) for Electron v9.1.0 which is kinda outdated (2 years old, Electron is at v18 these days).

The default npm install command already warns about a moderate severity vulnerability in one of the modules (although the app works as expected). npm audit fix instantly upgrades Electron, thus, the app no longer starts (fatal error in console).

I can also change the Lime templates to install newer Electron modules, but even the smallest bump (eg. to version 10.0.0) produces fatal runtime errors and the app won’t run at all (weirdly it’s starting to whine about NodeJS classes, eg. it says js.node.Buffer is undefined).

Anyone ever managed to use a newer Electron with OpenFL? I’m kinda stuck with this, and I’m in the need to use some nice Electron APIs which are not present in OpenFL (Webview, System Menu, Context Menu, Tray Icon, just to name a few) while possibly using a much newer version of Electron.

Note that I’m using the haxelib version of OpenFL.

Thank you.

Last time I used electron with Openfl, I used electron-builder and put the openfl html5 bin in the www folder and voilà. But it was to make a simple exe so I hadn’t use any electron native features. I probably did that because the electron target was outdated like you are saying.

After you build an OpenFL app for the electron target, you need to run npm install to actually get Electron before running it. So you should be able to simply modify the Electron version in the generated package.json before npm installing. As far as I know, OpenFL doesn’t actually integrate with any of Electron’s system APIs, so upgrading to a newer version should have very little impact on what already works today. OpenFL basically treats Electron like a normal, sandboxed web browser right now, with no special capabilities beyond the html5 target.

As I explained in the top post, I changed the version (in package.json) to eg. 13.0.0 and it produces this error in Electron console after npm install and npm start

So no, it won’t run, only with the pre-defined Electron version 9.1.0

This is produced with the bare minimum of a Sprite based OpenFL app and a project.xml file, no additional library or anything is involved.

Checking KeyValue.hx:37:3 does not help, it just points to a totally unrelated line of code, but I guess it’s related to hxnodejs library

I think I figured it out by disabling JS source map.

I had to manually edit Lime templates/electron/haxe/ElectronSetup.hx

ElectronApp.on('ready', function(e)
 {
  var config:Dynamic =
  {
  webPreferences:{
  nodeIntegration:true,
  contextIsolation:false
  },
  fullscreen: window.fullscreen,
  frame: frame,
  resizable: window.resizable,
  alwaysOnTop: window.alwaysOnTop,
  width: width,
  height: height,
  webgl: window.hardware
 };

The new property in BrowserWindow config object is contextIsolation:false which is required above Electron v11 in order so the require() JS function is working properly. Now it even works with the latest Electron version (18.0.3)

The JavaScript crash and the solutions are explained here: https://stackoverflow.com/questions/45723462/javascript-error-uncaught-referenceerror-require-is-not-defined

Thanks

Interesting. Requiring that Electron’s security features are turned off is definitely something we should avoid. Lime/OpenFL is going to need to be refactored so that it doesn’t use require() in the renderer process. It needs to use the inter-process communication capabilities that keep stuff like require() safely separated from the web content.

1 Like

I just pushed a commit to the development version of Lime that updates to Electron 18. Lime now accounts for these stricter security defaults of newer versions of Electron.

2 Likes

hxelectron is a great all-around haxe lib to use in Haxe or OpenFL projects, but for OpenFL it’s required to use the electron.remote.* package instead of electron.main.* because OpenFL apps run in the renderer process.

Additionally the main issue with my code (besides the dated Electron version) was that the remote package of Electron has been removed in v13, and it’s added as a separate nodejs module. They advice against using the remote module because of security reasons, but from an OpenFL developer standpoint, the hxelectron lib is still a great way to access Electron APIs without the hassle of creating JavaScript bridge code.

I needed to add a few lines of additional code in ElectronSetup.hx to initialize the remote module properly, and I needed to change the @:jsRequire externs in hxelectron’s classes, so it’s kinda hack-y, but for now it does the job well.

The only reason I’m using Electron target is because of the nice system APIs that would otherwise require writing native extensions

Yeah, I definitely understand that. When someone has time and motivation, OpenFL should ideally provide some of that JavaScript bridge code out of the box. Especially when similar capabilities exist between Adobe AIR (which was Flash for desktop apps) and Electron — a big one would be reading/writing files. It probably wouldn’t be able to expose all of Electron’s capabilities, but it would still be a big improvement.

If someone needs it, or for future reference, here’s the modified package.json

{
    "name": "::meta.packageName::",
    "version": "::meta.version::",
    "main": "ElectronSetup.js",
    "scripts": {
        "start": "electron ElectronSetup.js"
    },
    "devDependencies": {
        "electron": "^18.0.0",
        "@electron/remote": "^2.0.8"
    }
}

So npm install will pull the remote module as well.

And here’s the modified ElectronSetup.hx

package;

    class ElectronSetup
    {
    	public static var window:ElectronBrowserWindow;

    	static function main()
    	{
    		ElectronApp.commandLine.appendSwitch('ignore-gpu-blacklist', 'true');

    		var windows:Array<OpenFLWindow> = [
    			::foreach windows::
    			{
    				allowHighDPI: ::allowHighDPI::,
    				alwaysOnTop: ::alwaysOnTop::,
    				antialiasing: ::antialiasing::,
    				background: ::background::,
    				borderless: ::borderless::,
    				colorDepth: ::colorDepth::,
    				depthBuffer: ::depthBuffer::,
    				display: ::display::,
    				fullscreen: ::fullscreen::,
    				hardware: ::hardware::,
    				height: ::height::,
    				hidden: #if munit true #else ::hidden:: #end,
    				maximized: ::maximized::,
    				minimized: ::minimized::,
    				parameters: ::parameters::,
    				resizable: ::resizable::,
    				stencilBuffer: ::stencilBuffer::,
    				title: "::title::",
    				vsync: ::vsync::,
    				width: ::width::,
    				x: ::x::,
    				y: ::y::
    			},::end::
    		];

    		for (i in 0...windows.length)
    		{
    			var window:OpenFLWindow = windows[i];
    			var width:Int = window.width;
    			var height:Int = window.height;
    			if (width == 0) width = 800;
    			if (height == 0) height = 600;
    			var frame:Bool = window.borderless == false;

    			ElectronApp.commandLine.appendSwitch('--autoplay-policy', 'no-user-gesture-required');

    			ElectronApp.on('ready', function(e)
    			{
    				var config:Dynamic =
    					{
    						webPreferences:{
    							nodeIntegration:true,
    							contextIsolation: false
    						},
    						fullscreen: window.fullscreen,
    						frame: frame,
    						resizable: window.resizable,
    						alwaysOnTop: window.alwaysOnTop,
    						width: width,
    						height: height,
    						webgl: window.hardware
    					};
    				ElectronSetup.window = new ElectronBrowserWindow(config);

    				ElectronSetup.window.on('closed', function()
    				{
    					if (js.Node.process.platform != 'darwin')
    					{
    						ElectronApp.quit();
    					}
    				});

    				ElectronRemoteMain.initialize();
    				ElectronRemoteMain.enable(ElectronSetup.window.webContents);
    				ElectronSetup.window.loadURL('file://' + js.Node.__dirname + '/index.html');
    				#if (debug && !suppress_devtools)
    				ElectronSetup.window.webContents.openDevTools();
    				#end
    			});
    		}
    	}
    }

    typedef OpenFLWindow =
    {
    	allowHighDPI:Bool,
    	alwaysOnTop:Bool,
    	antialiasing:Int,
    	background:UInt,
    	borderless:Bool,
    	colorDepth:Int,
    	depthBuffer:Bool,
    	display:Dynamic,
    	fullscreen:Bool,
    	hardware:Dynamic,
    	height:Int,
    	hidden:Bool,
    	maximized:Bool,
    	minimized:Bool,
    	parameters:Dynamic,
    	resizable:Bool,
    	stencilBuffer:Bool,
    	title:String,
    	vsync:Bool,
    	width:Int,
    	x:Int,
    	y:Int
    }

    // Externs to compile without requiring hxelectron

    @:jsRequire("electron", "app") extern class ElectronApp
    {
    	public static var commandLine:Dynamic;
    	public static function on(type:Dynamic, callback:Dynamic):Dynamic;
    	public static function quit():Void;
    }

    @:jsRequire("electron", "BrowserWindow") extern class ElectronBrowserWindow
    {
    	public var webContents:Dynamic;
    	public function new(?options:Dynamic);
    	public function loadURL(url:String, ?options:Dynamic):Dynamic;
    	public function on(type:Dynamic, callback:Dynamic):Dynamic;
    }

    @:jsRequire("@electron/remote/main") extern class ElectronRemoteMain {
    	public static function initialize():Dynamic;
    	public static function enable(?webContents:Dynamic):Dynamic;
    }

the new code is the ElectronRemoteMain extern at the bottom, and

ElectronRemoteMain.initialize();
ElectronRemoteMain.enable(ElectronSetup.window.webContents);

these 2 new lines in static main()

1 Like

As for hxelectron, each class should be modified, eg.

@:jsRequire("electron", "remote.BrowserView") extern class BrowserView

should be changed to

@:jsRequire("@electron/remote", "BrowserView") extern class BrowserView

so the electron.remote.BrowserView is accessible and working in OpenFL.

Maybe I’ll open a Github issue or fork the repo and add the changes myself.

1 Like