float-diagonal

Use with Electron

Recommended Posts

When trying to use Phaser 3 Beta 15 with Electron I get errors about the names WEBGL_RENDERER and CANVAS_RENDERER being undefined as soon as I try to instantiate a Phaser.Game. This doesn't happen in a normal browser.

To sidestep the issues I was able to simply set values to window.WEBGL_RENDERER and window.CANVAS_RENDERER prior to loading phaser.js. This will at least get the Phaser init message in the console.

Should this be submitted as a Github issue? I don't know where Electron support falls on the spectrum and I don't know enough about the Phaser internals to say how much of an issue it would be to fix it.

Share this post


Link to post
Share on other sites

There are only two JS files in the project at the moment, src/main.js and src/renderer.js. The former is the Electron entry point which creates the main window for src/index.html and the latter is require()'d from src/index.html inside the window.

Phaser is loaded via a call to require('phaser') inside src/renderer.js. From what I can tell this is loading node_modules/phaser/dist/phaser.js from the project root that was built by doing npm install && npm run build from inside node_modules/phaser.

NOTE: The build instructions listed in the docs didn't work for me because it complained that Webpack was missing (even if Webpack was installed globally), so I had to add the npm install step.

Share this post


Link to post
Share on other sites
4 hours ago, rich said:

Those two settings are global defines that webpack uses during the build stage. Surely if you were packaging a game for Electron you'd build it first, then the Electron package would just be the build files + assets?

I'm not sure when or if I will be using any build system for this project. I don't see any immediate benefit from it. It is being built on Electron from the ground up because it needs direct access to local system functionality (and possibly other Node features) and is not headed to the browser right now. All the JS files will be available locally and can be accessed using Node's built-in CommonJS support, and I don't need to use any language features other than those already supported by Node/Electron. (I am, however, using Typescript indirectly via the // @ts-check directive in plain JS files)

Also, not to be rude, but I do not understand how bundling my project code with Phaser would resolve the issue of the names appearing in the compiled bundle. Wouldn't the same thing still be happening anyway?

Share this post


Link to post
Share on other sites

If you're not bundling the app before including it into Electron then it's almost certainly just trying to load the Phaser source files directly as a result of the call to require, and not the dist files, because the dist files don't have those globals in them.

Here is what happens if you build a dist version of Phaser, all of the render calls that use the globals change from this:

if (WEBGL_RENDERER)
{
    renderWebGL = require('./BlitterWebGLRenderer');
}

if (CANVAS_RENDERER)
{
    renderCanvas = require('./BlitterCanvasRenderer');
}

to this:

if (true)
{
    renderWebGL = __webpack_require__(1098);
}

if (true)
{
    renderCanvas = __webpack_require__(1099);
}

(this is taken from dist/phaser.js)

Which is why usually you'd build your app into a single bundle, and then only the bundle file (which is your game + Phaser + whatever else you need) is packaged by Electron.

Hope that makes a bit more sense.

Share this post


Link to post
Share on other sites
7 minutes ago, rich said:

If you're not bundling the app before including it into Electron then it's almost certainly just trying to load the Phaser source files directly as a result of the call to require, and not the dist files, because the dist files don't have those globals in them.

Here is what happens if you build a dist version of Phaser, all of the render calls that use the globals change from this:


if (WEBGL_RENDERER)
{
    renderWebGL = require('./BlitterWebGLRenderer');
}

if (CANVAS_RENDERER)
{
    renderCanvas = require('./BlitterCanvasRenderer');
}

to this:


if (true)
{
    renderWebGL = __webpack_require__(1098);
}

if (true)
{
    renderCanvas = __webpack_require__(1099);
}

(this is taken from dist/phaser.js)

Which is why usually you'd build your app into a single bundle, and then only the bundle file (which is your game + Phaser + whatever else you need) is packaged by Electron.

Hope that makes a bit more sense.

Yes, thanks! That does appear to be the case. This was a failure of my understanding of Node's import rules.

I am not familiar with how packaging a stand-alone Electron app works generally. For the time being I seem to be able to be able to resolve the issue by calling require('phaser/dist/phaser'). Do you foresee that causing any problems or would it be better to just setup a command for building the package?

Share this post


Link to post
Share on other sites

Thank you for your advice! I'll probably get to that point eventually.

Also, I just wanted to say that you're totally awesome for running this project. I remember using your work from the early Flixel days and it's really inspiring to see how far you've come since then.

Share this post


Link to post
Share on other sites

So, I ended up having to use Webpack after all and now I'm having a unique problem.

Before incorporating Webpack, Phaser didn't seem to have any problems using XMLHttpRequest for loading assets from the render thread even though it was using local filesystem paths. After switching to using the electron-webpack package, however, the dev console is suddenly complaining that the "file://" protocol is not supported by XMLHttpRequest. This is of course is normal behavior, but it begs the question why it was working before when it isn't now.

In any case I feel like the "correct" solution here would be to convince Phaser to use Node's built-in "fs" module to load files asynchronously. I've already tested that the data can be loaded from the rendering thread this way, so now I'm trying to determine if there is a way to override the asset loader with a custom version that uses fs. (I'm going through dev logs, examples, and source code looking for clues.)

Edited by float-diagonal
Corrected "webpack-electron" to "electron-webpack"

Share this post


Link to post
Share on other sites

I was unable to find a way to use create and properly install a custom loader class, so I had to settle for a monkey-patch. It tricks the standard loader into using Node's fs module when it tries to use XHR. It's definitely a fragile and sub-optimal solution but I needed to move on to other problems.

The XHR wrapper:

fs-xml-http-request.js

To use it, you can do this:

import Phaser from 'phaser';
import FSXHR from './fs-xml-http-request';

// Monkey-patches LoaderPlugin to use fs.readFile() when it tries to perform XHR
FSXHR.install(Phaser.Loader.LoaderPlugin.prototype, 'processLoadQueue');

const game = new Phaser.Game({
  ...
  scene: {
    preload() {
      // This will end up loading a local file
      this.load.image('foo', 'C:\\Data\\foo.png');
    }
    ...
  }
});

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.