Rory's Blog
Home
Blog
Projects
Facebook
Google+
Github
RSS

Node and Cyclic Dependencies

11/11/15

I feel like I've come into a rite of passage in JavaScript. I have hit the classical circular dependencies problem.

What I have is a script called publish, it requires htmlGenerate, template, and database. All also scripts I have made. htmlGenerate translates my bare-bones blog files into published posts, template is a basic script I made to fill in template html files I have (will soon be replaced by a proper library made by someone else), and database is my wrapper for interacting with my textfile lists that say what posts are published to index and in what order (hopefully eventually it'll refer to a proper database).

The order I mentioned these requirements are important, because requirements are loaded in order, so....

In htmlGenerate, rssGenerate is required, and in there database is required, and in there rssGenerate is required.

And there's the circular dependency. rssGenerate to database and then back to rssGenerate.

So, why does this matter? Because, as it turns out, when JavaScript A requires JavaScript B, and B also requires A, then B will only get A loaded up to the point where B is required.

Let me show you:

Let's make an A.js

// A.js
B = require('./B')
exports.afterB = true;

console.log('B after A:', B.afterA);

Now a B.js.

// B.js
A = require('./A')
exports.afterA = true;

console.log('A after B:', A.afterB);

And now a main.

// main.js
A = require('./A')
B = require('./B')

console.log('A after B:', A.afterB);
console.log('B after A:', B.afterA);

What happens when I run this code?

A after B: undefined
B after A: true
A after B: true
B after A: true

That "A after B" that gets logged in B.js is undefined. Why? A has required B, but B required A. A needs B to be finished loaded before it can finish loading, so B gets an incomplete copy of A and anything it does while initializing it does with only what A had already load up until A required B.

And I hit this bug naturally with my code. Which tells me two things, 1) I'm getting more familiar with JavaScript, because I was able to cause this, and 2) I'm writing bad JavaScript, because I allowed this to happen.

That's okay, I'm working on it, and it's kinda fun that I found such an infuriating feature of node's require module.

Further Reading

Node's module documentation about cycles, complete with better example.

Good blog post about fixing the problem.