Search code examples
node.jsrequirenode-modules

How to reference parent modules in Node.js


I have a few files, requiring each other recursively.

routes.js requires api.js.
api.js requires upload.js, pixels.js, etc.

From upload.js or pixels.js I want to use fn's in api.js.

Currently I'm requring like so, but it doesn't work:

// routes.js
var api = require('./api');
api.upload.image(args); // a fn run from routes.js

.

// api.js
module.exports = {
    upload : require('./upload')
}

.

// pixels.js
module.exports = {
    get : function (args) {
          console.log(args);
    }
}

.

// upload.js
var api = module.parent.exports;   // <= tricky part
module.exports = {
    image : function (args) {
          api.pixels.get(args); // <= api is undefined
    }
}

The module.parent.exports are empty in the sub-modules, and I can't figure out how to require them properly.

How should I require to get this functionality?


Solution

  • The question is old, but I'll still try to answer.

    Code sequence

    Code execution in JS does not happen for all modules instantly. Instead it occurs in a strict sequence. If one thinks about this while looking at where children modules are required and invoked, then the current result makes sense. Though OP's examples do not show explicitly where children modules are required, I guess this happens in the very beginning of the parent module, like so:

    // api.js
    const pixels = require('./pixels.js');
    const upload = require('./upload.js');
    module.exports = {
      pixels: pixels,
    }
    

    Indeed when you require upload.js (3rd line) the api.js knows nothing yet about its future exports (declared below).

    Working example

    Based on this understanding let's have a look at a slightly modified code:

    // api.js
    const pixels = require('./pixels.js');
    module.exports = {
      pixels: pixels,
    }
    const upload = require('./upload.js');
    let res = upload.image("test values");
    console.log(res);
    

    // pixels.js    
    function get (args) {
      return "The result of processing " + args;
    }
    module.exports = {
      get: get
    };
    

    // upload.js    
    const api = module.parent.exports;
    
    module.exports = {
      image: function (args) {
          return api.pixels.get(args);
      }
    }
    

    Now when you have your parent module exports prepared before invoking upload it's not undefined within the image function anymore.

    And if you run api.js you'll get:

    The result of processing test values

    Notes

    1. Things may become more complicated if referencing parents from multiple modules and/or bidirectionally. I'd say this is a pretty clear sign of bad project's structure and it should be refactored and probably simplified (to have less child to parent references).
    2. module.parent may become de facto deprecated as it was already discussed and announced to happen.