61

Let say, after I require a module and do something as below:

var b = require('./b.js');
--- do something with b ---

Then I want to take away module b (i.e. clean up the cache). how I can do it?

The reason is that I want to dynamically load/ remove or update the module without restarting node server. any idea?

------- more -------- based on the suggestion to delete require.cache, it still doesn't work...

what I did are few things:
1) delete require.cache[require.resolve('./b.js')];
2) loop for every require.cache's children and remove any child who is b.js
3) delete b

However, when i call b, it is still there! it is still accessible. unless I do that:

b = {};

not sure if it is a good way to handle that. because if later, I require ('./b.js') again while b.js has been modified. Will it require the old cached b.js (which I tried to delete), or the new one?

----------- More finding --------------

ok. i do more testing and playing around with the code.. here is what I found:

1) delete require.cache[]  is essential.  Only if it is deleted, 
 then the next time I load a new b.js will take effect.
2) looping through require.cache[] and delete any entry in the 
 children with the full filename of b.js doesn't take any effect.  i.e.
u can delete or leave it.  However, I'm unsure if there is any side
effect.  I think it is a good idea to keep it clean and delete it if
there is no performance impact.
3) of course, assign b={} doesn't really necessary, but i think it is 
 useful to also keep it clean.
murvinlai
  • 43,517
  • 50
  • 120
  • 169
  • The variable you assign the result of `require('./b')` to won't be deleted, the `delete` operation will only allow you to require a file a second time without getting a cached version but the variable won't magically be updated when you do. – robertklep Mar 27 '13 at 20:22
  • yes.. u r right.. and here is what i find out... (see my edition) – murvinlai Mar 27 '13 at 21:55
  • possible duplicate of [node.js require() cache - possible to invalidate?](http://stackoverflow.com/questions/9210542/node-js-require-cache-possible-to-invalidate) – Gajus Nov 12 '14 at 18:55

5 Answers5

121

You can use this to delete its entry in the cache:

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

require.resolve() will figure out the full path of ./b.js, which is used as a cache key.

robertklep
  • 174,329
  • 29
  • 336
  • 330
  • Oh.. let me try . so the full path will be module.filename? – murvinlai Mar 27 '13 at 18:36
  • 1
    Just try. I think it is more complicated than just doing delete. doing delete remove the top level cache. However, because b.js is a child of a.js, so it also cached as a child in a.js. So, i think i also need to remove the child of a.js – murvinlai Mar 27 '13 at 18:45
  • 4
    Note that you may also need to remove everything that `./b.js` requires as well. Depending on your use case, the nuclear option may be appropriate: `_.each(_.keys(require.cache), function (key) {delete require.cache[key];})` – mikermcneil May 27 '15 at 12:28
3

One of the easiest ways (although not the best in terms of performance as even unrelated module's caches get cleared) would be to simply purge every module in the cache

Note that clearing the cache for *.node files (native modules) might cause undefined behaviour and therefore is not supported (https://github.com/nodejs/node/commit/5c14d695d2c1f924cf06af6ae896027569993a5c), so there needs to be an if statement to ensure those don't get removed from the cache, too.

    for (const path in require.cache) {
      if (path.endsWith('.js')) { // only clear *.js, not *.node
        delete require.cache[path]
      }
    }
mkg20001
  • 61
  • 1
  • 9
3

Spent some time trying to clear cache in Jest tests for Vuex store with no luck. Seems like Jest has its own mechanism that doesn't need manual call to delete require.cache.

beforeEach(() => {
  jest.resetModules();
});

And tests:

let store;

it("1", () => {
   process.env.something = true;
   store = require("@/src/store.index");
});

it("2", () => {
   process.env.something = false;
   store = require("@/src/store.index");
});

Both stores will be different modules.

Alonad
  • 1,025
  • 11
  • 11
0

I have found the easiest way to handle invalidating the cache is actually to reset the exposed cache object. When deleting individual entries from the cache, the child dependencies become a bit troublesome to iterate through.

require.cache = {};
0

I found this useful for client side applications. I wanted to import code as I needed it and then garbage collect it when I was done. This seems to work. I'm not sure about the cache, but it should get garbage collected once there is no more reference to module and CONTAINER.sayHello has been deleted.

/* my-module.js */

function sayHello { console.log("hello"); }

export { sayHello };

/* somewhere-else.js */

const CONTAINER = {};

import("my-module.js").then(module => {

  CONTAINER.sayHello = module.sayHello;

  CONTAINER.sayHello(); // hello

  delete CONTAINER.sayHello;

  console.log(CONTAINER.sayHello); // undefined

});
Frank
  • 1,606
  • 3
  • 15
  • 34