1

I'm working on a JHipster application that I'm trying to get functioning in Electron. I have Golden Layout for window/pane management and cross-pane communication. I am having several problems with the combination of technologies, including:

  1. I can't pop out more than one pane at the same time into their own Electron windows. I instead get an Uncaught Error: Can't create config, layout not yet initialised error in the console.
  2. Two thirds of the panes don't display anything when popped out into Electron windows, and I'm not sure what the reason is. Any ideas or suggestions for this? One example of content is a leaflet map, another is a "PowerPoint preview" that is really just divs that mock the appearance of slides.
  3. I haven't made it this far yet, but I assume that I will have trouble communicating between popped-out Electron windows when I get more than one open. Right now, the panes communicate between each other using Golden Layout's glEventHub emissions. I have an avenue to explore when I cross that bridge, namely Electron ipcRenderer.

Some borrowed code is here (most of it I can't share because it's company confidential):

electron.js:

const electron = require('electron');
const app = electron.app;
const BrowserWindow = electron.BrowserWindow;

const path = require('path');
const isDev = require('electron-is-dev');

let mainWindow;

function createWindow() {
  mainWindow = new BrowserWindow({width: 900, height: 680});
  mainWindow.loadURL(isDev ? 'http://localhost:9000' : `file://${path.join(__dirname, '../build/index.html')}`);
  if (isDev) {
    // Open the DevTools.
    //BrowserWindow.addDevToolsExtension('<location to your react chrome extension>');
    mainWindow.webContents.openDevTools();
  }
  mainWindow.on('closed', () => mainWindow = null);
}

app.on('ready', createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (mainWindow === null) {
    createWindow();
  }
});

goldenLayoutComponent.tsx, a patch for Golden Layout:

import React from "react";
import ReactDOM from "react-dom";
// import "./goldenLayout-dependencies";
import GoldenLayout from "golden-layout";
import "golden-layout/src/css/goldenlayout-base.css";
import "golden-layout/src/css/goldenlayout-dark-theme.css";
import $ from "jquery";

interface IGoldenLayoutProps {
  htmlAttrs: {},
  config: any,
  registerComponents: Function
}

interface IGoldenLayoutState {
  renderPanels: Set<any>
}

interface IContainerRef {
  current: any
}

export class GoldenLayoutComponent extends React.Component <IGoldenLayoutProps, IGoldenLayoutState> {
  goldenLayoutInstance = undefined;
  state = {
    renderPanels: new Set<any>()
  };
  containerRef: IContainerRef = React.createRef();

  render() {
    const panels = Array.from(this.state.renderPanels || []);
    return (
      <div ref={this.containerRef as any} {...this.props.htmlAttrs}>
        {panels.map((panel, index) => {
          return ReactDOM.createPortal(
            panel._getReactComponent(),
            panel._container.getElement()[0]
          );
        })}
      </div>
    );
  }

  componentRender(reactComponentHandler) {
    this.setState(state => {
      const newRenderPanels = new Set(state.renderPanels);
      newRenderPanels.add(reactComponentHandler);
      return { renderPanels: newRenderPanels };
    });
  }
  componentDestroy(reactComponentHandler) {
    this.setState(state => {
      const newRenderPanels = new Set(state.renderPanels);
      newRenderPanels.delete(reactComponentHandler);
      return { renderPanels: newRenderPanels };
    });
  }

  componentDidMount() {
    this.goldenLayoutInstance = new GoldenLayout(
      this.props.config || {},
      this.containerRef.current
    );
    if (this.props.registerComponents instanceof Function)
      this.props.registerComponents(this.goldenLayoutInstance);
    this.goldenLayoutInstance.reactContainer = this;
    this.goldenLayoutInstance.init();
  }
}


// Patching internal GoldenLayout.__lm.utils.ReactComponentHandler:

const ReactComponentHandler = GoldenLayout["__lm"].utils.ReactComponentHandler;

class ReactComponentHandlerPatched extends ReactComponentHandler {
  _container: any;
  _reactClass: any;
  _render() {
    const reactContainer = this._container.layoutManager.reactContainer; // Instance of GoldenLayoutComponent class
    if (reactContainer && reactContainer.componentRender)
      reactContainer.componentRender(this);
  }
  _destroy() {
    // ReactDOM.unmountComponentAtNode( this._container.getElement()[ 0 ] );
    this._container.off("open", this._render, this);
    this._container.off("destroy", this._destroy, this);
  }

  _getReactComponent() {
    // the following method is absolute copy of the original, provided to prevent depenency on window.React
    const defaultProps = {
      glEventHub: this._container.layoutManager.eventHub,
      glContainer: this._container
    };
    const props = $.extend(defaultProps, this._container._config.props);
    return React.createElement(this._reactClass, props);
  }
}

GoldenLayout["__lm"].utils.ReactComponentHandler = ReactComponentHandlerPatched;

Any help or insight into these issues would be appreciated. Thanks in advance!

1 Answers1

0

If you are still looking for a solutions, 1 and 2 I have solved, if you want to see my solution you could see in this repository.

But it was basically this:

1: The window that popups has a different path than the main window, so I just had to put a try catch in my requires, and you have to set

nativeWindowOpen = true

when creating the Browser window.

2: Solves it's self after 1 I think

NedLandy
  • 23
  • 1
  • 6
  • Whilst this may theoretically answer the question, [it would be preferable](//meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – Arghya Sadhu Aug 28 '20 at 10:23
  • Hi @ArghyaSadhu, thanks for the response. We haven't been using Golden Layout in development in our company for a long time now. But I appreciate your getting back to me! – Grant Reighard Sep 14 '20 at 21:21