moog-require
moog-require
provides powerful module subclassing for server-side development. It extends the features of moog with the following additions:
- Fetches modules from a local modules folder if they are not defined explicitly
- If a module is defined explicitly and also exists in localModules, the local modules folder becomes a source of defaults for properties not defined explicitly
- Fetches modules from npm if they are not defined either explicitly or via the local modules folder
- If a module exists by the same name both in npm and via explicit definition or local modules, automatically extends the npm module without the need for a new name (like the "category" feature of Objective C)
- Provides access to an "asset chain" of subclass module directories and type names, to implement template overrides and the like
- Also supports bundling moog modules in a single npm module, if explicitly configured
Example
module.exports = {
self.construct = function(self, options) {
self.renderTemplate = function(name, data) {
var i;
for (i = 0; (i < options.__meta.length); i++) {
var meta = options.__meta[i];
var path = meta.dirname + '/views/' + name + '.html';
if (fs.existsSync(path)) {
return templateEngine.render(path, data);
}
}
};
};
};
module.exports = {
color: 'red',
construct: function(self, options) {
self.defaultTags = options.tags;
self.get = function(params, callback) {
return callback(events);
};
}
}
module.exports = {
color: 'green',
construct: function(self, options) {
var superGet = self.get;
self.get = function(params, callback) {
params.upcoming = true;
return superGet(params, callback);
};
}
};
var synth = require('moog-require')({
localModules: __dirname + '/lib/modules',
defaultBaseClass: 'module'
});
synth.define({
'module': {
color: 'gray'
},
'events': {
color: 'blue',
},
'parties': {
extend: 'events',
color: 'lavender',
beforeConstruct: function(self, options) {
options.tags = (options.tags || []).concat('party');
},
construct: function(self, options, callback) {
var superGet = self.get;
self.get = function(params, callback) {
params.title = /party/i;
return superGet(params, callback);
};
console.log(options._directories);
},
setBridge: function(modules) {
}
}
});
return synth.createAll({ mailer: myMailer }, function(err, modules) {
return modules.events.get({ ... }, function(err, events) {
...
});
});
synth.bridge(modules);
return synth.create('parties', { color: 'purple' }, function(err, party) {
...
});
Calling require
yourself
Don't.
Well, okay...
If you want to write this:
`extend': require('./lib/weird-place/my-module/index.js')
You may do so, but in that case your module must export its __name
, __dirname
and __filename
, like so:
module.exports = {
__name: 'my-module',
__dirname: __dirname,
__filename: __filename,
construct: function(self, options) { ... }
};
This is only necessary if you are using require
directly. Most of the time, you will be happier if you just specify a module name and let us require
it for you. This even works in npm modules. (Yes, it will still find it if it is an npm dependency of your own module.)
Packaging multiple moog-require modules in a single npm module
Sometimes several modules are conceptually distinct, but are developed and versioned in tandem. In these cases there is no benefit from separate packaging, just a significant delay in npm install
. npm peer dependencies are one way to handle this, but npm peer dependencies may be on the chopping block, and they are significantly slower than pre-packaging modules together.
The difficulty of course is that the link between npm module names and moog-require module names is broken when we do this. So we need another way to indicate to moog-require that it should look in the appropriate place.
Since searching for "X", where X is actually provided by module "Y", is not a core feature of npm itself we have kept this mechanism simple: you can give moog-require
an array of npm module names that contain a "bundle" of definitions rather than a single definition. An npm "bundle" module then must export a moogBundle
array property which contains the names of the moog-require modules it defines. The actual definitions live in lib/modules/module-one/index.js
, lib/modules/module-two/index.js
, etc. within the bundle npm module. moog-require
will find these automatically and will consider these first before requiring normally from npm.
Here's an example:
module.exports = {
moogBundle: {
modules: [ 'module-one', 'module-two' ],
directory: 'lib/modules'
}
};
module.exports = {
construct: function(self, options) { ... }
};
module.exports = {
construct: function(self, options) { ... }
};
var synth = require('moog-require')({
bundles: [ 'mybundle' ],
localModules: __dirname + '/lib/modules',
defaultBaseClass: 'module'
});
synth.define({
'module-one': {},
'module-two': {}
});
Note that just as before, we must include these modules in our explicit define
calls if we want to instantiate them with createAll
, although we don't have to override any properties; we can pass empty objects to just use the defaults defined in the project level folder, and/or implicitly inherit from npm.
However, you may explicitly create
a type that exists only in the project level folder and/or npm.