On circular dependencies in Javascript
April 4, 2019
Interesting dialog captured from our company’s Slack chat.
-
F S [9:10 PM]
Error: Unexpected value 'undefined' imported by the module 'AuthPagesModule'
For anyone who doesn’t knows, this is Angular’s way to say" “Hey! You have a circular dependency on your modules!"
-
J D [9:11 PM] thats a javascript feature I’m sure that has cost many millions of hours of developer time over the years… Its even better in vanilla javascript with require style, you just get an undefined object and it silently continues.
const library = require('library');
< library here will just be undefined and you are left up to your own to realize its a circular dependency (edited) -
A O [9:18 PM] I think it’s “ok” because the circular dependency will be available eventually The same thing happens in python
-
J D [9:19 PM] available eventually?
-
A R [9:20 PM] Angular has a way to deal with that,
forwardRef
-
A O [9:20 PM] Module internals are undefined because the interpreter hasn’t yet gotten that far
-
A O [9:25 PM] Say you had
// a.js const B = require('./b'); exports.prop = 'foo'; // b.js const A = require('./a'); console.log(A.prop) // undefined setInterval(() => { console.log(A.prop) // 'foo' }, 1000);
Since the log is deferred by a second the interpreter has finished its job and
prop
is defiend -
Mark Safronov [6 minutes ago] @AO What is your entry point? This example is quite meaningless without one. I just made the files
a.js
andb.js
as you described and then made entry point script namedcircular.js
, which does just requireb.js
:require('./b');
If I run
node circular.js
it will print me ‘foo’ every 1 second indefinitely.If I run
node b.js
it will print me ‘foo’ every 1 second indefinitely.If I run
node a.js
it will print me ‘undefined’ once then ‘foo’ every 1 second indefinitely.I think circular dependency like that will break your application no matter whether Node.js module system finished parsing the module or not.