Decache removing all child dependencies of target module from cache
andrsnn opened this issue · comments
Currently when a module with child dependencies is removed from the require cache via decache, all of its child dependencies are also removed from the cache.
For example:
When requiring a module that requires several other modules.
a.js
-- b.js
-- c.js
-- d.js
The require.cache will then contain references to each module.
e.g. Object.keys(require.cache)
will look like:
[ '/Users/my-user/Documents/git/decache/my-test-file.js',
'/Users/my-user/Documents/git/decache/decache.js',
'/Users/my-user/Documents/git/decache/node_modules/callsite/index.js',
'/Users/my-user/Documents/git/decache/a.js',
'/Users/my-user/Documents/git/decache/b.js',
'/Users/my-user/Documents/git/decache/c.js',
'/Users/my-user/Documents/git/decache/d.js',
'/Users/my-user/Documents/git/decache/e.js' ]
after calling decache on the a.js
module
decache('./a')
The require cache will no longer contain references to the a.js module specified or any of its dependencies
e.g. Object.keys(require.cache)
will look like:
[ '/Users/my-user/Documents/git/decache/my-test-file.js',
'/Users/my-user/Documents/git/decache/decache.js',
'/Users/my-user/Documents/git/decache/node_modules/callsite/index.js' ]
This is due to the fact that the decache module recursively DFS the target modules dependency tree. Deleting each module passed by the callback iterator.
// Run over the cache looking for the files
// loaded by the specified module name
require.searchCache(moduleName, function (mod) {
delete require.cache[mod.id];
});
....
require.searchCache = function (moduleName, callback) {
// Resolve the module identified by the specified name
var mod = require.resolve(moduleName);
// Check if the module has been resolved and found within
// the cache no else so #ignore else http://git.io/vtgMI
/* istanbul ignore else */
if (mod && ((mod = require.cache[mod]) !== undefined)) {
// Recursively go over the results
(function run(mod) {
// Go over each of the module's children and
// run over it
mod.children.forEach(function (child) {
run(child);
});
// Call the specified callback providing the
// found module
callback(mod);
})(mod);
}
};
Is this behavior intended? Should the DFS instead be removing all references to child.parent? I would assume that some people using this module are depending on this behavior or have worked around it. Curious as to thoughts on this.
Thanks!
@andrsnn this was our desired behaviour as we want the "child" dependencies to be "fresh".
if you would prefer that they were not removed, we could consider adding that as an optional parameter...
@andrsnn If you don't need it to be recursive, then you just need to manually delete the key on the require.cache object:
delete require.cache['/Users/my-user/Documents/git/decache/a.js'];
That should be enough.
@albertogasparin @andrsnn Note you're better off resolving the path:
delete require.cache[require.resolve('/Users/my-user/Documents/git/decache/a.js')];
Source: https://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate
delete require.cache[require.resolve('/Users/my-user/Documents/git/decache/a.js')];
I assume we also need to run:
Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
if (cacheKey.indexOf(moduleName)>0) {
delete module.constructor._pathCache[cacheKey];
}
});
From decache.js#L38... or not? What's that for, anyway?
Could we add to the documentation the explicit info that it does this? This is in face the desired behavior, but I had to dig in the issues to figure it out, or else look in the source or download and try. Would be much preferred if you pointed out in the readme that this is what it does.