Nodejs and Expressjs: Constants in global variable - javascript

Defined in: util/constant.js
module.exports = {
userTypeAdmin: 0,
userTypeUser: 1
};
Required only once in: app.js
...
global.constant = require('./util/constant');
...
Used many times
In: route/index.js
console.log(constant.userTypeAdmin); // Show 0
In: route/user.js
console.log(constant.userTypeUser); // Show 1
Question:
I must removed of app.js: global.constant = require('./util/constant');
and add: const constant = require('../util/constant');
in route/index.js and route/user.js ?
Or that's ok how I am it making?

1. const constant = require('../util/constant');
2. global.constant = require('./util/constant');
Only difference in these,
statement 1 ask you to import the constant package wherever you want to use it.
statement 2 make available constant package globally.so,you can access it without import.
With statement 2,if you modified any properties within constant,it will reflect throughout the application.
So,make sure,you are using global only when you want to share something across the application.
If you want to share the data globally,and don't want this should be change,then delcare each primitive variable with const keyword.In this case,making object const will not help you.
In either case you can exclude it.

Related

Node.js and Modules require. Objects are not assigned by reference?

I'm writing this question after 2 days of total struggling during which I couldn't find a solution but also couldn't find an explanation of why this code is not working.
I will report a super simplified simulation of my code.
I have 5 Node.js files:
1) server.js -> Is the main file used to start the server
2) globalVars.js -> Is where all the server "global" objects are stored.
3) globalFunctions.js -> Is where all "general" functions are stored to be used by all other modules
4) helloManager.js -> Example file which contains some standard function used by the server
5) aspect.js -> Same as helloManager.js
//server.js
//Loading the globalVars file. All objects are passed by reference so I use this to store the global variables
var globalVars = require("./globalVars.js");
//Assigning to the respective global object all the functions exported from other modules
globalVars.Modules.globalFunctions = require("./globalFunctions.js");
globalVars.Modules.aspect = require("./aspect.js");
globalVars.Modules.helloManager = require("./helloManager.js");
//After this point, the objects in globalVars.js will be populated with the respective functions exported from the files
//A timeout just to be sure it is not a problem of timing? (Well, it is not...)
setTimeout(function(){
console.log(globalVars.Modules.helloManager.helloOutput());
}, 2000);
/*
Console will throw the following error:
../globalFunctions.js:6
return "MR. " + aspect.getAspect();
^
TypeError: aspect.getAspect is not a function
*/
//globalVars.js
//Objects that will be populated with the functions inside other modules
module.exports.Modules = {
aspect: {},
helloManager: {},
globalFunctions: {}
};
//helloManager.js
var globalVars = require("./globalVars.js");
var { globalFunctions } = globalVars.Modules;
module.exports.helloOutput = function(){
return "hello " + globalFunctions.getHumanData();
};
//aspect.js
module.exports.getAspect = function(){
return "human";
};
//globalFunctions.js
var globalVars = require("./globalVars.js");
var { aspect } = globalVars.Modules;
module.exports.getHumanData = function(){
return "MR. " + aspect.getAspect();
};
Please don't answer me to put everything in the same file, because my code is way more complicated to report so here I'm posting this very simple simulation.
I know that objects are assigned by reference and so if all modules get the variables from "globalVars" they works kinda like "global".
The problem is when in globalFunctions.js I load
var { aspect } = globalVars.Modules;
Since in server.js the module aspect.js is not loaded yet, it will be an empty object.
But I'm expecting that
var { aspect } = globalVars.Modules;
is getting the reference of globalVars and not a copy, so when server.js finishes loading all the modules, the variabile aspect inside globalVars.Modules will point to the correct object and so it would find the function I need!
Infact the console.log inside server.js is executed after all modules have been loaded for this exact reason.
Does anyone know what is the reason of this problem and how could I solve it?
Thank to everyone who will help!
What's happening
It's an issue of what it means to do const { aspect } = globalVars.Modules; (which is the same as const aspect = globalVars.Modules.aspect;). That is, it's a matter of assignment semantics.
Let's look at a simpler example, then we can see hot it applies to what you're doing. Assume you have:
let a = {/*original object*/};
When you do
b = a;
the value in a is copied into b. That value is an object reference, so they now both point to the same object, but there is no ongoing link between a and b. If you then do
a = {/*new object*/};
that has no effect whatsoever on b, because there's no ongoing link between a (the variable) and b (the variable). b still refers to the original object, not the new one.
The same is true of any assignable item, such as an object property or parameter. That's what's happening with globalVars.Modules.aspect. globalFunctions is grabbing the value (simple assignment semantics, though using destructuring), then server.js is replacing that value with a new one.
Here's how that's happening in your code:
// server.js
var globalVars = (function() {
// globalVars.js
return { // this is the `exports` object
Modules: {
aspect: {}, // *** That's the `a = {/*original object*/}`
}
};
})();
// back in server.js
globalVars.Modules.globalFunctions = (function() {
// globalFunctions.js
const { aspect } = globalVars.Modules; // **** That's the `b = a`
return { // this is the `exports` object
getHumanData: function(){
return "MR. " + aspect.getAspect();
}
};
})();
// back in server.js
globalVars.Modules.aspect = (function() { // *** that's the `a = {/*new object*/}
return { // this is the `exports` object
getAspect: function(){
return "human";
}
};
})();
// back in server.js
globalVars.Modules.globalFunctions.getHumanData(); // Fails because the object it's using
// is the old one, not the new one
How to fix it
globalFunctions.js relies on aspect.js, so have it rely on it directly:
// In `globalFunctions.js`
const aspect = require("./aspect.js");
module.exports.getHumanData = function(){
return "MR. " + aspect.getAspect();
};
Assuming there are no cycles, that'll work.
At a larger level: There may be no reason to have globalVars.Modules at all. A module is only loaded once (normally), so rather than globalVars.Modules, just have each module directly rely on the module it needs, rather than funnelling it all through a central object. Node.js' module cache is already the central object.
If you don't want globalFunctions.js to rely on aspect.js directly (why not?), then don't copy the aspect property from Modules, use it as of when you need it:
// In `globalFunctions.js`
const {Modules} = require("./globalVars.js");
module.exports.getHumanData = function(){
return "MR. " + Modules.aspect.getAspect();
};
That'll work assuming nothing reassigns Modules (which nothing seems to in the code you've shown). But again, it makes more sense to rely on aspect.js directly if you can.
It's kind of fun to note that this is one of the reasons that modern ESM modules don't use simple assignment semantics like CommonJS ones do. ESM wouldn't help your specific thing, because you're using your own globalVars.Modules object instead of using the module objects, but it solves a problem that people often had with CommonJS modules which, like your problem, was caused by expecting b (an imported value) to be affected when reassigning a (the exported value). The issue people would have with CommonJS happened mostly when there were cycles between two modules (circular dependencies, directly or indirectly). ESM solves this by making the imported binding (b in my example) a live binding to the exported binding (a in my example). This is the only place JavaScript has what you could argue is a form of pass-by-reference (references to variables).
As you've noticed, var { aspect } = globalVars.Modules; copies the current value of globalVars.Modules.aspect to the local variable aspect. It's just alternative syntax for var aspect = globalVars.Modules.aspect.
If you later change the value of globalVars.Modules.aspect to a new object (as opposed to mutating the object that is already there) then the local variable doesn't update.
If you want the most recent value then you need to continue accessing globalVars.Modules.aspect whenever you need it.

Setting variable with more than two conditions in JavaScript

First time dealing with this so please bare with me.
I inherited a web application that handles three different environments but shares the same code base. Essentially, it's three different web applications rolled into one - with minor to major adjustments on each environment.
I'm launching the site and the CSS and JS paths linked need to change, to take into account a new domain folder.
I found a variable called 'DOMAINBASE', and some variables above it - please see the code below:
export const isEnvironmentBFE:boolean = checkEnvironment(DEPLOY_ENV.BFE);
export const isEnvironmentTCAT:boolean = checkEnvironment(DEPLOY_ENV.TCAT);
export const isEnvironmentBFERENTAL:boolean = checkEnvironment(DEPLOY_ENV.BFERENTAL);
export const DOMAINBASE = checkEnvironment(DEPLOY_ENV.BFE)
? "https://subdomain.domain1.ca"
: "https://subdomain.domain2.com";
I want to add another condition, in other words another URL to DOMAINBASE, where there is currently only two.
I've tried adding the following condition but does not work:
export const DOMAINBASE = checkEnvironment(DEPLOY_ENV.BFE)
? "https://subdomain.domain1.ca"
: checkEnvironment(DEPLOY_ENV.BFERENTAL) // <-- when new environment is launched
? "https://subdomain.domain1.ca/new-folder" // <-- make it so it uses this structure
: "https://subdomain.domain2.com";
How do I properly add a third condition to this JavaScript variable?
Perhaps try it without the 'export'?
This is working for me when i try from the console
const DOMAINBASE = 5<6
? "https://subdomain.domain1.ca"
: 6<7
? "https://subdomain.domain1.ca/new-folder"
: "https://subdomain.domain2.com";

Unable to export variable from node js module

First of all I have checked all the questions on Stack Overflow regarding this.
I am trying to export variable str whose value is getting updated inside the function to another module but it is showing undefined after exporting it in another file.
But if I update the value of variable outside function then export is working fine.
I have a function with code in file Excel.js
var str='abc';
wb.xlsx.readFile(filePath).then(function()
{
var sh = wb.getWorksheet("Sheet1");
console.log("YOUR LECTURE IS",sh.getRow(goingSlot+1).getCell(DAY+1).value);
//console works fine
str="YOUR LECTURE IS"+sh.getRow(goingSlot+1).getCell(DAY+1).value;
//the assignment here leads to undefined after exporting
}
str="something";
//this successfully exports the value as something
And then I export this to my main file with syntax
exports.str=str;
Incase you need to see code for main file
The code for the main file is
const express=require('express');
const app=express();
const myle=require('./readingExcel.js');
const res=myle.name;
console.log(res);
//CONSOLE SHOWS UNDEFINED
exports.str and str are not the same variable even though you write exports.str = str
var a = 2;
var b = a;
a = 4;
console.log(b) // b is still 2 and not 4
So use exports.str directly instead of str.
exports.str = 'abc'
// ...
exports.str="YOUR LECTURE IS"+sh.getRow(goingSlot+1).getCell(DAY+1).value;
// ...
exports.str = 'something'
I just want to add something to #t.niese's response (which in my opinion is pretty solid).
Check your code for any mode.exports happening after your exports.str assignment. exports and module.exports are usually pointing to the same place, but I always use module.exports. Using exports has the risk of being overwritten somewhere else (module.exports too, but that is the real reference used by node).
https://medium.freecodecamp.org/node-js-module-exports-vs-exports-ec7e254d63ac

module.exports update array

I'm trying to understand module.exports better.
As I understand it, it can be used as a two way communication (you can send and receive data to the module.
However, this is not working as I expected:
File1.js:
var Test = require("./Balances")
Test.push(12)
Balances.js:
var arrays = [10, 11];
module.exports = arrays
File2.js:
var Test = require("./Balances")
setInterval(function(){console.log(Test)},2000)
What I want is to be able to add to the array from File1, and read the output in File2.
File2 reads the initial array just fine, but the value I push never shows in File2.
However, if I add a console.log(Test) in File1, that pushed value does appear there.
Upon rerunning File1, I don't however see [12, 12] , only [ 12 ], which means the first push never got written in the Balances array.
Any idea why?
When you import a variable from another javascript module, you get that variable by value, not by reference (you create a copy of the value at the given memory address, you don't simply get a pointer to that same exact variable). Therefore, you have only mutated the Test variable in File1.js; to reflect those changes in your console.log in File2.js you would have to re-export your mutated variable from File1.js and import that into File2.js, and then do the log.
Here is analysis of your code:
File1.js:
// creates copy of the `Balance.js` `arrays` variable
// stores value in new variable `Test`
var Test = require("./Balances") // => [10, 11]
// pushes 12 to the copy
Test.push(12) // => [10, 11, 12]
File2.js:
// creates copy of the `Balance.js` `arrays` variable
// stores value in new variable `Test`
var Test = require("./Balances") // => [10, 11]
// This interval does nothing. The fact is, the mutated
// `arrays` var from `File1.js` does not effect the
// `arrays` var in any other modules scope.
setInterval(function(){console.log(Test)},2000) // => [10, 11]
This is all assuming you have additional code not seen here that is required and executed from an entry point. As Thomas said in the comments, there is no state persisted between running individual scripts.
To accomplish what you're attempting in your post:
Balances.js:
var arrays = [10, 11]
module.exports = arrays
File1.js:
var test = require('./Balances')
test.push(12)
module.exports = test
File2.js:
var test = require('./File1')
function action() {
console.log(test)
}
module.exports = action
main.js (entry point):
var action = require('./File2')
action() // => [10, 11, 12]
run $ node main.js
Hope this helps!
It had to have never gotten pushed because you didn't actually require File1.js anywhere. This main.js works exactly as expected with the original File1.js, File2.js, and Balances.js files. (You probably wanted setTimeout, and as mentioned that had no effect anyhow, but it does work.)
require('./File1')
require('./File2')
Yes, modifying passed non-primitives updates the original item. They are not copied. Don't spend the next few years on a redundant construct to rebuild what is already happening.
Technically you can use modules like that, but I'd avoid that. Mutating state like that can lead to a lot of problems, especially if it is done in distributed modules.
And out of a sudden you have some error or unwanted behaviour that seems to come out of nowhere. Because its source is in an completely unrelated part of your app. Have fun, finding/debugging that.
I'd rather use modules as read-only sources for configs and stuff, or export a self-contained API that manages these mutations and everything else that happens in that module.
Back to you question
all you need is a common entry point that loads both modules in the same application.
That's probably ýour misconception. every time you call node ... you start a seperate application with seperate memory and state. It loads the files you tell it to, executes the code and eventually finishes. Like opening two sites in the browser, one loading File1, the other one loading File2.
So, you can create a common entry point like main.js
require("./File1");
require("./File2");
and then start the application at that common entry point node main.js
Or you can run node -i -r "./File1" -r "./File2" and start typing more JS.

Node define unique variable that I need to use across the modules

Currently I am just passing my fileNamePrefix like that:
let shortid = require('shortid');
let fileNamePrefix = shortid.generate();
module1.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f1.json`
module2.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f2.json`
module3.run(fileNamePrefix); //generating a file based on `fileNamePrefix` `xxxxx.f3.js
Which I think in not quite right, I might need to pass more things to my modules later on, so I want to avoid to pass that as function params.
What is the best way to approach that in nodejs?
Will global object like global.fileNamePrefix = shortid.generate(); will do in that case or would you approach that different? I just read that global is not good...
You can use either singleton approach or approach suggested by #Сергей Тертичный
Singleton :
//shortid.js
var fileSingleTon = module.exports = {
fileNamePrefix: null,
getFileNamePrefix: function() {
return fileSingleTon.fileNamePrefix || fileSingleTon.generate()
},
generate: function() {
console.log('generating..');
return fileSingleTon.fileNamePrefix = 'your_file_prefix';
}
}
//module1.js
var fileNamePrefix = require('./shortid').getFileNamePrefix();
//do stuff for module1
//module2/js
var fileNamePrefix = require('./shortid').getFileNamePrefix();
//do stuff for module1
and so on..
Even now you are calling require('./shortid').getFileNamePrefix(); multiple times, generate function is getting called only once.
Node Caching approach :
Consider you have shortid.js as following :
// A: block of code to do some manipulations
// B : module.exports = manipulation result.
So basically in node js "modules" core module which is responsible for giving us module.export functionality executes whatever is here above export(in abode example the part A) only for the first time and caches it even if you have required in in multiple other files. However, it only executes the functions or block of code in every require which is inside export. So you can use this approach where your A block will have login to generate fileNamePrefix and then B just returns it.
Just create module like that:
// unicname.js
let shortid = require('shortid');
let fileName = shortid.generate();
module.exports = {fname: fileName};
//module1.js
const {fname} = require('./unicname.js');
....
Since the node.js caching the modules the value will be calculated only one time so you can get same value in all your modules.

Categories