Node.js inherit local variables - node.js

I have a variable in my server.js, lets call it 'a'. When I require a module, it doesn't have access to the variable a. For example:
server.js
myModule = require('./myModule.js');
var a = 'Hello!'
myModule.say();
myModule.js
exports.say = function () {
console.log(a);
}
How can I make it so myModule.js can access the variables in server.js without having function arguments?

server.js:
myModule = require('./myModule.js');
global.a = 'Hello!'
myModule.say();
myModule.js:
exports.say = function () {
console.log(global.a);
}
However, please keep in mind globals are usually discouraged in Node.js (and JavaScript in general). Isn't the point of a module to encapsulate certain functionality? If so, it shouldn't depend on outside variables existing or being defined.
Ideally, you want to pass in the required information into the module via some sort of initialization function or configuration parameters.

Related

Electron variables defined in renderer are incorrectly available in imported modules

I am currently transitioning a script I made in Node.js to Electron. However, I am encountering a problem with variable scope. Variables defined in my Node.js script are not available in my modules unless they are passed or assigned. However, in electron if I declare a variable it will be available in all of my modules without passing or assigning it. For example this Node.js script will correctly fail:
// index.js
var myModule = require('./src/myModule.js');
var myString = 'string';
myModule.run();
// myModule.js
exports.run = function() {
console.log(myString); // Correctly says myString is undefined because it is not declared in myModule.js
}
However, the same code in Electron will print the variable defined in renderer.js:
// renderer.js
var myModule = require('./src/myModule.js');
var myString = 'string';
myModule.run();
// myModule.js
exports.run = function() {
console.log(myString); // Prints 'string' even though it is not declared in myModule.js
}
How can I prevent the variables defined in renderer.js from being available in my modules. I find it makes it very easy for me to create unorganized code.
You need to define the type of your script as module in your html.
<script type="module" src="./renderer.js"></script>
Otherwise renderer.js will use the global scope to save your variable, which is why it was available for myModule.js in your example.
But you can also notice that variables defined in myModules.js will use, like you expect, the local scope. That's because only scripts loaded via the tag will use the global scope.
So another option to do this would be to create a renderer.js which consists only of
// renderer.js
require('./index.js');
and your original nodejs files should work as expected:
// index.js
var myModule = require('./src/myModule.js');
var myString = 'string';
myModule.run();
// myModule.js
exports.run = function() {
console.log(myString); // myString is now undefined
}
But you should be aware that variables defined inside of renderer.js will still use the global scope.

Extend module with global configuration without breaking current usages

I want to extend a current Node.js module with some global config setting being configured once without breaking current usages of this module.
This is the signature of the module:
const myFunction = function(someOptions) { ... };
module.exports = myFunction;
Usage is
const myFunction = require('myfunction');
const result = myFunction(options);
Now I want to set some options on application startup to be used by the module myfunction whenever being required without breaking current usages of the module myfunction.
If possible, I want to avoid using Node.js global.
Functions in JavaScript are just objects, so you can give them properties. This is a little hacky, but it could certainly work for you:
// greeter.js
function sayHello() {
const message = sayHello.message || "Hi";
console.log(message);
}
module.exports = sayHello;
You can now set the config of this function globally as follows:
const sayHello = require("./greeter.js");
sayHello.message = "S'up dawg";
Any subsequent calls to sayHello() after the code above is executed will use the overridden message. This works because calls to require() are cached, so each time you require(./greeter.js); you're getting back exactly the same function object.

Best way to invoke code inside a module in nodejs

From a performance perspective, is there any difference between invoking code by wrapping it in a function and then exporting it:
function doSomething () {
// doing something here
}
module.exports = doSomething();
And just requiring it without any exports? like this:
myModule.js
// Code doing something
file that requires the module:
var doSomething = require('./myModule');
And if the purpose of the code inside the module is to run just once, do I need to store it in a variable?
If you don't need the return value of that function, then you don't have to store it in a variable.
The difference with:
function doSomething () {
// doing something here
}
module.exports = doSomething();
and using:
var x = require('module');
var y = require('module');
vs.
function doSomething () {
// doing something here
}
module.exports = doSomething;
and using:
var x = require('module')();
var y = require('module')();
is that in the first case, the function will be run only once, while in the second case the function will be run twice.
The difference is that if you just include it without module.exports, then the code will execute immediately but be private to the module. You can only access the data if you export it somehow, with module.exports. It can be either a function or a Javascript Object. Essentially, you can view everything within the module as being completely hidden from everything else in your application.
The only shortcut that I know of is for JSON files. If you look here: Module.exports vs plain json for config files, you can see that you can require('file.json') and it will replace the contents of the json file with a Javascript object that you can then use in your application.

Scope of JS Functions outside Node Modules

I know that in Node, if you've got variables defined outside your module.exports, it's still locally meaning it's not poluting the global namespace. It's not public. What's public is what's defined in your module.
However what about functions. Do they act the same as variables? Could function names that live outside module.exports collide?
example:
myFirst.js
var iAmStillPrivate = "private";
module.exports = {
...whatever code I wanna expose through this module
}
function find(somethingId)
{
..some code
};
mySecond.js
var iAmStillPrivate = "private";
module.exports = {
...whatever code
}
function find(somethingId)
{
..some code
};
do the find() conflict and pollute the global namespace?
Should I do this instead?:
mySecond.js
var iAmStillPrivate = "private";
module.exports = {
find: find(id)
...whatever code
}
var find = function find(somethingId)
{
..some code
};
or doesn't it matter throwing it into a variable? good practice? doesn't really matter?
CONCLUSION
mySecond.js (I'm a mother fu**ing module. I create an implicit anonymous function that wraps everything in here when I'm 'required' inside other .js files)
`var iAmStillPrivate = "private";` (no I'm scoped to the module, the root anonymous function that is...)
(module.exports - I'm allowing this stuff to be public. When I say public in node,that is...public in that the stuff in here is accessible to other modules in other .js files or whatever.)
module.exports = {
...whatever code
}
(I'm still a function scoped to the module but I've not been exported so I'm not available to other modules, I only belong to the module (the root anonymous function)
function find(somethingId)
{
..some code
};
Functions in each module of NodeJs are local for that module and do not conflict with functions of other modules with the same name.
Think about it as though the module was wrapped in a function.
Also you really don't need to define a variable for your functions because at the end it doesn't matter, the scope of functions and variables of these two lines are the same and local for module:
var find = function find(somethingId) ...
function find(somethingId) ...
Side Question
Also in you comment you asked about this scenario:
what if I have a function in global scope and a module also has a private function with the same name. do they conflict?
What happens is that inside your module any call to that function will trigger the local function not the global one. once you are outside of that module or inside another modules any call to that function will trigger the global function.
Let's look at it with an example. suppose our Node app starting point is index.js here its content:
echo('one');
require('./include.js')
echo('three');
function echo(txt){
console.log("we are in index.js", txt);
}
And here is a module called include.js:
echo('two');
function echo(txt){
console.log("we are in include.js", txt);
}
if you run this app using node index.js command, the output should be:
we are in index.js one
we are in include.js two
we are in index.js three
See? All the functions are there working as I explained earlier.

NodeJS Functions/Module Include Scope

I'm developing an application with node.js and socket.io. I have built a small-scale project with some variables and functions inside a connection-specific block. These functions have access to the variables declared within that block without the need to pass the values in specifically.
This works fine, and is acceptable for a project of this size. However, as I was trying to clean the code up a bit, I looked into factoring those functions out into their own file and found modules declared by using exports.functionname as described here: http://nodejs.org/docs/v0.3.2/api/modules.html
However, these functions do not have access to the variables within the same block as they normally do when being require()'d in instead of actually being declared in the file.
Is there some way to make functions in an external file behave as if they were declared locally in nodejs?
There isn't without hacking the module system, which is exactly what I did. https://github.com/Benvie/Node.js-Ultra-REPL/blob/master/lib/ScopedModule.js
I can't say I recommend it for production. Basically the issue is more with JavaScript itself. Node wraps modules in a function so they have their own private scope. The only way to share in that scope is to be executed inside that function which wouldn't really work for a module (modular...) system. The only other scope is global which also isn't desirable.
The trick I used to get around it is in changing that wrapper function to have dynamic properties based on an externally defined set of module imports so that from inside the module wrapper all those parameters look like they're magically defined but aren't global.
Node's module wrapper looks like this:
(function (exports, module, require, __filename, __dirname){
/**module**/
})
Where mine simply adds more parameters and ensures they're resolved before executing the module wrapper.
I have it read a file named ".deps.json" in a given folder before loading a module.
An example one would be like this
[{
"providers": [ "./utility/",
"./settings/" ],
"receivers": [ "*" ]
}]
So it will load the modules in those subfolders and then expose each one as a parameter in the wrapper, named based on the filename.
The usual and clean way would be to define a function in your module, that takes the required variables as parameters:
// extracted_file.js
exports.handler = function(param1, param2) {
return param1 + param2;
}
// caller file
var extractedHandler = require('./extracted_file').handle;
var localVar1 = 1300,
localVar2 = 37;
console.log(extractedHandler(localVar1, localVar2));
You can change function scope using toString() and the dreaded eval.
If your functions were in say lib.js as follows:-
var lib = {}
lib.foo = function() { console.log(var1) }
lib.bar = function() { console.log(var2) }
module.exports = lib
In main.js you could have this:-
var var1 = 1
var var2 = 2
var ob1 = require('./lib')
ob1.foo()
ob1.bar()
When you run it the ob1.foo() line gives a ReferenceError, var1 is not defined. This is because the scope of foo() comes from lib.js and not your main js file, and var1 is invisible to it. ob1.foo is a reference to a function with lib.js scope. You need to make a new reference with main.js scope.
To do this convert each function to string and eval it. That will create a new function with the same code but with main.js scope. Here's one way using a setMainScope method which loops through all the functions changing their scope to main.js.
var var1 = 1
var var2 = 2
var ob1 = {}
ob1.setMainScope = function(ob2) {
for(var prop in ob2) {
if( !ob2.hasOwnProperty(prop) ) {continue}
if( typeof ob2[prop] !== 'function' ) {continue}
this[prop] = eval( "(" + ob2[prop].toString() + ")" )
}
}
ob1.setMainScope( require('./lib') )
ob1.foo() // 1
ob1.bar() // 2
Now it all works nicely except eval was used. The scope of foo() and bar() is now main.js and so they 'see' var1 and var2.

Resources