So here is the story:
I develop a 2D game editor called ct.js, and it is based on NW.js framework that doesn't differ much from electron. Here we have a "foreground" page where all the GUI is placed, and a background page, where node.js context is placed, augmented with browser environment. Here, "pages" are regular web pages, with DOM, js, and stuff.
Ct.js is an app that consists of tons of scripts, including 3rd-party libraries. Some of them are browser-based and behave strangely in hybrid environments, where both node.js (specifically
require) and DOM features are present. Libraries may try to override node.js stuff, breaking everything, or think that they are in a pure node.js environment and disable needed features. So most 3rd-party stuff is concatenated and bundled as a script in the foreground page.
But we're in 2019, right? We want to use package managers, or at least
require so we can organize our code more logically and reliably.
And here is the problem: node modules run in the background page, and regular scripts execute in the "foreground" window.
Surely, we can pass the needed variables from one context to another, but what I couldn't transfer was pixi.js' drawing context. IDK how to name that thing, but I suppose that it all narrows down to WebGL contexts that can't be shared between pages.
If I run
require('pixi.js');, then PIXI resorts in the background page, and it can't draw in the foreground page. Everything fails silently: you get a blank canvas, though it seems that simulation still runs — somewhere there.
Another problem is that
Tickers from the background page (that are needed to create a render loop) work as if they were stopped. Probably, it is because of
requestAnimationFrame, or maybe it has something to deal with WebGL exclusively.
I could place pixi.js to that concatenated pile of libraries, but it would pull out all the code for a
RoomEditor class, and that's a big tree of additional classes that are better kept as node modules.
The solution ✨
I put this line at the beginning of my foreground page:
global.PIXI = require('pixi.js'); // BOOM 💥
Node.js has a nice feature that browser pages don't have: a
global object that persists in one instance across any possible code of your node.js app, including foreground and background pages in NW.js. Some frameworks like Feathers use
global to preserve the state of your whole app.
This is a bit hacky way, yes. But, oh well 🙃
But here's what I get:
- all the
requires get the benefit of having a transparent dependency structure, run in a separate background context, give a modular structure and get independence;
- pixi.js still works against the foreground
window, and calls in node modules still work.
Win-win with just one global variable in the environment (not worse than the case with pixi.js loaded and used as a regular script in the foreground page).
Did you face such issue in electron, though?
Top comments (1)
yeah, probably the same issue in Electron, as they both use the same web technology under the hood, and that problem is most likely not NW.js- or ELectron-specific, but due to how web contexts work across windows.