module.exports update array - javascript

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.

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.

Moving folders using gulp

I have project with 3 folders (I'm using gulp), which I don't need to compile. So, I need a task, which takes 3 folders "src/fonts", "src/libs" and "src/docs" as gulp.src() and just move them in dest/ folder. I don't need to do something with them, just move them after building.
My current attempt:
gulp.task('others', function () {
return gulp.src(['src/libs/**'], ['src/fonts/**'], ['src/docs/**'])
.pipe(gulp.dest('dist/'))
});
Using this code, task move only inner files and folders(need to be wrapped), and it take only "src/libs" as gulp.src()
Problem:
You're using gulp.src() wrong.
Explanation:
In the current state of your code, the following is happening:
['src/libs/**'] gets passed to globs property
['src/fonts/**'] gets passed to options property
['src/docs/**'] gets passed to NOTHING
The above explains why you're only seeing the files of src/libs being selected.
Thus:
gulp.src(['src/libs/**'], ['src/fonts/**'], ['src/docs/**'])
should be
gulp.src(['src/libs/**','src/fonts/**','src/docs/**'])
or (with a file wildcard *.*)
// something like this (its dirty as I'm writing this off the cuff)
// but you get the idea
var sources = [
'src/libs/**',
'src/libs/**/*.*',
...
];
gulp.src(sources)
Some More Information:
The docs specify the usage as such:
gulp.src(globs[, options])
where globs can only be a:
string => 'im/a/single/directory/or/file/s'
(a single) array object => ['dir1','dir2','dir3','etc']
and options, ... well, an options object (with defined values that you can supply)
options => { buffer: true, read: false, ... }

Nodejs and Expressjs: Constants in global variable

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.

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.

NodeJS: Single object with all requires, or "standard" paths in code?

So, I'm a big fan of creating global namespaces in javascript. For example, if my app is named Xyz I normally have an object XYZ which I fill with properties and nested objects, for an example:
XYZ.Resources.ErrorMessage // = "An error while making request, please try again"
XYZ.DAL.City // = { getAll: function() { ... }, getById: function(id) { .. } }
XYZ.ViewModels.City // = { .... }
XYZ.Models.City // = { .... }
I sort of picked this up while working on a project with Knockout, and I really like it because there are no wild references to some objects declare in god-knows-where. Everything is in one place.
Now. This is ok for front-end, however, I'm currently developing a basic skeleton for a project which will start in a month, and it uses Node.
What I wanted was, instead of all the requires in .js files, I'd have a single object ('XYZ') which would hold all requires in one place. For example:
Instead of:
// route.js file
var cityModel = require('./models/city');
var cityService = require('./services/city');
app.get('/city', function() { ...........});
I would make an object:
XYZ.Models.City = require('./models/city');
XYZ.DAL.City = require('./services/city');
And use it like:
// route.js file
var cityModel = XYZ.Models.City;
var cityService = XYZ.DAL.City;
app.get('/city', function() { ...........});
I don't really have in-depth knowledge but all of the requires get cached and are served, if cached, from memory so re-requiring in multiple files isn't a problem.
Is this an ok workflow, or should I just stick to the standard procedure of referencing dependencies?
edit: I forgot to say, would this sort-of-factory pattern block the main thread, or delay the starting of the server? I just need to know what are the downsides... I don't mind the requires in code, but I just renamed a single folder and had to go through five files to change the paths... Which is really inconvenient.
I think that's a bad idea, because you are going to serve a ton of modules every single time, and you may not need them always. Your namespaced object will get quite monstrous. require will check the module cache first, so I'd use standard requires for each request / script that you need on the server.

Categories