1

I just started to work on my first electron app and imported some existing code that uses the net module. When I import the code from the electron app, the net module returns an empty object.

const net = require('net'); // => {}

I thought that electron bundles node together with the required native modules, so I'm a bit confused about why the import isn't working.

EDIT: I've bootstrapped the app with vue-cli-tools, so it's using webpack to bundle dependencies. Not sure if this is important.

Johannes Stricker
  • 1,701
  • 13
  • 23
  • Which bit of the app are you using this in? The Main process or the Renderer process? – Quentin Nov 02 '20 at 12:04
  • To be honest, I'm not sure which code is running in which process. I'm importing a module that uses the `net` module from within a Vue component, so my guess would be the renderer process? – Johannes Stricker Nov 02 '20 at 12:30

2 Answers2

2

I thought that electron bundles node together with the required native modules,

It does, but having a browser runtime and a node.js runtime bundled together still leaves you with two different runtimes.

Understanding the difference between the Main and Renderer processes is essential for Electron development.

The Main process runs on the Node.js runtime and has access to Node.js APIs (like net).

The Renderer process runs on Chromium and has access to browser APIs (like the DOM).

You can't access net from your client-side Vue code because it is running in the Renderer process.

You need to create a service in the Main process and exchange data between it and something running in the Renderer.

This is typically done using the IPC apis.

// In main process.
const { ipcMain } = require('electron')
ipcMain.on('message-from-browser', (event, arg) => {
  const something = doSomethingWithNetModule()
  event.reply('reply-to-browser', something)
})

and

// In renderer process (web page).
const { ipcRenderer } = require('electron')

ipcRenderer.on('asynchronous-reply', (event, arg) => {
    doSomethingWithDataFromNetModule(arg)
})

ipcRenderer.send('message-from-browser', 'do something with the net module please')

Note that since you are using Webpack you will have issues with require("electron") which are explained in this question.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • Ah, this makes sense and I actually expected something like this to be the case. I just wonder why it has to work that way, as it undoubtedly makes things more complicated. – Johannes Stricker Nov 02 '20 at 15:18
  • Providing glue between Chromium and Node is *much* less work than transfering all of the features of one into the other … and then keeping it up to date as new upstream releases of both projects are released. – Quentin Nov 02 '20 at 15:20
  • @Quentin this isn't quite correct as the renderer process _can_ have access to the node APIs as well. It is often the case that it is a better idea to only do that in the main process, but that will depend on your preference and what you are doing. You certainly can access `net` (and `fs`, `http` etc) from the renderer process should you chose to, so long as `nodeIntegration` is enabled. – Euan Smith Nov 05 '20 at 12:12
  • @EuanSmith while you make a valid point, please note that enabling `nodeIntegration` disables the sandbox environment. It allows anything running in your web environment to access the node runtime, which is a severe security risk. I would advise to never enable it. – thomaux Sep 22 '22 at 13:47
  • 1
    @thomaux a valid warning, and I would also advise never to do it if you access anything at all served from the web. I've built electron apps before that ONLY serve local content I'm completely in control of. For a simple app, where the separation between the node and web processes is overkill, this is fine. Bigger apps, or cases where ANY web content is accessed and served, I fully agree don't enable `nodeIntegration` – Euan Smith Sep 28 '22 at 13:44
1

Weback may be trying to bundle net. Two things to try:

In vue.config.js configure the externals option with webpack. (note you may neet commonjs2 in the option below, see the externals documentation for more info)

module.exports = {
  configureWebpack: {
    externals: {
      net: 'commonjs net',
    }
  },
}

Alternatively (and less recommended, but has worked in the past when finding the right webpack settings has proved stubborn), rename require so that webpack ignores it:

const _require = require;
//...
const net = _require('net');
Euan Smith
  • 2,102
  • 1
  • 16
  • 26
  • Thanks, but if I add the `externals` part it outputs another error: `require is not defined`. Google said I'd have to specify, but I tried `target: 'node'` (which resulted in `exports is not defined`) and `target: 'web'` (which resulted in undefined require, again). **Edit**: I'd rather not overwrite `require`. There has to be another way? – Johannes Stricker Nov 02 '20 at 13:19
  • 1
    Glad to see see you've now got an answer which works ;). You _can_ access the node modules from the renderer (we do in our application) but indeed it is often a better pattern to keep that access to the main process. The second approach is often helpful when trying to find what your problem actually is and so you then know at least where to focus to find a better solution. – Euan Smith Nov 03 '20 at 08:44
  • Honestly, I'm still struggling a bit with this. One thing I'm confused about: I can use installed node modules in the renderer process (Vue, for example), right? These modules could themselves be requiring native node modules, right? So how does that work? – Johannes Stricker Nov 03 '20 at 12:43
  • 1
    Webpack is used to bundle. Vue would be bundled into the render process, so actually the render code has no actual `require` or `import` statements for this. Where you get a problem is with internal node modules like `fs` and, as you found `net`, and therefore also with not modules which themselves use internals or those which bind to other low-level interfaces (we use `keytar` which comes into this category). Using `externals` basically says to webpack to leave the require in place. For this to work in the renderer process it needs to have the node environment enabled. – Euan Smith Nov 05 '20 at 11:54