I love playing around with Node require, see a couple of previous blog posts and existing projects:
- Hooking into Node loader for fun and profit
- Hacking Node require and really-need
- Faster Node app require and cache-require-paths
- Was NodeJS module used
Recently I had another epiphany: if I need to mock a module, why bother reading its source file from disk at all? Or how about loading fake or non-existing modules? Turns out this is very simple to do and can be used during unit testing and a few other fun things (stay tuned for the future updates).
Simple module mocking
Let us solve the first problem: imagine we really want to load something else instead of the actual
file foo.js. We can insert the mock data first before the actual file had a chance to load.
Node has a cache of all loaded and evaluated code. Each entry is stored
under the fully resolved filename. The loaded source file foo.js has something like this
| 1 | module.exports = 'this is foo'; | 
| 1 | require('./foo.js') // loads "foo.js" and sticks it into the cache | 
The only interesting properties that we need to insert ourselves are:
- id (same as the full resolved filename)
- exports - the actual compiled module.exportsvalue
- loaded - might not matter, but better to be set to true
Thus we can insert the mock data directly into the require.cache at desired key to use
completely fake module.
| 1 | var resolved = require('path').resolve('./foo.js'); | 
Done. Any require('./foo.js') after that will return the fake exports value from the cache.
| 1 | module.exports = 'this is foo'; | 
| 1 | // test-foo.js loads after insert-fake-foo.js | 
Loading a non-existing module
Let us try loading a file called bar.js that actually does not exist.
Typically this would be impossible: there would be an exception
Error: Cannot find module './bar.js'
    at Function.Module._resolveFilename (module.js:331:15)
Even if we insert the mock data into the require.cache, 
the next call require('./bar.js') still check if the file exists
in order to properly resolve it. Thus we need to fake the filename resolution. Luckily this is simple
to do.
| 1 | var resolvedFakeName = require('path').resolve('./bar.js'); | 
We only return the fake yes answer for our non-existent module, and let the real method do the actual work for every other module. Combined with inserting mock data into the cache, this work around allows to load non-existent modules in the entire app.
Update 1
I hate to write an entire file Gruntfile.js just to run a single grunt plugin, so I wrote 
grunty - loads and runs a given plugin without global grunt CLI
or a gruntfile. For example to run the excellent 
grunt-contrib-concat plugin, just add this to
the package.json (and install plugin and grunty as dependencies).
| 1 | "scripts": { | 
In order to make this work, I avoided writing even a temporary Gruntfile.js, instead
putting the configuration function directly into the module cache.
| 1 | // this returns initialized config function | 
Pretty useful.