Reputation: 13494
Consider the following example:
// bar.js
const foo = require('./foo');
module.exports = function(args){
let f = foo(args)
}
// foo is not a function
Then:
// bar.js
module.exports = function(args){
let f = require('./foo')(args)
}
// behaves as expected
foo.js looks like:
const bar = require('./bar');
module.exports = function(args){ //same args as bar.js
const foo = {};
foo.f1 = function(arg){
console.log("Hi")
}
return foo
};
Upvotes: 1
Views: 4165
Reputation: 7771
You are dealing with the problems of cyclic dependencies. I guess foo.js
looks somehow like this:
const bar = require('./bar');
module.exports = function(args) {
console.log(args);
};
Let's follow the steps the VM performs to execute the code (assuming you load foo.js
first):
foo.js
. Initialize exports with A = {}
.bar.js
. Initialize exports with B = {}
. Now within bar.js
:
bar.js
requires the exports of foo.js
(which are still A = {}
), so set foo
in bar.js
to A = {}
(this is the problem!).bar.js
with the function as declared.foo.js
with the function as declared.As you can see, there is no way for the VM to keep track of the exports of foo.js
within bar.js
if you use cyclic dependencies.
In your second example, you resolve the exports of foo.js
later, when the function is called. At that point, the exports of foo.js
have already been replaced with the function, and it works.
Short version: This is what happens.
foo.js
and initializes the exports of foo.js
with object A
.bar.js
and initializes the exports of bar.js
with object B
.foo
in bar.js
to the exports of foo.js
, therefore foo = A
.bar.js
with the function C
bar
in foo.js
to the exports of bar.js
, therefore bar = C
.foo.js
with the function D
.As you can see again, the variable foo
in bar.js
is still A
, even though it should be D
.
You will usually want to avoid using cyclic dependencies. If it is really necessary, then do not replace module.exports
, but rather attach properties to the object:
module.exports.doBarAction = function(args){
let f = foo.doFooAction(args)
};
This solves the problem as the object is still the same at runtime.
However, in most situations it is better to get rid of cyclic dependencies, at least as long as we are talking about CommonJS modules.
Upvotes: 5