For example I want to use custom logger:
logger = require('basic-logger'),
logger.setLevel('info')
var customConfig = {
showMillis: true,
showTimestamp: true
}
var log = new logger(customConfig)
How to use this logger in other modules instead of console.log ?
Most people advise against using global variables. If you want the same logger class in different modules you can do this
logger.js
module.exports = new logger(customConfig);
foobar.js
var logger = require('./logger');
logger('barfoo');
If you do want a global variable you can do:
global.logger = new logger(customConfig);
global.myNumber; //Delclaration of the global variable - undefined
global.myNumber = 5; //Global variable initialized to value 5.
var myNumberSquared = global.myNumber * global.myNumber; //Using the global variable.
Node.js is different from client Side JavaScript when it comes to global variables. Just because you use the word var at the top of your Node.js script does not mean the variable will be accessible by all objects you require such as your 'basic-logger' .
To make something global just put the word global and a dot in front of the variable's name. So if I want company_id to be global I call it global.company_id. But be careful, global.company_id and company_id are the same thing so don't name global variable the same thing as any other variable in any other script - any other script that will be running on your server or any other place within the same code.
you can define it with using global or GLOBAL, nodejs supports both.
for e.g
global.underscore = require("underscore");
or
GLOBAL.underscore = require("underscore");
I would suggest everytime when using global check if the variable is already define by simply check
if (!global.logger){
global.logger = require('my_logger');
}
I've found it to have better performance
Global variables can be used in Node when used wisely.
Declaration of global variables in Node:
a = 10;
GLOBAL.a = 10;
global.a = 10;
All of the above commands the same actions with different syntaxes.
Use global variables when they are not about to be changed
Here an example of something that can happen when using global variables:
// app.js
a = 10; // no var or let or const means global
// users.js
app.get("/users", (req, res, next) => {
res.send(a); // 10;
});
// permissions.js
app.get("/permissions", (req, res, next) => {
a = 11; // notice that there is no previous declaration of a in the permissions.js, means we looking for the global instance of a.
res.send(a); // 11;
});
Explained:
Run users route first and receive 10;
Then run permissions route and receive 11;
Then run again the users route and receive 11 as well instead of 10;
Global variables can be overtaken!
Now think about using express and assignin res object as global.. And you end up with async error become corrupt and server is shuts down.
When to use global vars?
As I said - when var is not about to be changed.
Anyways it's more recommended that you will be using the process.env object from the config file.
If your app is written in TypeScript, try
(global as any).logger = // ...
or
Object.assign(global, { logger: // ... })
However, I will do it only when React Native's __DEV__ in testing environment.
May be following is better to avoid the if statement:
global.logger || (global.logger = require('my_logger'));
Related
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.
I would like to use updated (and only then) globals among all node modules. How to do that? Questions are in code.
app.js
var data = 'data';
var global = require('glob.js')(data);
// here we are require your globals variables and we corectly 'set them'
console.log(globals.glob1);
// we can use them here
glob.js
module.exports = function(data)
{
var globs = {
glob1 : data.toLowerCase(),
glob2 : data.toUpperCase()
}
return globs;
}
mod.js
var global = require('glob.js'); // I require globals but they are not set...
function funct(someOtherData, someMoreData)
{
var test = global.glob1;
console.log(test);
// why I can't use globals here ? How can I use corectly set globals (globals need to be updated first - app.js, then ALL other modules should be able to use correctly set globals)?
}
module.export = funct;
For the answer scroll down to the TLDR section below but do read on to understand why.
Part1 - the difference between a function and a function call
Your first mistake is that you are exporting a function, not an object:
module.exports = function(data) // <---- this is a function
{
var globs = {
glob1 : data.toLowerCase(),
glob2 : data.toUpperCase()
}
return globs;
}
and in app.js you do this:
console.log(globs.glob1); <--- globs is a function, not an object
when you should be doing this:
console.log(globs().glob1);
Why is this? OK, lets forget for a moment your module. Consider the following code:
var a = function(){ return 2 };
console.log(a); // do you expect this to print a function or 2?
console.log(a()); // what do you expect this to print?
This is a very basic rule about functions in all programming languages, not just javascript: to get the return value you need to call the function. So in your code:
function myExportedFunction (data) {
// some logic here...
return globs;
}
console.log(myExportedFunction); // prints a function
console.log(myExportedFunction()); // prints the globs object
console.log(myExportedFunction().glob1); // prints value of glob1
So it's simple really. There is no magic syntax going on. You've just forgotten to return the glob object and are using the function pointer instead. Obviously the function has no glob1 property so it's correct for it to be undefined.
Part2 - function local variables
OK. So let's say you made the changes I recommended above. There's an obvious problem with the way the function was written. What happens when you do this:
var glob = require('glob.js')();
console.log(glob.glob1); // <--- prints "undefined"
So the first problem is you're not checking if you're passing data or nothing. So every time you call the function you will overwrite the stored value.
There's another problem, you are always returning a different object every time you call the function. Let's look at how local variables work when returned:
function a () {
var data = {}
return data;
}
var x = a();
var y = a();
x.testing = 1;
y.testing = 2;
console.log(x.testing); // prints 1
console.log(y.testing); // prints 2
So, every time you call a function that creates a local variable you are returning a different object. Actually what's doing this is not really the variable but the object literal syntax:
var a = {};
// is basically the same as
var a = new Object();
If we change the above example to:
function a () {
return {};
}
it would still behave the same.
TLDR
So, how do we fix it? Simple, create the object outside of the function and check if we pass data to initialize:
var globs = {
glob1 : "",
glob2 : ""
}
module.exports = function(data)
{
globs.glob1 = data.toLowerCase();
globs.glob2 = data.toUpperCase();
return globs;
}
Now everything should work:
In app.js
var global = require('glob.js')(data);
In mod.js
var global = require('glob.js')();
Epologue - modules are singletons
It may or may not be obvious to you why the above should work. In case you already know why I'm writing this as reference to future readers.
In node.js modules are implemented as proper singletons. Therefore in node if you want a singleton all you need to do is write a module, you don't need to implement any special code for it.
What this means is that all module globals (module scoped variables) are shared amongst all requires. Here's a very simple module to share one variable amongst all modules:
shared.js
var x = "";
module.exports = {
set: function (val) {x=val},
get: function () {return x}
}
a.js
var shared = require('./shared');
shared.set("hello world");
b.js
var shared = require('./shared');
console.log(shared.get()); // prints "hello world"
We're using this feature to declare a shared glob variable in the code above.
You can use the global. variable identifier to set global variables in NodeJS, instead of var, example:
app.js
var data = 'data';
var glob = require('./glob.js');
glob(data);
// here we are require your globals variables and we corectly 'set them'
console.log(global.gl.glob1);
var mod = require('./mod.js');
mod();
// we can use them here
glob.js
module.exports = function(data)
{
console.log("setting globals");
global.gl = {
glob1 : '1' + data,
glob2 : '2' + data
}
// return global.gl; // can be removed
}
mod.js
function funct(someOtherData, someMoreData)
{
var test = global.gl.glob1;
console.log(test);
test = global.gl.glob2;
console.log(test);
// why I can't use globals here ? How can I use corectly set globals (globals need to be updated first - app.js, then ALL other modules should be able to use correctly set globals)?
}
module.exports = funct;
As you can see in glob.js, i switched to var globs = to global.gl = and then in mod.js used it as global.gl.
Running app.js outputs:
setting globals
1data // From app.js
1data // From mod.js imported in app.js
2data // From mod.js imported in app.js
There are 2 options:
Use nodejs global variable (not recommended)
Create shared module
You chose 2nd option, but did it a bit wrong way by exporting a function. When you import the package and call the function it always creates new globs object and fulfill it with your data. Instead you can export an object. Simple example
glob.js
Global object is defined here
module.exports = {
glob1: '1',
glob2: '2'
};
mod.js
You can change global object here, like
var globs = require('./glob');
module.exports.updateGlob1 = function(data) {
globs.glob1 = data;
};
app.js
Here if you access global variable you can see it updated
var globs = require('./glob');
var mod = require('./mod');
mod.updateGlob1('1 plus 2');
console.log(globs.glob1); // Output: '1 plus 2'
There can be more complex examples, as for module design pattern often IIFE is used.
UPDATE
Another example using IIFE.
glob.js
module.exports = (function() {
var glob1 = 'initial value';
return {
// Getter method
getGlob1() {
return glob1;
},
// Setter method
setGlob1(value) {
glob1 = value;
}
}
})();
mod.js
var shared = require('./shared');
module.exports.testFn = function() {
// Access global variable with getter method
console.log('In mod.js', shared.getGlob1());
};
app.js
var shared = require('./shared');
var mod = require('./mod');
// Print initial value
console.log('Initial', shared.getGlob1());
// Set new value to global variable
shared.setGlob1('new value');
// Print updated value
console.log('In app.js', shared.getGlob1());
// Use global variable in mod.js file
mod.testFn();
My log.js,
var data ;
var winston = require('winston');
var config = {'status':1};
module.exports.config = config;
My get.js file(from where i want to modify log.js),
exports.getcategories = function (req, res) {
if(log.status == 1){
var data = 'loaded successfully';
}
};
Here i want to modify my data variable in log.js from my get.js,can anyone please suggest help.
You need to read up on Javascript scopes. In order to access any variable in a file or function from outside it, there are only two ways:
Make the variable global (NOT a good idea).
Create getter/setter functions and export them, thereby exposing it to the outside world
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.
I'm using Express and Passport for node.js to build a simple web server, I coded a simple module and then I loaded the module inside a GET request, everything works great until more than one user access the request.
I use to believe that a "var" inside an "app.get" function was removed from memory after the function finished, but isn't the case, I use some local variables inside the external module and the values are being shared between users, the module looks like this:
var some_value=0;
function some_method(){
some_value++;
return some_value;
}
exports.some_method = some_method;
And the Express request code looks like this:
app.get('/someurl', function(req, res) {
var some_extermal_module = require('/some_extermal_module'); // <-----Right way?
var data = some_extermal_module.some_method();
res.render('view', {
title : 'Title',
data_to_vew: data
});
});
An object inside a "app.get" request stays always in memory regardless of is being accessed by a different user?
How to clean a "var" object after it runs?
How can I avoid this memory conflicts?
Do I have to code differently the module or call differently the module?
Thanks a lot.
UPDATE: I guess this is a proper solution but I need the review of some node.js/Express expert for approval it or correction.
app.js:
var ext_mod = require('./module');
var express = require('express');
var app = express();
app.get('/', function(req, res){
var ex_mod_instance = new ext_mod({});
ex_mod_instance.func_a({},function(ret){
res.send('Hello World: '+ret);
});
ex_mod_instance = null; // clean
});
app.listen(8080);
console.log('Listening on port 8080');
module.js:
var node_module = function(config) {
this.config = config;
this.counter=0;
};
node_module.prototype = {
func_a: function(param,done) {
this.counter++;
done(this.counter);
},
func_b: function(param,done) {
}
};
module.exports = node_module;
Is this the best way to save memory (leaks)?
Every time a function is called you do get "clean" local variables in the local scope. Modules are for the purpose of writing clean, organized code, so that you do not have every function and variable in the global scope. I believe require does cache the module, so maybe you are having a problem with variables in the closure around the function exported from the module. You'll have to include more code.
One way you could solve this is by exporting a function that creates the module. That function could be your constructor, which will scope your counter locally.
Again, this is one solution.
Your variable 'some_value' is global in the context of the module. So each time a request use this module, it uses the same variable.
(Require does cache the modules wich are loaded only the first time)
I can think of 2 ways to achieve this:
either you want one variable per request, and you declare this variable in the module function, or in the res.locals.some_value if you want to use it in many functions during the same request
either you want one variable per user, and then you need to use express session middleware, and add the variable to req.session.some_value