I'm creating an Electron application that uses Socket.io to communicate to a server application, but I'm experiencing a weird issue: whereas my Electron app successfully joins and receives messages from my server, it completely fails to emit anything.
Client-side:
const io = require('socket.io-client');
// ...
var socket = io("http://localhost:8081");
socket.on('welcome', () => {
console.log('welcome received'); // displayed
socket.emit('test')
});
socket.on('error', (e) => {
console.log(e); // not displayed
});
socket.on('ok', () => {
console.log("OK received"); // not displayed
});
socket.on('connect', () => {
console.log("connected"); // displayed
socket.emit('test');
});
Server-side:
io.on('connection', (client) => {
io.emit('welcome');
client.on("test", () => {
console.log("received test"); // not displayed
io.emit("ok");
})
});
io.listen(8081);
Note that there is also a Web client that connects to the server, and works absolutely as expected.
What am I doing wrong?
Electron has the main process that can have node integration and renderer process that has nodeIntegration
turned off by default for security reasons.
If you try to use your client code in the main process (main.js) it will work and receive/emit normal. But if you try to use the client code on the rendered process, then it won't work. You need to add the client code inside the preload.js
and then preload it using the webPreferences.preload
option of the BrowserWindow
like this:
function createWindow () {
// Create the browser window.
mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
// and load the index.html of the app.
mainWindow.loadFile('index.html')
...
}
Then you can have the client code inside preload.js
:
const io = require('socket.io-client');
const socket = io(`http://localhost:${process.env.SOCKET_PORT}`);
socket.on('welcome', () => {
console.log('on welcome : welcome received renderer'); // displayed
socket.emit('test')
});
socket.on('error', (e) => {
console.log(e); // displayed ?
});
socket.on('ok', () => {
console.log("OK received renderer"); // displayed
});
socket.on('connect', () => {
console.log("connected renderer"); // displayed
socket.emit('test');
});
begin the socket, start the electron app and see it working:
Beware of the Content Security Policy (CSP):
To avoid this, you have to add your WS server to your CSP. For localhost use this inside index.html
header:
<meta http-equiv="Content-Security-Policy" content="default-src 'self' ws://localhost:*/socket.io/; script-src 'self' ws://localhost:*/socket.io/">
<meta http-equiv="X-Content-Security-Policy" content="default-src 'self' ws://localhost:*/socket.io/; script-src 'self' ws://localhost:*/socket.io/">
It's a localhost server for all ports and of course it's for development only, you have to enter normal WS server in production.
You can clone and check my working example from Github: https://github.com/clytras/electron-sockets
EDIT Last but not least; check and allow incomming/outgoing access for nodejs and/or port in firewal.
Electron version: 7.1.2
Node version: 12.8.1
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With