Saturday, December 12, 2015

Least Astonishment: Node.js mutable module cache

Node.js' require cache's modules after the initial call to `require`, so that subsequent calls to require return the cached module.  If a module exports an object, and that object is mutated then subsequent calls to require that module will import the mutated object.  Below are 3 files.  One exporting an object, one requiring that object and mutating it, and another re-requiring the object, which loads the mutated object from the cache:

shared.js exports an object, which will be required and mutated.

mutate-require.js imports the object from shared.js.  This is the first import so it is loading the object that shared.js exports fresh and stores it in the cache.  It then mutates that object, and exports null.

Finally index.js imports mutate-require.js, which triggers the require of shared.js, the imports shared.js directly, which results from a cache load.  The comment at the bottom of index.js shows the output of when index.js is executed.

Is this the behavior you'd expect?  I was surprised, when I saw this.  I could imagine a more sane default being: having `require` copy the exported value to the cache and returning the clean copy on each require. But then what about modules that export objects that mutate themselves??  Thoughts?