How to export a Node.js module requiring assignment - javascript

My case is that I need to require a module named Router in my index file meanwhile assign value to a variable of the module.
I have figured out several ways to achieve it. However, as a beginner, I want to know which one is the best practice or design and why cannot use the others.
Method 1 - export a setter & keep variable as 'private'
router.js
var handler;
exports.setHandler=function(h){handler=h};
exports.route=function(){console.log(handler)}
index.js
var router=require('./router');
router.setHanlder('test');
router.route();
Method 2 - let variable be 'public' and use 'this' to refer
router.js
exports.handler={}; //not necessary
exports.route=function(){console.log(this.handler)}
index.js
var router=require('./router');
router.hanlder='test';
router.route();
Method 3 - export a factory function to receive value as a parameter
router.js
module.exports=function(handler){
return {route:function(){console.log(return handler)}};
}
index.js
var router=require('./router')('test');
router.route();
Which one above should I use? Any other methods suggested?

I would suggest method 3, it being a callback;non-blocking code. Also, it is close to what seems natural to me!

I like to do it this way - I recommend trying to stay away from handlers like that with modules because it is a complexity trap that will catch you one day, that is, unless you need them =).
module.exports = function( options ) {
// set options
// based on options set vars and functions on this
if (options.test === true) this.route = function() {//....}
else this.route = function() {//......}
}
then in the using file
var Router = require('router.js');
var router = new Router({/* options */});
router.route();

It's possible to use method 2 as well. If you are using aws lambda, you will see that they used method 2 to export the function handler.

Related

How do you call a function inside a module.exports = function () in another class?

In the following example, simply putting module.exports = {save} on the jsFileName.js file functions is not an option here, due to limitations on my codebase. Is this possible to access the function from the export, inside of callFunctionFromAboveFile.js shown below? See the below example of how I'd like to access that function. I've searched all the other answers to questions similar but they all mention using the exports differently as I stated in my first line above.
If there is a way to access it as it is shown, please share your answer or details as to why it's not possible. Also, other ways to handle this would be helpful but I can't change the class up much given the limitation to the codebase.
jsFileName.js
module.exports = function (JsFileName) {
JsFileName.save = function (stuff) {}
}
callFunctionFromAboveFile.js
const JsFileName = require('jsFileName');
// TODO I'm not sure how this would call the save() w/out using exports differently.
// TODO I have to use exports as I've posted it in jsFileName.js
The default export of jsFileName.js is a function that adds functions to its parameter JsFileName.
Apparently, you can pass any object which is then modified to act as the module's exports.
That means: Pass any object you want to have the modules' functionality. Note that the object is not returned, so you have to keep the reference to it yourself.
// callFunctionFromAboveFile.js
const JsFileName = {};
require("jsFileName") // Get default export (the function)
(JsFileName); // Call with any object you want to "enhance"
JsFileName.save(/*...*/);

Use javascript module inside an object

I'm asking a question:
Imagine I have a javascript module (using revealing module pattern) and I want to use it inside some prototype methods of an object. What will be the best way on your opinion to do it?
I have currently two ideas in mind:
- Pass the global module to the constructor of the object and keep it in an object property (this.myModule...)
- Use the module from the prototype method directly as global variable
Let me explain you the situation with a small example:
I have file1.js containing the module :
var myModule = (function(){
function doSomething(){...}
return {doSomething: doSomething};
})()
To use this module, which of the two options is the best for you? Or maybe you have a better option to propose?
I can't use requirejs nor any libraries to ease the modularity and dependency management of my application. Also, I can't change the existing architecture.
// Option 1
function myObject(myModule){
...
this._myModule = myModule;
}
myObject.prototype.doAnotherThing = function(){
...
this._myModule.doSomething();
}
var test = new myObject(myModule);
// Option 2
function myObject(){
...
}
myObject.prototype.doAnotherThing = function(){
...
myModule.doSomething();
}
var test = new myObject();
I'm really interested by having your point of view.
Thanks a lot in advance,
Remi

What happens when using "require()" in Node.js?

Sorry if this is a dumb question but I'm new to JavaScript/Node.js. This code below eludes me and I've done a fair bit of research... My questions below are more specifically related to instantiation.
I don't understand this:
var myApp = require('express');
var myCode = myApp();
How I see that it should be for instantiation:
var myApp = new Express();
var myCode = myApp.insideExpress();
How anonymous function expressions are:
var myApp = function();
var myCode = myApp();
If the word "require" acts as a sort of anonymous function expression, then how are things instantiated in the background? This is very important for making proper patterns, no?
My questions are:
What's happening in the background for the first example, is JavaScript/Node.js instantiating/constructing or not at all?
Are people who do this just creating bad patterns? Why should I use this pattern?
If no instantiation, then why not?
Thanks in advance
const myVar = require("someModule") loads a module from the file system, runs the module initialization code and assigns the module exports to your variable. The module loading sub-system maintains a cache so if it was previously loaded, it is not loaded or run again, the module's exports are just retrieved from the cache and assigned to your variable.
So, when you do this:
var myApp = require('express'); // load express module, assigns exports to myApp
var myCode = myApp(); // calls myApp() function and assigns result to myCode
The first line loads the express module and assigns the exports from that module to your myApp variable. In this particular case (it varies from module to module), the exports from the Express module is a function. So, after that first line of code, myApp contains a function which happens to be a factory function for creating new Express app objects.
The second line of code calls that factory function which returns a new Express app object.
A module can export anything it wants. In the case above, it exported a function, but it's also common to export an object that has a whole bunch of properties which you can then access. You can also export a constructor in which case the caller would then use new with the constructor to create a new object from it.
In the Express module, it did not export a constructor (which is why you don't use new with it). Instead, it decided to export a factory function that, when called, creates and returns a new object. This is just a design decision that can go either way depending upon the needs of the module and the whims of the code writer.
I can't really tell what you're asking here with this code:
var myApp = new Express(); // the express module does not export a constructor
var myCode = myApp.insideExpress();
This would work only if Express was a constructor function. The express module itself does not choose to export a constructor function so this is not how you use the express module. It could have been designed this way, but it was not. They simply made a different design decision when designing it.
For this other case you show:
var myApp = function();
var myCode = myApp();
That first line of code doesn't make any sense. Perhaps you meant for it to have a body to the function:
var myApp = function() { some code here };
var myCode = myApp();
In that case, myApp is being assigned a function expression (which is just one of several ways to declare a function). It's similar, though not exactly the same as:
function myApp() { some code here }
If the word "require" acts as a sort of anonymous function expression, then how are things instantiated in the background? This is very important for making proper patterns, no?
require('someModule) loads a module and returns the exports from the module which can be any Javascript data type. It doesn't act as an anonymous function in any way. require() is an actual function and you are just calling it and getting back its return value. Remember that in Javascript, you can return any data type from a function, include return another function (which is what the express module does).
What's happening in the background for the first example, is JavaScript/Node.js instantiating/constructing or not at all?
No instantiating or constructing. It's just loading a module, running its initialization code and return its exports. Some objects are created by the module loading system that are used for its own housekeeping, but the module itself is just initializing itself and then deciding what it wants to export.
Are people who do this just creating bad patterns? Why should I use this pattern?
Modules are highly useful in node.js development and it is considered good design to use proper module design. There are many, many advantages to good module design such as easier code maintenance, easier code testing, easier code reuse, easier code sharing, no need to create globals in order to share code, etc...
If no instantiation, then why not?
A module decides what it wants to export. It can, in its initialization code, create an instance of an object and export it. It can export a factory function that creates an instance of an object when called. It can export a constructor directly that lets the caller use new with it to create an instance of an object. It can export a utility function that just carries out some function and doesn't create any objects. It can export just data. It can export a plain object with multiple properties on it that have all sorts of possible uses. The possibilities are endless and it entirely depends upon what the purpose is of the module and what it wishes to share with the other module that loaded it.
It's just loading a library or a module into your script. It is not instantiating a new object. It's just making the loaded module's functions etc available to your current script. Here is a good writeup that I found,
http://fredkschott.com/post/2014/06/require-and-the-module-system/
I hope that helps answer your question.

Best approach to passing variables between multi-file Node.js modules?

I have a Node.js module that I have kept as a single file up to this point. It's getting rather large though and has a lot of functionality in it that might be better separated into other modules. For example, separating out logging initialization and functionality into it's own module.
My module has a lot of (I want to say "global" but not really) top-level variables that lots of different functions access, use and modify. If I separate out functionality into separate files/modules and require them into my primary module, what is the proper approach to passing those variables between the modules?
For example, with everything in one module/file, it's easy to do this:
const logger = (log, message) {........}
const makeRequestHandler = (url, filepath) {
....
logger.info('some message here')
....
}
So it's pretty easy to access top-level systems like the logger. But, if I decided to split my logger and makeRequestHandler into their own modules/files, how would I handle this?
let logger = require('./mylogger') // Custom module
let makeRequest = require('./makerequest') // Another custom module
makeRequest.handler(url, filepath, logger)
This would work, but it doesn't seem elegant or optimal. It would get even more weird if I have a lot of different variables that I needed to pass in:
makeRequest.handler(url, filepath, logger, profiler, reportingBuffer, compressionHandler)
I've also considered passing stuff into the modules when requiring:
let makeRequest = require('./makeRequest')(logger)
or better yet:
let makeRequest = require('./makeRequest')(this) // I can access all variables made in my primary/top-level module
Is there an approach here that is more proper and better/easier to maintain? Is the last one the best approach?
What about a global locator pattern or service locator/service provider pattern as pointed out in comments wherein you can have something like a service registry and include these services in any module you want to use them in.
Although I am not sure about being the best solution of all, but it is easier to implement and feels like a neater solution than passing in the this context around the modules.
//logger.js
const logger = (log, message) {........}
export logger
Now, in the app file is where you can initialize the logger and other service instances and register them in the global locator
let logger = require('./mylogger') // Custom module
init() {
//init and set the logger
global.logger = new logger();
...
}
And this is how you can use it in the code to makRequest
let logger = global.logger;
const makeRequestHandler = (url, filepath) {
....
logger.info('some message here')
....
}
What I feel is problem with these solutions :
//Solution 1 : As you pointed out yourself this can get messy when number of paramters increase and is not very readable or understandable.
let logger = require('./mylogger')
let makeRequest = require('./makerequest')
makeRequest.handler(url, filepath, logger)
//Solution 2 : Passing around the `this` context is never a good idea,for keeping sensitive data independent or scope isolation
let makeRequest = require('./makeRequest')(this)
note :
This article explains some aspects of this solution in detail for your consideration.
Also there are some npm modules which provide these features like Service Locator
. HTH

Difference between require('module')() and const mod = require('module') mod() in node/express

I have two files: server.js and db.js
server.js looks as such:
...
const app = express();
app.use('/db', db());
app.listen(3000, () => {
console.log('Server started on port 3000')
});
...
and db.js as such:
...
function init() {
const db = require('express-pouchdb')(PouchDB, {
mode: 'minimumForPouchDB'
});
return db;
}
...
This works just fine, and I am able to reach the pouchdb http-api from my frontend. But before, I had const PouchDBExpress = require('pouchdb-express'); in the top of db.js, and the first line in init() looked like this; const db = PouchDBExpress(PouchDB, {. This gave an error in one of the internal files in pouchdb saying cannot set property query on req which only has getters (paraphrasing).
So this made me copy the exaples from pouchdb-servers GitHub examples which requires and invokes pouched-express directly, and everthing worked fine. Is there an explanation for this? I'm glad it works now, but I'm sort of confused as to what could cause this.
The only difference between:
require('module')()
and
const mod = require('module');
mod();
is that in the second case, you retain a reference to the module exports object (perhaps for other uses) whereas in the first one you do not.
Both cases load the module and then call the exported object as a function. But, if the module export has other properties or other methods that you need access to then, obviously, you need to retain a reference to it as in the second option.
For us to comment in more detail about the code scenario that you said did not work, you will have to show us that exact code scenario. Describing what is different in words rather than showing the actual code makes it too hard to follow and impossible to spot anything else you may have inadvertently done wrong to cause your problem.
In require('module')(), you don't retain a reference of the module imported.
While in const mod = require('module'); mod(), you retain a reference and can use the same reference later in your code.
This problem might be due to some other reason like -
Are you using a some another global instance of the db, and your code works in the given case as you are making a local instance
Some other code dependent scenario.
Please provide more details for the same

Categories

Resources