0

Here's a basic example of what I'm trying to do:

ModuleA.js

module.exports = {
  doX () {
    console.log(data['a']);
  }
}

ModuleB.js

module.exports = {
  doX () {
    console.log(data['b']);
  }
}

server.js

let data = { a:'foo', b:'bar' };

let doX = {};

doX['a'] = require('./ModuleA.js').doX;
doX['b'] = require('./ModuleB.js').doX;

doX['a'](); // Should print 'foo'
doX['b'](); // Should print 'bar'

In the actual implementation there would be many more variables to pass in than just data, so passing that to the functions isn't a viable solution.

This almost works, but the functions in the modules need access to functions and variables at the top level of the server file. I know I could global.variable all of my variables and functions but I'd rather not, as I've only seen people recommend against that. Of course I could pass every single variable and function in each function call, but that would look ridiculous and brings up way too many potential problems. I was hoping I could pass a reference to the server's namespace, by passing this or something, but that didn't work. I could register every function and variable on some object and pass that around, but that's inconvenient and I'm trying to refactor for convenience and organization. I think I could read in the module files and eval them, as seen here, but I would much rather use the standard module.exports system if possible.

John
  • 35
  • 7
  • 1
    Your `data` variable is local to `server.js` and is not accessible to your other two modules. I'd suggest you pass it to them when you load those modules as a means of sharing it with them. That design pattern is typically called a "module constructor" if you want to read more about it. – jfriend00 Sep 14 '18 at 18:45
  • Also, I consider it a confusing coding practice to use the same `doX` name for different types of things in different modules. The two methods with that name are fine, but the `doX` object in server.js just confuses the heck out of things. – jfriend00 Sep 14 '18 at 18:47
  • The idea for doX as an object of functions is that each function in that object will do roughly the same thing, but for a different piece of hardware. They're all almost exactly the same, will take the same parameters and return the same format, but the syntax and response structure for each device is different enough that they need their own functions. Also, as was stated in the question, in the actual implementation there are many variables and functions that would need to be passed, not just the one, so it isn't a viable solution. – John Sep 14 '18 at 18:49
  • 1
    Well, passing data from one module to another is how you achieve shared data with separate modules without using globals. That's how you do it. Since you've now rejected the usual design pattern, there's not much else we can do without understanding a lot more about the real problem so we can go further outside your box and suggest a better design than the path you're down. Abstracting hardware to have a common set of methods sounds like a perfect fit for subclasses where each piece of hardware has its own subclass, all with the same interface. Shared data could be in the base class. – jfriend00 Sep 14 '18 at 18:59
  • I agree, but as it's written I would have to pass around several variables and functions to each function call, as the methods that I currently have are all defined in server.js and make use of objects and functions defined there. I was hoping there was a way to effectively pass server.js' entire namepsace as a single variable, so the modules could at least access the functions through `server.func()` or something, which would be easy enough to tack on at this point. Since that probably isn't the case I'll likely be re-writing the functions to just return some data and handle that in server.js – John Sep 14 '18 at 19:08
  • 1
    You can pass a lot of variables at once if you make them properties of an object and pass just the object. Then, both places can reference the same properties on the same object and you can pass an infinite number of properties by passing one object. There is no way to pass a modules namespace. You have to create your own object with properties on it and pass that. – jfriend00 Sep 14 '18 at 20:27
  • 1
    I still think this lends itself to a base class that contains all the shared data and derived objects for each piece of hardware. – jfriend00 Sep 14 '18 at 20:29
  • @jfriend00 You're right, on Friday I thought about it while at home and defining a class is definitely the way to go. I was trying to morph the existing code into a modular state with as little changes as possible, when I should have just re-done it from the start. Thanks – John Sep 17 '18 at 12:18

2 Answers2

0

I'll summarize my comments into an answer.

Your data variable is local to server.js and is not accessible to your other two modules. I'd suggest you pass it to them when you load those modules as a means of sharing it with them. That design pattern is typically called a "module constructor" if you want to read more about it.

Passing data from one module to another is how you achieve shared data with separate modules without using globals. That's how you do it. Since you've now rejected the usual design pattern, there's not much else we can do without understanding a lot more about the real problem so we can go further outside your box and suggest a better design than the path you're down.

Abstracting hardware to have a common set of methods sounds like a perfect fit for subclasses where each piece of hardware has its own subclass, all with the same interface. Shared data could be in the base class.

You can pass a lot of variables at once if you make them properties of an object and pass just the object. Then, both places can reference the same properties on the same object and you can pass an infinite number of properties by passing one object. There is no way to pass a modules namespace. You have to create your own object with properties on it and pass that. You can create such an object and then set that object into the base class and then all your derived classes can have access to that object.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
0

In short:

module.exports = {
  doX () {
    console.log(data['a']);
                ^^^^ this variable is not available here. You should pass it as argument to make it available.

  }
}
Nurbol Alpysbayev
  • 19,522
  • 3
  • 54
  • 89