Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When used on the renderer process of the Electron environment, the message "Class constructor NodeSSH cannot be invoked without 'new'" is displayed and instantiation fail. #427

Open
TakamiChie opened this issue Apr 29, 2022 · 4 comments

Comments

@TakamiChie
Copy link

TakamiChie commented Apr 29, 2022

Hello.

I am considering the use of NodeSSH in the Electron environment.
I made the NodeSSH module available on the renderer process using a preload mechanism in order to reflect the processing result on the screen.

// main.js
const { app, BrowserWindow } = require('electron')
const path = require("path");

let win
function createWindow() {
  win = new BrowserWindow({
    width: 400,
    height: 400,
    webPreferences: {
      nodeIntegration: true, 
      preload: path.join(__dirname, './src/preload.js'),
      contextIsolation: true,
    }
  });
  // ...
}
app.on('ready', () => {
  createWindow();
})
// preload.js
const { contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld(
  "requires", {
    nodessh : require('node-ssh'),
    ipcRenderer : ipcRenderer,
  }
);
// index.js(In RendererProcess)
const {NodeSSH} = window.requires.nodessh;
const ssh = new NodeSSH();
// ...

In this way, electron execution itself is possible, but on the second line of the index .js, an error of "Class constructor NodeSSH cannot be invoked without 'new'" occurs and the script stops executing.

When I checked in electron's developer console, the value of "window.requires.nodessh" seems to be "{SSHError: ƒ, NodeSSH: ƒ}", and I think the loading itself is successful, but is there any missing description?


Environment

Windows 11 Pro
Version 21H2 Build: 22000.613

npm -v

8.4.1

.\node_modules.bin\electron -v

v18.1.0

@steelbrain
Copy link
Owner

steelbrain commented May 2, 2022

Hello! This is quite an interesting bug you're hitting. If I had to guess, it'a a bundler messing things up somewhere.

Can you please post the output of the code below?

// index.js(In RendererProcess)
const {NodeSSH} = window.requires.nodessh;
console.log(NodeSSH.toString())
// ...

@TakamiChie
Copy link
Author

Thanks for the reply.
Electron's developer console displays the following message:

Uncaught Error: Class constructor NodeSSH cannot be invoked without 'new'
at index.js:2:13

Also, if I check the NodeSSH value from the console, it looks like this:

NodeSSH
ƒ () { [native code] }

The value of window.requires.nodessh is as follows.

{SSHError: ƒ, NodeSSH: ƒ}
NodeSSH: ƒ ()arguments: nullcaller: nulllength: 0name: ""prototype: {constructor: ƒ}[[Prototype]]: ƒ ()[[Scopes]]:
Scopes[0]SSHError: ƒ ()arguments: nullcaller: nulllength: 0name: ""prototype: {constructor: ƒ}[[Prototype]]: ƒ ()[[Scopes]]: Scopes[0]
[[Prototype]]: Object

Did it become a clue?

@steelbrain
Copy link
Owner

Aha! That explains it! It's a limitation in the Electron code proxy. You'll have to work it around.

Instead of exporting node-ssh directly, you'll have to expose a local file that acts as a proxy for the APIs for node-ssh. For example, a file that exports a function function getNodeSSH(opts) { return new NodeSSH(opts) } in preload, and then call getNodeSSH in renderer so that you do not have to use new keyword in renderer and can move forward

@TakamiChie
Copy link
Author

Thanks for the reply. The code was changed as follows and the process was performed.

// preload.js
const { contextBridge, ipcRenderer} = require("electron");
const { NodeSSH } = require("node-ssh"); // changed

contextBridge.exposeInMainWorld(
  "requires", {
    getNodeSSH: function (opts) { return new NodeSSH(opts) }, // changed
    ipcRenderer : ipcRenderer,
  }
);
// index.js(In RendererProcess)
const ssh = window.requires.getNodeSSH(); // changed
ssh.connect({...}); // changed

However, the following error prevents the SSH connection.

Uncaught TypeError: ssh.connect is not a function at index.js:3:5

When I checked the ssh variable, it seems to be reading it because it says {connection: null}, but when you check ssh.connect the value is undefined.

In addition, it was confirmed that the desired processing can be executed when SSH connection is performed in the main process using ipcRenderer.
When using NodeSSH, is it better to make an SSH connection in the main process using interprocess communication?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants