Support for lightweight "helper" windows


#1

I’m working on an Electron-based mail client. The mail client supports packages the same way Atom does, but unlike Atom it has one main window, and frequently needs to open lightweight, short-lived windows—composer windows, contact editing windows, you name it.

We’re finding that Electron is not very well suited to this scenario of use. Opening new windows with NodeJS enabled, and then loading modules, package javascript, etc. into them is very slow. Even loading a restricted subset of the application code into a new window can take 300-400msec on slow machines. This is fine for Atom, because it opens few windows and all the windows need all the code, but it’s not ideal for showing a composer with light plugin integration, a feedback form that lists the packages you have installed, etc.

There are a few ways we’ve tried to solve this problem:

  1. Create secondary windows ahead of time and keep them hidden. When the user asks for a window, pop it off a stack of “hot” windows and display it. This works fine, especially for a smaller number of window types, but creates a huge memory overhead and thrashing on slow machines as offscreen windows are prepared.

  2. Use BrowserWindows without node-integration, and write separate code for these windows which uses https://github.com/seanchas116/electron-safe-ipc or similar to interact with the main window’s renderer process. This also works, but makes it much harder to write re-usable application code. This could potentially lead to a lot of IPC traffic through three processes, which is also rough on slow machines.

If we could dig a little deeper, I think there are some more interesting ways to solve this problem. I realize these may be completely impossible given the architecture of Electron, but I feel like this is a significant current limitation that may be worthy of a dedicated solution.

A: Allow “lightweight” secondary windows to share a renderer process with another “parent” window. This would allow us to quickly render a preferences window, for example, without loading anything again. I know this was the approach Node-Webkit used and one of the primary ways Electron is different, but I think it makes sense in some scenarios.

B: Allow a DOM node in the main window to serve as the root node of another window: It’d be great if we could say “this DOM tree should appear in child window A”. We could render the nodes in the main window, handle input events in the main window, etc. (We are currently investigating whether we can do this in “user space” by forwarding React’s virtual DOM and virtual events over IPC)

C: Allow BrowserWindows to be initialized as memory-replicas of an existing BrowserWindow: If we could initialize V8 with an exact copy of the memory in our main BrowserWindow, we might be able to prepare a secondary window much faster. (This solution might also allow Atom to open windows more quickly.)

I’d love to know if any of these seem remotely feasible, or if there’s another way to solve the problem I haven’t thought of.