I'm developing a Node.js application that contains a game engine, and I basically have this pattern in my engine:
A.js
var B = require('./B');
var A = module.exports = function () {
this.b = new B;
console.log(B.staticBar)
};
A.staticFoo = 'foo';
B.js
var A = require('./A');
var B = module.exports = function () {
console.log(A.staticFoo);
};
B.staticBar = 'bar';
So I want both A.staticFoo to be accessible in B.js and B.staticBar in A.js.
Any idea how to do that?
Thanks
EDIT : actually my static variables are config values, so another solution would be to group them into a config.js file and require that file in every other file, but I find it more elegant to define config variables directly as static members of related classes. Hope that's clear enough ;)
I would suggest separating your static state into a third module... By decoupling state from your module, you can operate either independently.
state.js
//state.js - changed by other modules...
module.exports = {
staticFoo: null,
staticBar: null
};
a.js
//a.js
var state = require('./state');
exports = module.exports = fnA;
...
function fnA() {
console.log(state.staticBar);
}
b.js
//b.js
var state = require('./state');
exports = module.exports = fnB;
...
function fnB() {
console.log(state.staticFoo);
}
Another example mentions something akin to dependency injection... given how modules work in JS, and that you can override for testing with proxyquire and the like, I tend to prefer the simpler requires structure over dealing with DI/IoC in JS as it muddles your project code.
I also like to do my requires, then my exports, then any methods within that module, usually just one method in a module.
It would depend on the architecture of your code. BUT, working with other people's code is always different of course.
The best choice is to separate your code into smaller module(s). If they're referencing each other it can challenging to build tests especially when the code grows.
OR
If that's not possible you could always remove coupling through the use of references.
B.js
var _A;
exports.setA = function(ref) {
_A = ref;
};
var B = exports.B = function () {
console.log(_A.staticFoo);
};
And use B.setA(A) to make sure B has a reference to use A.staticFoo
Related
I'm writing a node program and I want several functions contained in separate files to access and modify the same scope of variables without defining them in the global scope.
The solution I found is using a module to share its scope but it seems a bit tricky.
Here's the file tree :
- index.js
- file-a.js
- file-b.js
- shared-scope.js
index.js :
require('./file-a')
require('./file-b')
file-a.js :
const sharedScope = require('./shared-scope');
sharedScope.foo = 'bar'
file-b.js :
const sharedScope = require('./shared-scope');
console.log(sharedScope) // Prints { foo: 'bar' }
shared-scope.js :
module.exports = {};
What do you think about it? Is this a good way of sharing a scope between modules?
Sure, that's called a singleton. Some might say that any global, shared state is bad, but if that's what you want, this is a perfectly fine and simple way to do it.
The most obvious alternative is to define the data in one place and then in other modules, define functions which work on the data.
file-b.js:
module.exports = function (data) {
data.foo = "bar";
}
index.js:
const assignFoo = require('./file-b.js');
const data = {};
assignFoo(data);
I am taking first steps with node.js and obviously one of the first things i tried to do was exporting some data from a module, so i tried this simple case:
dummy.js:
var user = "rally";
module.exports = {
user:user
};
and than required it from a different file like this:
var dummy = require('./dummy.js');
console.log(dummy.user); // rally
So far so good, every thing works, but now i dived into code where there is this definition in the beginning of the module:
module.exports = function(passport,config, mongoose) {}
and i don't understand whats the meaning of it and how can i work with it.
just for trying to understand i defined some variables inside this abstract function but couldn't get their value from any other file.
any idea how can i export variables from module defined like this..? so for example i could require this module and get the "Dummy" variable and use it in a different file
module.exports = function(passport,config, mongoose) {
var dummy = "Dummy";
}
It works exactly the same as the first one does, only that it exports a function instead of an object.
The module that imports the module can then call that function:
var dummy = require('./dummy.js');
dummy();
any idea how can i export variables from module defined like this..?
Since functions are just objects, you can also assign properties to it:
module.exports = function(passport,config, mongoose) {}
module.exports.user = 'rally';
However I'd argue that this is less expected if a module directly exports a function. You are probably better off exporting the function as its own export:
exports.login = function(passport,config, mongoose) {}
exports.user = 'rally';
WHAT IS A MODULE?
A module encapsulates related code into a single unit of code. When creating a module, this can be interpreted as moving all related functions into a file.
// dummy.js
var exports = module.exports = {};
The utility of dummy.js increases when its encapsulated code can be utilized in other files. This is achieved by using exports.
HOW ARE THEY INVOKED?
You could declare your functions outside of the module.exports block. Functions inside exports can be invoked exactly the same way as variables or any other object.
EXAMPLE
//dummy.js
var myVariable = "foo";
var myFunction = function(){
//some logic
};
module.exports{
myVariable : myVariable,
myFunction : myFunction,
myVariableTypeTwo : "bar",
myFunctionTypeTwo : function () {
//some logic
}
}
We can now access the publicly available methods of dummy.js as a property from any js file.
var dummy = require('./dummy.js');
dummy.myVariable; //foo
dummy.myFunction();
dummy.myVariableTypeTwo; //bar
dummy.myFunctionTypeTwo();
NOTE
In the code above, we could have replaced module.exports with exports and achieved the same result. If this seems confusing, remember that exports and module.exports reference the same object.
In one of my JS files I include another one. How can I set variables in the included module?
I thought doing something like this would work
var mymodule = require('mymodule.js');
mymodule.myvariable = 'test';
And then in mymodule
this.myvariable === 'test';
But this doesn't work, it's undefined. What are the various options for passing a value into a module? I could just add the variable as a parameter to every function I call in mymodule, but that isn't ideal.
Is there a way to do it without globals, so that I can set the variables independently in various required modules, like this?
var mymodule1 = require('mymodule.js');
var mymodule2 = require('mymodule.js');
mymodule1.myvariable = 'test1';
mymodule2.myvariable = 'test2';
The problem with what you were doing is that you set the variable after importing, but this.myvariable === 'test'; was being called when the module was imported, before your variable was set.
You can have your module export a function and then call the function when you import, passing your variable as an argument.
module.exports = function(myVar) {
var myModule = {
// has access to myVar
...
};
return myModule;
};
When you import,
var myModule = require('myModule')(myVar);
If you use this method, keep in mind that you get a different instance of your module wherever you import, which may not be what you want.
If you want to set values of a module from outside the module, a good option is to have your module export an object with a setter method, and use that to set the value of the variable as a property of the object. This makes it more clear that you want this value to be settable, whereas just doing myModule.myVar = can set you up for confusion later.
module.exports = {
myVar: null,
setMyVar: function(myVar) {
this.myVar = myVar;
},
...
};
In this case you're accessing the same instance of the model wherever you import it.
Edit in response to comment
In the first option you show where you get a different instance each
time, how can I export multiple functions that each share the same
myVar? If that module exports 5 functions each that need myVar, can I
set it in one place like at import time rather than passing it into
each function?
Not entirely sure if I understand what you're describing, but you could do something like this:
module.exports = function(myVar) {
var modules = {};
modules.someModule = {...};
modules.anotherModule = {...};
...
return modules;
};
Each of these sub-modules would have access to the same myVar. So you would import as above and the result would be an object containing each of your five modules as properties. I can't say whether this is a good idea, it's getting pretty convoluted, but maybe it makes sense for your situation.
NodeJS require() will always load the module once so you will need to implement scoping into your module where different instances of the module can exist with their own internal state.
You can implement your module as a JS class like:
var MyModule = function(){};
MyModule.prototype.someFunction = function(params){
this.someVar = params;
}
MyModule.prototype.anotherFunction = function(key, value){
this[key] = value;
}
module.exports = MyModule;
Then in your code;
var MyModule = require('MyModule');
someModule = new MyModule();
// treat someModule like an object with its getters/setters/functions
Should work just fine. Here is a working example:
index.js
var module = require('./module.js');
module.myvar = 'Hello world';
module.test();
module.js
module.exports = {
test: function() {
console.log('var is', this.myvar);
}
};
Keep in mind if you use this in a closure that the scope isn't any longer the module itself. So that could be your problem.
Can you show me the part of the module code where you use this?
This is a module named StrUpperCase.js
exports.StrUpperCase = function(str) {
return str.toUpperCase();
}
In app.js:
var str = "Welcome World...";
const SUC = require('./modules/StrUpperCase');
console.log(SUC.StrUpperCase(str));
I am looking for the best way to employ global configuration settings in my Node applications. In order of (my) preference the ways i have found are:
Attach config to global object
global.config = {
db: require('./config/db'),
server: require('./config/server'),
session: require('./config/session'),
auth: require('./config/auth')
};
Pass config object to modules that need it.
var config = {
db: require('./config/db'),
server: require('./config/server'),
session: require('./config/session'),
auth: require('./config/auth')
};
var responder = require('./responder')(config);
Require config files in each module. Since I usually split my config into seperate files I really do not like doing this. Since I dont always use certain files this also usually involces checking if files exist.
Is there any reason why one should avoid either of these methods? Is there any reason why one should be preferred over the others?
In my experience it is common use and good style to go with the option No. 2: Pass config options to modules that need it you suggested.
Reasons:
It decouples configuration from actual logic. If you include configuration files within
the module itself, there's a needless dependency to one specific configuration file.
There's still a defined dependency on specific configuration values which are provided as parameter - and not "magically" pulled from a global namespace which makes code hard to read, maintain and test.
This is by the way a rule of thumb for almost every language that allows things like global variables/objects and constructs for including "everything you like everywhere you like". But requirejs already pushes you a bit into the right direction by at least allowing exports to be a function that immediately accepts configuration. So the one-liner is an elegant way for requiring and configuring resources.
Everything beyond that would probably end up in a discussion about dependency injection (DI) concepts - which is a separate topic.
For small project all three ways are acceptable. For big I can say next:
Global variable is a problem
If you start to use this way, you need to defend config object like var config = {...}; config.freeze();. In any cases global variables is a bad practice, for NodeJS especially, because it destructs modular system.
Passing config is the best way
That is the reason? TESTING
In tests you need to get some states of your config file. The first and third ways provides you next code style:
config.js
module.exports= {
a: 10
};
app.js
var config = require('config');
module.exports.func = function(){
if (config.a > 10) return 'A';
return 'B';
}
Mocha+Chai test
var expect = require('chai').except,
config = require('config'),
app = require('app');
describe('Func', function(){
it('return "A" if a > 10', function(){
config.a = 12; //DHOOO!!! (c) Homer Simpson
expect(app.func()).to.equal('A');
});
it('return "B" if a <= 10', function(){
config.a = 9;
expect(app.func()).to.equal('B');
});
config.a = 12; //return default state of config. DHOOO!!!
});
How you can see you need to have editable config, that is a bad practice (big project where each developer can change state of config in any place... DHOOO!!!)
And for second way it looks like this:
config.js
var config = {
a: 10
};
config.freezy();
module.exports = config;
app.js
module.exports.func = function(config){
if (config.a > 10) return 'A';
return 'B';
}
Mocha+Chai test
var expect = require('chai').except,
app = require('app');
describe('Func', function(){
it('return "A" if a > 10', function(){
expect(app.func({a:12})).to.equal('A');
});
it('return "B" if a <= 10', function(){
expect(app.func({a:9})).to.equal('B');
});
});
UPDATE
In this example func is very syntetic, for real project you can see something like this:
module.js
var SubModule = require('submodule');
function MyModule(config, someVar) {
//Don't use full config, only options you needed.
//Pull out config options
this._a = config.a;
this._b = config.b;
this.doSomethink(someVar);
this.subModule = new SubModule(config);
}
MyModule.prototype.doSomething = function(){
if (this._a > 10) return 'A';
return 'B';
}
module.exports = MyModule;`
submodule.js
function MySubModule(config) {
this._c = config.c;
}
module.exports = MySubModule;
I have following structure for my client;
var myObject = (function(){
var mainObjectList = [];
var globalObject = {
init:function(mainObjectId){
var logger = {};
var utilityObject1 = {};
var utilityObject2 = {};
var mainObject = {};
mainObjectList.push(mainObject);
},//init
someOtherMethods:function(){}
};//globalObject
return globalObject;
})();
with my client I can say
myObject.init(5);
and create a new structure.
My problem is I have a lot of utility objects inside init function closure (logger, utilityObject1, utilityObject2..). My total file exceeded 1000 lines so I want to separate all utility objects into different files to have a better project. for example I could separate logger, utilityObject1 , utilityObject2 to their own files. the problem is since objects are in closure I cannot just add them to main object in separate files. so I thought of following injection method.
//start of file1
var myObject = (function(){
var mainObjectList = [];
var globalObject = {
init:function(mainObjectId){
var logger;
var utilityObject1 = {};
var utilityObject2 = {};
var mainObject = {};
mainObjectList.push(mainObject);
},//init
someOtherMethods:function(){},
injectLogger:function(creator){
this.logger = creator();
}
};//globalObject
return globalObject;
})();
//start of file2
myObject.injectLogger(function(){return {};});
That way I can separate my files for development. but in production I can concatenate files to have one file. But I have some problems with this design. I just added an accessible injectLogger function into myObject. and my logger cannot use other local variables in closure now(I have to pass them to creator object now). My question is is there any other way to separate that kind of code into files. (maybe an external utility.)
I like to use google's closure compiler http://code.google.com/closure/compiler/
If you don't want to use something like that, you might try this sort of thing: (Make sure you load globalObject.js first to define the variable).
//globalObject.js
var globalObject = function() {
}
//init.js
globalObject.prototype.init = function() {
this.utilityFunction();
//do something with utilityObject1
this.utilityFunction(this.utilityObject1);
}
//utilityFunction.js
globalObject.prototype.utilityFunction= function() {}
//utilityObject1.js
globalObject.prototype.utilityObject1 = {};
//main.js
var myObject = new globalObject();
myObject.init();
You could then overwrite the function by doing something like this:
//main.js
var myObject = new globalObject();
myObject.utilityFunction = function() {
//new function
}
myObject.init(); // This will then use the new utilityFunction method you just set.
As I understand it, you want to have some lexical variables that all of your modules close over, but you want to keep the code for the various modules in different files.
One way to achieve this exact behavior is to create a single Javascript file by concatenating the module definitions together:
Header.js-partial
var myObject = (function(){
var mainObjectList = [];
var globalObject = {
init:function(mainObjectId){
Logger.js:
function Logger() { this.enabled = true; }
Logger.prototype.log = function() {
if (window.console && window.console.log) {
return window.console.log.apply(window.console.log, arguments]);
}
}
etc.
Add other module files as desired. They can reference lexical variables.
Footer.js-partial
}// end init
}; // end globalObject
return globalObject;
})();
In the end you need a script that will concatenate all of these files together into a single js file. There is no other way to get truly lexical variable access in pure Javascript.
A superior alternative
That said, this technique is ripe for confusion and I don't recommend it. Closures are generally meant for closing over local variables, not program-wide variables. If you use a lexical variables declared 1000 lines ago, you will spend some amount of time tracking down where all your variables were declared when running your program. Instead you should probably enclose private, 'global' data in the globalObject. For example, store mainObjectList in globalObject.mainObjectList and reference that in module files.
I recommend a solution like that described by nemophrost. Each file should be valid javascript on its own.
You could use command-line PHP to serve as a preprocessor to combine your files. For example, main.js.php could look like this:
(function() {
<?php require('foo.js.php');?>
})();
and then run the command php main.js.php > combined.js when you want to produce an output file usable for minification and deployment.
This has the advantage that you can load main.js.php onto a server to test a new version of the code without recompiling. You can just put a line at the very beginning of main.js.php to get PHP to send the correct MIME type:
<?php header('Content-type: text/javascript');?>
The way I deal with this problem to check to see if the global object exists and if not create it. This way the order isn't important.
// file 1
var Global_Obj = Global_Obj || {}; // creates empty global object
Global_Obj.An_Obj = { /* stuff */ };
// file 2
var Global_Obj = Global_Obj || {}; // uses created global object
Global_Obj.Another_Obj = { /* stuff */ };