node.js require() cache - possible to invalidate?

后端 未结 17 1654
我寻月下人不归
我寻月下人不归 2020-11-22 06:52

From the node.js documentation:

Modules are cached after the first time they are loaded. This means (among other things) that every call to require(\'

相关标签:
17条回答
  • 2020-11-22 07:23

    I couldn't neatly add code in an answer's comment. But I would use @Ben Barkay's answer then add this to the require.uncache function.

        // see https://github.com/joyent/node/issues/8266
        // use in it in @Ben Barkay's require.uncache function or along with it. whatever
        Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
            if ( cacheKey.indexOf(moduleName) > -1 ) {
                delete module.constructor._pathCache[ cacheKey ];
            }
        }); 
    

    Say you've required a module, then uninstalled it, then reinstalled the same module but used a different version that has a different main script in its package.json, the next require will fail because that main script does not exists because it's cached in Module._pathCache

    0 讨论(0)
  • 2020-11-22 07:25

    You can always safely delete an entry in require.cache without a problem, even when there are circular dependencies. Because when you delete, you just delete a reference to the cached module object, not the module object itself, the module object will not be GCed because in case of circular dependencies, there is still a object referencing this module object.

    Suppose you have:

    script a.js:

    var b=require('./b.js').b;
    exports.a='a from a.js';
    exports.b=b;
    

    and script b.js:

    var a=require('./a.js').a;
    exports.b='b from b.js';
    exports.a=a;
    

    when you do:

    var a=require('./a.js')
    var b=require('./b.js')
    

    you will get:

    > a
    { a: 'a from a.js', b: 'b from b.js' }
    > b
    { b: 'b from b.js', a: undefined }
    

    now if you edit your b.js:

    var a=require('./a.js').a;
    exports.b='b from b.js. changed value';
    exports.a=a;
    

    and do:

    delete require.cache[require.resolve('./b.js')]
    b=require('./b.js')
    

    you will get:

    > a
    { a: 'a from a.js', b: 'b from b.js' }
    > b
    { b: 'b from b.js. changed value',
      a: 'a from a.js' }
    

    ===

    The above is valid if directly running node.js. However, if using tools that have their own module caching system, such as jest, the correct statement would be:

    jest.resetModules();
    
    0 讨论(0)
  • 2020-11-22 07:27

    Yes, you can invalidate cache.

    The cache is stored in an object called require.cache which you can access directly according to filenames (e.g. - /projects/app/home/index.js as opposed to ./home which you would use in a require('./home') statement).

    delete require.cache['/projects/app/home/index.js'];
    

    Our team has found the following module useful. To invalidate certain groups of modules.

    https://www.npmjs.com/package/node-resource

    0 讨论(0)
  • 2020-11-22 07:27

    requireUncached with relative path:

    0 讨论(0)
  • 2020-11-22 07:30

    For anyone coming across this who is using Jest, because Jest does its own module caching, there's a built-in function for this - just make sure jest.resetModules runs eg. after each of your tests:

    afterEach( function() {
      jest.resetModules();
    });
    

    Found this after trying to use decache like another answer suggested. Thanks to Anthony Garvan.

    Function documentation here.

    0 讨论(0)
  • 2020-11-22 07:31

    Yes, you can access the cache via require.cache[moduleName] where moduleName is the name of the module you wish to access. Deleting an entry by calling delete require.cache[moduleName] will cause require to load the actual file.

    This is how you would remove all cached files associated with the module:

    /**
     * Removes a module from the cache
     */
    function purgeCache(moduleName) {
        // Traverse the cache looking for the files
        // loaded by the specified module name
        searchCache(moduleName, function (mod) {
            delete require.cache[mod.id];
        });
    
        // Remove cached paths to the module.
        // Thanks to @bentael for pointing this out.
        Object.keys(module.constructor._pathCache).forEach(function(cacheKey) {
            if (cacheKey.indexOf(moduleName)>0) {
                delete module.constructor._pathCache[cacheKey];
            }
        });
    };
    
    /**
     * Traverses the cache to search for all the cached
     * files of the specified module name
     */
    function searchCache(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
        if (mod && ((mod = require.cache[mod]) !== undefined)) {
            // Recursively go over the results
            (function traverse(mod) {
                // Go over each of the module's children and
                // traverse them
                mod.children.forEach(function (child) {
                    traverse(child);
                });
    
                // Call the specified callback providing the
                // found cached module
                callback(mod);
            }(mod));
        }
    };
    

    Usage would be:

    // Load the package
    var mypackage = require('./mypackage');
    
    // Purge the package from cache
    purgeCache('./mypackage');
    

    Since this code uses the same resolver require does, just specify whatever you would for require.


    "Unix was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things." – Doug Gwyn

    I think that there should have been a way for performing an explicit uncached module loading.

    0 讨论(0)
提交回复
热议问题