I'm developing a node.js module that has several functions.
The module itself will require some config to start (there will be defaults... that can be overridden - file paths for example)
What's the preferred approach when exporting a function? Allowing it to be instantiated from a require statement, and pass in the config object (optional) to the constructor?
var MyModule = require('myModule);
var myModule = new MyModule({
name: "test name"
});
myModule.doThing(function(x){
});
Having this in the module:
module.exports = function MyModule(){
MyModule.prototype.config = {name: "default name"}
function doThing(cb){
//do stuff
cb();
}
}
Or, creating an instance from the exports statement in the module, then using it like this:
var myModule = require('myModule);
myModule.config = {name: "test name"}
myModule.doThing(function(x){
});
Instead, having this in the module:
module.exports = exports = MyModule();
function MyModule(){
MyModule.prototype.config = {name: "default name"}
function doThing(cb){
//do stuff
cb();
}
}
I'm developing a node.js module that has several functions.
The module itself will require some config to start (there will be defaults... that can be overridden - file paths for example)
What's the preferred approach when exporting a function? Allowing it to be instantiated from a require statement, and pass in the config object (optional) to the constructor?
var MyModule = require('myModule);
var myModule = new MyModule({
name: "test name"
});
myModule.doThing(function(x){
});
Having this in the module:
module.exports = function MyModule(){
MyModule.prototype.config = {name: "default name"}
function doThing(cb){
//do stuff
cb();
}
}
Or, creating an instance from the exports statement in the module, then using it like this:
var myModule = require('myModule);
myModule.config = {name: "test name"}
myModule.doThing(function(x){
});
Instead, having this in the module:
module.exports = exports = MyModule();
function MyModule(){
MyModule.prototype.config = {name: "default name"}
function doThing(cb){
//do stuff
cb();
}
}
Share
Improve this question
asked Jan 12, 2013 at 1:42
AlexAlex
38.6k54 gold badges214 silver badges340 bronze badges
2 Answers
Reset to default 6I’ll say let you users provide an object when instanciating, put the defaults in the prototype. You may also want to provide a configure function, this allows you (now or in the future) to validate keys/values, and your users to set configs after instanciation.
// Module
var Mod = module.exports = function Mod (opts) {
opts = (opts === Object(opts)) ? opts : {};
// This allows users to instanciate without the `new` keyword
if (! (this instanceof Mod)) {
return new Mod(opts);
}
// Copy user provided configs to this.config
for (var key in opts) if ({}.hasOwnProperty.call(opts, key)) {
this.config[key] = opts[key];
}
};
Mod.prototype.config = {
foo : 'foo',
bar : 'bar'
};
Mod.prototype.configure = function configure (key, val) {
this.config[key] = val;
return this;
};
// Usage
const Mod = require('/path/to/mod');
var i1 = new Mod;
var i2 = Mod();
var i3 = new Mod({
foo: 'bar'
});
var i4 = Mod({
foo: 'bar'
});
i4.configure('bar', 'baz');
var i5 = (new Mod).configure('bar', 'baz');
EDIT
As Jake Sellers noted in the ments, this isn’t standard API pattern in CommonJS modules. A better solution would be to export a function that returns whatever object you’re creating.
More importantly, I should not advise to put the config in the prototype, ever. Doing this makes the config object shared by all children. As such any modification on it will also affect all children. Shame on me, I wasn’t a beginner when I wrote this crap. Double thanks Jake ;)
A better implementation:
// Keep defaults private
var defaults = {
foo : 'foo',
bar : 'bar'
};
// Construct
var Mod = function Mod (opts) {
opts = (opts === Object(opts)) ? opts : {};
// This allows users to instanciate without the `new` keyword
if (! (this instanceof Mod)) {
return new Mod(opts);
}
this.config = {};
// Copy user provided configs to this.config or set to default
for (var key in defaults) if (defaults.hasOwnProperty(key)) {
if ({}.hasOwnProperty.call(opts, key)) {
this.config[key] = opts[key];
}
else {
this.config[key] = defaults[key];
}
}
};
// Let the user update configuration post-instanciation
Mod.prototype.configure = function configure (key, val) {
this.config[key] = val;
return this;
};
// Export a function that creates the object
exports.createMod = function createMod (opts) {
return new Mod(opts);
};
// Export the constructor so user is able to derive from it
// or check instanceof
exports.Mod = Mod;
// USAGE
var mod = require('/path/to/mod');
var i1 = mod.createMod({ foo : 'bar' });
i1.configure('bar', 'baz');
It depends on whether you want the users of your module be able to use exactly one pre-defined instance (the one that you create on module.exports
) or if you want them to be able to create their own instances (then you need to export the constructor as a function, not its return value).
If you go and write a constructor, I'd opt for the second option (let the user create the instances) - except if it's a singleton object you are providing.