Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

require() node module from Electron renderer process served over HTTP

Typically, in an Electron app, you can require node modules from both the main process and the renderer process:

var myModule = require('my-module');

However, this doesn't seem to work if the page was loaded via HTTP instead of from the local filesystem. In other words, if I open a window like this:

win.loadURL(`file://${__dirname}/index.html`);

I can require a node module without problems. But if I instead open a window like this:

win.loadURL(`http://localhost:1234/index.html`);

I no longer can require node modules inside my web page - I get Uncaught Error: Cannot find module 'my-module' in the web page's console. Is there any way to use node modules in an Electron page that was served over HTTP?


A little context: My company is building an application that needs the ability to be hosted as a web application and inside an Electron shell. To make this simpler and consistent across both environments, my Electron app starts a local web server and opens the app hosted at http://localhost:1234. Now I'd like the ability to add spell checking/spelling suggestions into the application using electron-spell-check-provider. This module needs to be imported and initialized inside the renderer process, so I'm trying to require('electron-spell-check-provider') inside my web page, but this fails with the Cannot find module error.

like image 327
Nathan Friend Avatar asked Sep 07 '16 12:09

Nathan Friend


2 Answers

Finally figured this out. In the main process, figure out the absolute path to the node_modules directory, as in:

var nodeModDir = require.resolve('some-valid-module');
var dirnm      = 'node_modules';
var pos = nodeModDir.lastIndexOf(dirnm);
if(pos != -1)
    nodeModDir = nodeModDir.substr(0, pos+dirnm.length+1);

Now get this path to the renderer process via some IPC. Finally, in the renderer you can now require using an absolute path:

var mymod = require(nodeModDir+'some-valid-module');

Works perfectly for me with electron 1.6.7.

like image 148
logidelic Avatar answered Oct 03 '22 08:10

logidelic


You can add a preload-script which adds a property to the global/window variable. I named mine appRoot. appRoot just has the __dirname value of the preload-script. You then have to go from the folder of the preload-script to your module. I simply use path.join() to make it clean.
This is similar to @logidelic's approach, but without having to mess with IPC messages.

main.js

mainWindow = new BrowserWindow({
  webPreferences: {
    preload: 'preload.js'
  }
})

preload.js:

global.appRoot = window.appRoot = __dirname

index.html:

<script>
  const { join } = require('path')
  require(join(appRoot, 'rendererApp'))
</script>
like image 34
RoyalBingBong Avatar answered Oct 03 '22 09:10

RoyalBingBong