Separating socket IO calls for cleaner code in Node and Express

950 views Asked by At

So, I'm making an app and I have gotten socket IO working and the app just runs on Express.

Anyway, within the main server file is where I am doing my calls. Some examples:

//Object 1
io.of('/type1').on
(   'connection', socket => 
{   socket.on
    (   'call1', () =>
        {   doSomething1();
        }
    );
}
);

// Object 2
io.of('/type2').on
(   'connection', socket => 
{   socket.on
    (   'call2', () =>
        {   doSomething2();
        }
    );
}
);

Obviously, there are way more socket.on calls for the various objects. What I wanted to do was actually separate these objects' logic from the main loop into some separate files to better clean up the main server.js file I have. I've got some 300 lines of various socket calls.

Something like socketCalls1.js for Object 1, etc.

The only thing is that the io variable doesn't seem sharable across multiple files... Is there a good, clean way of doing this?

1

There are 1 answers

1
slebetman On BEST ANSWER

The only thing is that the io variable doesn't seem sharable across multiple files...

This is not true. You can pass the io variable into functions and out of modules just like any other variable. Also like any other variable it is automatically privately scoped to a single file.

There are several ways to share objects across files and if you've gotten this far I'm sure you've used most of them. Only maybe you may not have realized what you have been doing.

Method 1: pass io into functions.

One way to split your logic is to split it across several modules. Since you can pass objects into functions your modules should export functions. For example:

  • file1: type1.js

    function init (io) {
      io.of('/type1').on
      (   'connection', socket => 
      {   socket.on
          (   'call1', () =>
              {   doSomething1();
              }
          );
      }
      );
    }
    
    module.exports = init;
    
  • file2: type2.js

    function init (io) {
      io.of('/type2').on
      (   'connection', socket => 
      {   socket.on
          (   'call2', () =>
              {   doSomething2();
              }
          );
      }
      );
    }
    
    module.exports = init;
    
  • main.js

    const type1 = require('./path/to/type1.js');
    const type2 = require('./path/to/type2.js');
    
    // some code to init your app ...
    
    type1.init(io); // pass io to type1 module
    type2.init(io); // pass io to type2 module
    

This works because io is just a regular variable. And just like any variable you can pass it as a function argument. Nothing here is fancy, this is all basic features of programming languages.

Method2: share io as a module.

Another technique is specific to how modules work in node.js. Modules are singletons in node. What that means is that a module represents exactly one object. If 3 different files require()s the module they will all get the same object.

We can use this to share the io object between modules:

  • file1: server-init.js

    let app = require('express')();
    let http = require('http').Server(app);
    let io = require('socket.io')(http);
    
    module.exports = {
        app: app,
        http: http,
        io: io
    }
    
  • file2: type1.js

    const io = require('./path/to/server-init').io;
    // Alternatively you can use the syntax:
    // const { io } = require('./path/to/server-init');
    
    function init () {
      io.of('/type1').on
      (   'connection', socket => 
      {   socket.on
          (   'call1', () =>
              {   doSomething1();
              }
          );
      }
      );
    }
    
    module.exports = init;
    
  • file3: type2.js

    const io = require('./path/to/server-init').io;
    
    function init () {
      io.of('/type2').on
      (   'connection', socket => 
      {   socket.on
          (   'call2', () =>
              {   doSomething2();
              }
          );
      }
      );
    }
    
    module.exports = init;
    
  • main.js

    const type1 = require('./path/to/type1.js');
    const type2 = require('./path/to/type2.js');
    const { http, app } = require('./path/to/server-init');
    
    // some init code
    
    type1.init();
    type2.init();
    http.listen(PORT);