'Socket.IO and Electron : why bidirectional communication websocket don't work in my app?

I'm using express and electron with socket.io I should have a bidirectional communicationwith websocket protocol (101) between my client (in React) and my serve part, but it render me http protocol with GET and POST request (200).

My app is doing HTTP request GET, POST (200), but it should be a websocket (101) like they explain in this doc : https://socket.io/docs/v3/how-it-works/#upgrade-mechanism.

My dependencies :

"name": "test",
  "version": "0.1.0",
  "main": "electron-starter.js",
  "private": true,
  "dependencies": {
    "@material-ui/core": "^4.12.4",
    "@testing-library/jest-dom": "^5.16.3",
    "@testing-library/react": "^12.1.4",
    "@testing-library/user-event": "^13.5.0",
    "chokidar": "^3.5.3",
    "express": "^4.17.3",
    "menubar": "^9.1.2",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "react-scripts": "5.0.0",
    "socket.io": "^4.4.1",
    "socket.io-client": "^4.4.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "electron": "ELECTRON_START_URL=http://localhost:3000 electron .",
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "devDependencies": {
    "electron": "^18.0.1"
  }
}

Request on client

Client part :

port React, {useState, useEffect} from 'react';
import { io } from 'socket.io-client';
import logo from './logo.svg';
import './App.css';

const socket = io('http://localhost:8000');

function App() {

  const [state, setState] = useState()

  useEffect(()=> {
    socket.on('new-remote-operations', (files) => {
      console.log("hello", files?.pathFiles);
      setState(files.pathFiles);
    })

  }, [])

  return (
    <div className="App">
      {state?.map((file) =>
        <div style={{display : "flex"}}>
          <p key={file}>{file}</p>
          <button onClick={() => {
            socket.emit("new-operations-delete", { path: file })
          }}>Delete</button>
        </div>
      )}
      <div>
        <button onClick={()=> {
          socket.emit("new-operations", { pathFiles: state} )
        }}>New operations</button>
      </div>
    </div>
  );
}

export default App;

Serve part :

//Express and Socket IO modules
const express = require("express");
const { createServer } = require("http");
const { Server } = require("socket.io");

const appExpress = express();
const httpServer = createServer(appExpress);
const io = new Server(httpServer, {
  cors: {
    origin: "*",
  }
});

//Chokidar
const chokidar = require('chokidar');

const electron = require('electron');
// Module to control application life.
const app = electron.app;
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
//Library Menubar to set electron-app in a "pop-up-like"
const { menubar } = require('menubar');

const mb = menubar({
  index: process.env.ELECTRON_START_URL,
  browserWindow : {
    width: 400,
    height: 400
  },
  icon: "images/favicon-20x20.png"
});

mb.app.on('ready', () => {
  console.log("is listening")
});

// Quit when all windows are closed.
mb.app.on('window-all-closed', function () {
    // On OS X it is common for applications and their menu bar
    // to stay active until the user quits explicitly with Cmd + Q
    if (process.platform !== 'darwin') {
        mb.app.quit()
    }
});

mb.app.on('activate', function () {
    // On OS X it's common to re-create a window in the app when the
    // dock icon is clicked and there are no other windows open.
    if (mainWindow === null) {
        createWindow()
    }
});

//chokidar watcher
const watcher = chokidar.watch('/Users/enzo/Desktop/dossier-1-test', {
  ignored: /(^|[\/\\])\../, // ignore dotfiles
  persistent: true
});

watcher.on('ready', () => {
  console.log("watching")
})

const log = console.log.bind(console);
// Add event listeners.
let pathArray = [];
let files = { pathFiles : []};

//watcher on add and delete event
watcher
  .on('add', path => {
    console.log(`file ${path} added`)
    pathArray.push(path)
    files = {
      pathFiles: pathArray,
    }
  })
  .on('unlink', path => {
    console.log(`file ${path} removed`)
    pathArray = pathArray.filter( file => file != path)
    files = {
      pathFiles: pathArray
    }
  });

//express and socket io server
appExpress.get('/', (req, res) => {
  res.sendFile("http://localhost:3000");
});

io.on('connection', (socket) => {
  console.log("initial", files)
  //send to front on connect
  io.emit("new-remote-operations", files)
  //request for updates: send new value to front
  socket.on("new-operations", () => {
    console.log("after refresh", files)
    io.emit("new-remote-operations", files)
  });
  //request to delete: send new array without path deleted
  socket.on("new-operations-delete", (data) => {
    console.log("on delete", data)
    pathArray = pathArray.filter( file => file != data.path)
    files = {
      pathFiles: pathArray
    };
    io.emit("new-remote-operations", files)
  })
}); 

httpServer.listen(8000);


I tried to do it with a Node.js server and it works good. But i want to do it with express...



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source