Nodejs Modules and Export Explained
Enjoyed a week playing around with nodejs :) Lets share
Simple Node Server [http://localhost:6666]:
var http = require('http'); var server = http.createServer(function (req, res) { // Do Whatever you want res.writeHead(200, {'Content-Type':'text/plain'}); res.end('Running'); }).listen(6666, function () { console.log('Node Runs on port 6666'); });
How to install a node_module?
NPM is a powerful package manager for node which you can use to install node modules
Ex:
npm install redis
The above command installs redis module in ./node_modules/redis directory
How to use a module?
Use require() method
Ex:
require('redis')
How will node resolve the modules?
Consider
/home/xxx/sample |___ index.js |___ node_modules |____ redis |____lib/ ... |____ my_module |____node_modules |____first.js |____test.js
//test.js var redis = require('redis');
So node will look for redis module in
1.my_module/node_modules/
2.sample/node_modules/
3.xxx/node_modules/
4.home/node_modules
5./node_modules
Also some global folders
You can exploit this behaviour nicely if planned :)
Will node load the module everytime I request it to via require?
No, It won't load the module everytime you request untill the module requested resolves to a location different from previously loaded location.
Ya, Node caches the module
Cache means?? What will get cached?
uh uHHH... Lets get deeper into modules before this question
How to write your own module?
Simple... Let us write a module which performs lowercase to uppercase conversion
//simple.js var stringtoUpper = function (text) { return text.toUpperCase(); }; exports.toUpper = stringtoUpper;
Done :)
//test.js var utils = require('./simple'); console.log(utils.toUpper('this is text')); //Execution node test.js >THIS IS TEXT
What is that exports?
That is whatever you wish to expose to the src module that requires the destination module.
This is shared between all instances of the current module.
exports.toUpper same and equal to module.exports.toUpper, [exports === module.exports] nice way to use. module is the referrence to the current module :)
Also you can name your export different from it's actual name. As you can see in the above example. Actual function's name is stringtoUpper, but exports' name is toUpper
Consider the same simple.js and instead exports.toUpper = stringtoUpper replace with
1.module.exports.toUpper = stringtoUpper;
2.module.exports = stringtoUpper;
3.module.exports = new stringtoUpper('this is a text');
All the three are different
module.exports is an object
1 makes it {toUpper: [Function]]}
2 makes it [Function] // We can use this a constructor function
3 makes it an object of stringtoUpper class
After require('test.js'); to use the exports, follow
1 : simple.toUpper('This is a text')
2 : simple('this is a text') or require('simple')('this is a text') or new simple('this is a text');
3 : You can access all public members. Here there is none
Methods 2 & 3 overrides the entire object, means whatever might be there initialised before via exports will be overridden
Ex:
module.exports.a = 10;
module.exports.b = 20;
module.exports = 20; // will override a & b
Hope you understand the reason. module.exports itself is an object and members of it can be initialised either as module.exports.a, module.exports.b but when module.exports = 20 happens the whole object is initialised with new value
Now lets comeback to caching
node caches all these exports of a module when they are loaded for the first time
1 & 2 has no effect on caching since they are just functions they can be called n number of times with change in parameter
But 3 is different. The object returned is cached. So how many ever time you load the module after first time, no instantiation take place [Kind of singleton]. Because you are exporting only one object of the class.
So, If you are looking for stateful implementation across modules you can go for 3, else go for 1 or 2
Happy Node :) Hope this helps :)
Succinct - the docs did not make this as clear and now I refactored my app.js module to be cleaner and free of routes code. Hellooooo unit tests!
ReplyDeleteI'm glad that this post helped you :)
DeleteHere I see you did a var http = require('http');
ReplyDeleteWhat if I wanted two different instances of http?
Can I do var http2 = require('http'); ?
Will http and http2 be new instances?
Hi, if you are requiring http twice it means that you are requiring the same exports object cached by node js vm twice. But,
Deleteexports.createServer = function(requestListener) {
return new Server(requestListener);
};
Above is the create server function exposed by http module. There you can see "new Server" which means that if you do
http.createServer and http2.createServer they should be different
Hope this is clear