0

I'm new to node.js but have developed enough server-side code that exporting and requiring a file for each custom-written library function is getting unwieldy. I've been reading about alternatives and am confused--perhaps because I should compromise on my goal.

There are 3 separate reusable .js files that are part of one logical kind of task. Let's call the task-type, "x".

  • xLibrary.js - misc utilities specific to that task - many functions
  • xSubtask1.js - some complex code and supporting functions
  • xSubtask2.js - some complex code and supporting functions

I understand how to proceed if I treat each file as a separate module with a separate variable that references it. But since the subtasks are arbitrarily segregated (due to complexity not logical association) it creates confusion to have to remember which file contains a given function.

I'd like to put all the modules in 1 subdirectory and reference all the functions as xTask.*. The only way I know to do that is to combine all the files into one, but that makes maintaining the code more complex.

I've read articles and stackoverflow until my head is spinning. Many of the more comprehensive answers use logic to add each module in a subdirectory. I think hard-coding function and file names is more appropriate for my current level of expertise.

Can someone tell me how to proceed?

Damian Dziaduch
  • 2,107
  • 1
  • 15
  • 16
  • 1
    For importing convenience, you can make one parent module that imports all the functions from each of your three sub-modules and then exports them all such that a client of this can just import the one parent module and get everything. This would be done differently depending upon whether it's a CommonJS module that uses `require()` or an ESM module that uses `import`. – jfriend00 Jan 10 '21 at 06:01
  • That sounds great @jfriend00. I'm in a CommonJS environment. I think the current node.js needs to be unless I go to experimental mode. A quick search didn't find simple directions. If you have time, I'd appreciate further direction, but in any case, I'm grateful for a couple search terms to further investigate. – Jim Thompson Jan 10 '21 at 06:53
  • 1
    FYI, the latest versions of nodejs can use ESM modules without experimental modes. You just need to either give the ESM modules a .mjs file extension of set the right module type in your package.json file. – jfriend00 Jan 10 '21 at 06:57
  • 1
    I can't really advise you on that. It really depends upon what you're doing. I personally haven't found any significant programming advantage to the ESM modules yet so I'm still using CommonJS modules. ESM modules have some limitations (primarily to make life easier for bunders). For example, you can't use the technique shown in my answer below (with computed exports) in an ESM module as all ESM exports have to be statically named without running any code. – jfriend00 Jan 10 '21 at 07:03

1 Answers1

1

For CommonJS modules, you can make a parent module that collects all the exports from a set of sub-modules and then exports them all as part of one main object. Here's some code I used in one of my projects that does that:

// this just re-exports everything that the sub-modules export
module.exports = [
    './mapConcurrent.js',
    './deferred.js',
    './utils.js',
    './rateMap.js',
    './concurrency.js',
    './retry.js',
].reduce((obj, file) => {
    const m = require(file);
    Object.assign(obj, m);
    return obj;
}, {});

I put this in an index.js file that then allowed a user of this module to just require() the directory name and they would get an imported object with all the entry points on it for the whole module.

Note: This assumes that none of the exported symbols in any of the sub-modules have conflicting names. That is under your own control to manage so that's a requirement to do this.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • Thank you @jfriend00. I'm guessing I can study this and figure out how to use the technique. I assume I leave modules that come with node; e.g., http and mysql out of the parent since I have no easy way of knowing if they have conflicting names? If that's a wrong assumption, please let me know. I'll come back and flag the answer as having worked after I get things working--hopefully Monday. – Jim Thompson Jan 10 '21 at 07:16
  • 1
    @JimThompson - The modules you list in this array should ONLY be your own modules. Don't re-export built-in modules. If some code wants to use mysql directly, it should import that itself. – jfriend00 Jan 10 '21 at 07:17
  • 1
    @JimThompson - And, for how to do this with an ESM module, see [here](https://stackoverflow.com/questions/65650975/how-to-make-summary-module-that-re-exports-all-the-exports-of-sub-modules-for-es). – jfriend00 Jan 10 '21 at 21:26
  • @friend00 -- OK. I'll try the ESM technique you pointed to on the assumption that a newer technique has long-term advantages. I don't know enough to compare actual advantages of each. Thank you again for your help. – Jim Thompson Jan 11 '21 at 15:40
  • @jfriend.00 -- Thanks for explaining. The CommonJS script was more clear than anything I could find previously. Even though I never implemented it, I assume I could have had I not switched to trying an ESModule solution per the link you provided. Thanks again for all the help. – Jim Thompson Jan 12 '21 at 03:46