unloading code/modules
I'm curious if there is any good way to unload a module after using it. I have some cases where I need to use modules that bring in a lot of code, but they are used rarely (say as an admin tool), but I hesitate to use them because afterwards they'll presumably just waste memory that could be better used elsewhere. Is there any way to unload them, either explicitly or by allowing the system to do so when they haven't been used for a while?
Solution 1:
Yes, it is possible to access the module cache directly:
var name = require.resolve('moduleName');
delete require.cache[name];
Note that if your code carries a reference to whatever was exposed by these modules you want to get rid of, it won't be cleaned up.
(As an aside: Underneath the surface, require.resolve
and require.cache
are just proxies to Module._resolveFilename
and Module._cache
respectively, with Module
being the core module loader, i.e. require('module')
.)
Solution 2:
You can do something like this to "unload" a node module:
/**
* Deletes a node module and all associated children
* from node require cache
* @param {string} moduleName The name of the module or
* absolute/relative path to it
*/
function deleteModule(moduleName) {
var solvedName = require.resolve(moduleName),
nodeModule = require.cache[solvedName];
if (nodeModule) {
for (var i = 0; i < nodeModule.children.length; i++) {
var child = nodeModule.children[i];
deleteModule(child.filename);
}
delete require.cache[solvedName];
}
}
"Unloading" a node module means that you're "deleting" its entry from node require cache. The snippet above transitively deletes one node module from the cache and all the associated modules (children modules).
In my case I was requiring "index.js" that, at the same time, was requiring "/lib/.js". I wanted to test initialization of "index.js" (and therefore the only other module being required in there which was /lib/.js). Deleting "index.js" from the cache was not enough because the cache maintained a separate reference to "/lib/.js" and that caused the module "/lib/.js" to not be loaded again from its file.
The code above might certainly delete from the cache other modules this module depends on (this is actually what I wanted BUT you might not want to do this for other modules like "fs", "path" or even "underscore").
You can always extend this method to accept a list of modules you don't want to delete or a filter you could apply to the "path" of the resolved module. You can say: don't delete core node modules (a list of core node modules names is available as a npm package: https://www.npmjs.com/package/node-core-module-names) or don't delete any of the packages under node_modules, etc etc.. This could be a filter inside the function but it's the same logic.