Accessing RequireJS Modules for Debugging

RequireJS is a module loader for Javascript that allows you to separate your code into separate modules and then lazy-load the relevant code when you need it. If done right, it makes your code easier to develop and maintain.

We don't care about that right now. On a page without a module loader, Javascript code exists at the global level. This means we have free reign to modify functions and variables at will. However, with a module loader, code only exists when it is referenced and then is hidden away. If we modify the loaded code, it is overwritten when the module is reloaded, effectively making our changes pointless. Likewise, variables declared inside the modules cannot be accessed from the global level.

Luckily, RequireJS has to store function signatures in global memory so that other modules know how to call them. We can hijack these function signatures to move module variables out to a global level. RequireJS stores these function signatures in the following format:
require.s.contexts._.defined.[modulename].prototype.[functionname]

For example, BrowserQuest has a module called Game that contains all the game related logic. In it, it has a function tick that is called every frame to update the rendering. We can hook this function and add a piece of code to extract the game object to global level.

If you access this in the console, you can see its stored code:

function(){this.currentTime=(new Date).getTime(),this.started&&(this.updateCursorLogic(),this.updater.update(),this.renderer.renderFrame()),this.isStopped||requestAnimFrame(this.tick.bind(this))}

We can modify this to extract the game object by adding a small piece of code to the beginning and reassigning the function signature:

require.s.contexts._.defined.game.prototype.tick = function(){if(!window.game){window.game=this;}this.currentTime=(new Date).getTime(),this.started&&(this.updateCursorLogic(),this.updater.update(),this.renderer.renderFrame()),this.isStopped||requestAnimFrame(this.tick.bind(this))}

Now window.game points to the game object held inside the Game module and can be played around with like any usual variable.