modulapp
v1.0.1
Published
Modular application framework
Downloads
3
Maintainers
Readme
Modulapp
Modular application framework for node.js
Overview
Modulapp is a framework for defining application in a modular way.
It provides an App
class and a Module
class.
Module concept
Basically a module is an autonomous part of the application. It could be a npm package or it could be a dedicated file in the app's repository. A module can have dependencies (ie. other modules) and can also provides its own API to other dependants.
A module is an instance of the Module
class (which extends EventEmitter). You can add any property and functions to that instance.
Modulapp allows to define hooks for a module. The lifecycle of a module has 4 steps: setup
, enable
, disable
and destroy
. A specific behavior of the module can be defined during those 4 steps. It's during those hooks that dependencies and options are injected to the module.
The App
instance is managing the lifecycle of all modules and dealing with the dependencies and options.
App concept
The App manages the dependencies and the lifecycle of the modules.
An app is an instance of the App
class (which extends EventEmitter). The modules must be declared to the app. Then the lifecycle of the app can be performed. The app's lifecycle is composed of 5 steps:
resolve
: Checks the modules and resolve the dependency treesetup
: Synchronously execute thesetup
hook of every module following the dependency tree orderstart
: Synchronously execute theenable
hook of every module following the dependency tree orderstop
: Synchronously execute thedisable
hook of every module following the dependency tree reverse orderdestroy
: Synchronously execute thedestroy
hook of every module following the dependency tree reverse order
As the modules are processed synchronously following the dependency tree, the dependencies of a particular module have already been processed before it.
Usage
Install from npm
npm install modulapp
To write a module, import the Module
class.
const Module = require('modulapp').Module;
To write an app, import the App
class.
const App = require('modulapp').App;
Example
Module class
// myModule.js
const Module = require('modulapp').Module;
let myModule = new Module("myModule");
// define the dependencies by referencing other modulapp modules' id
myModule.dependencies = ['server', 'db'];
// custom property
myModule.foo = 'foo';
// custom function
myModule.bar = function() {
myModule.emit('bar'); // Module extends EventEmitter
};
// overwrite the setup hook
myModule.setup = function(app, imports, options, done) {
console.log('setting up myModule');
done(null); // executing the done callback is required
};
// overwrite the enable hook
myModule.enable = function(app, imports, options, done) {
console.log('enabling myModule');
let db = imports.db;
db.on('disconnected', () => {
// Do some stuff on event
});
let server = imports.server
server.doSomething((err) => {
if (err) {
done(err); // if something wrong return done with the error
} else {
done(null);
}
});
};
// myModule.disable can also be overwritten
// myModule.destroy can also be overwritten
module.exports = myModule;
App class
// app.js
const App = require('modulapp').App;
let app = new App();
// Get the modules
let server = require('./server.js');
let db = require('./db.js');
let myModule = require('./myModule.js');
// set the configuration
app.addConfig(server, db, myModule);
// start the application
// start() will itself execute resolve() and setup() if not done
app.start((err) => {
if (err) {
console.log(err);
} else {
console.log('app started!');
}
});
someListener.on('destroy app', () => {
app.stop((err) => {
if (err) {
console.log(err);
} else {
app.destroy((err) => {
if (err) {
console.log(err);
} else {
console.log('app destroyed!');
}
});
}
});
});
API References
Classes
App ⇐ EventEmitter
Class representing an App.
Kind: global class
Extends: EventEmitter
Emits: resolving, resolved, setting_up, setup, starting, started, stopping, stopped, destroying, destroyed
Access: public
Since: 1.0.0
Author: nauwep [email protected]
- App ⇐ EventEmitter
- new App([config], [options])
- instance
- .id : String
- .config : Array.<Module>
- .options : Object
- .status : String
- .addOptions([options])
- .addConfig([...config])
- events
- lifecycle management
- static
new App([config], [options])
Provide a new instance of App. The config and options are optionnal.
Throws:
- Error ERR_APP_011 if options is not an Object.
- Error ERR_APP_013 if a module is not a Module instance.
| Param | Type | Default | Description | | --- | --- | --- | --- | | [config] | Module | Array.<Module> | [] | The list of modules. | | [options] | Object | {} | Options for the modules. |
Example
const App = require('modulapp').App;
let app = new App();
let serverModule = require('./server.js');
let dbModule = require('./db.js');
app.addConfig(serverModule, dbModule);
app.start((err) => {
console.log('App started!');
});
app.id : String
The id of the app, randomly generated.
Kind: instance property of App
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
console.log(app.id); // -> '123456789'
app.id = 'anotherId'; // -> throw Error read-only
app.config : Array.<Module>
The configuration of the app. Getting config never return null, at least an empty Array []. Setting null or undefined replaces the current config by an empty Array []. Setting a module will build an Array with that single module.
Kind: instance property of App
Throws:
- Error ERR_APP_013 if a module is not a Module instance.
- Error ERR_APP_014 if the module is not in created status.
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Default | Description | | --- | --- | --- | --- | | [newConfig] | Module | Array.<Module> | [] | The new config. |
Example
console.log(app.config); // -> [loggerModule]
app.config = [serverModule, dbModule]; // -> [serverModule, dbModule]
app.config = null; // -> []
app.config = serverModule; // -> [serverModule]
app.options : Object
The options of the app's modules. Read-write property. Getting options never return null, at least an empty Object {}. Setting null or undefined replaces the current options by an empty Object {}.
Kind: instance property of App
Throws:
- Error ERR_APP_009 if the app is not in created status.
- Error ERR_APP_008 if not an Object
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Default | Description | | --- | --- | --- | --- | | [newOptions] | Object | {} | The new options. |
Example
console.log(app.options); // -> {server: {port: 8080}}
app.options = {server: {host: 'localhost'}}; // -> {server: {host: 'localhost'}}
app.options = null; // -> {}
app.status : String
The status of the module. The value is part of the supported status.
Kind: instance property of App
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
console.log(app.status); // -> 'created'
app.status = App.status.RESOLVED; // -> throw Error read-only
app.addOptions([options])
Add options to the app's modules. Merge with existing options.
Kind: instance method of App
Throws:
- Error ERR_APP_008 if the options parameter is not an Object.
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Default | Description | | --- | --- | --- | --- | | [options] | Object | {} | The options to add. |
Example
console.log(app.options); // -> {server: {port: 8080}}
app.addOptions({server: {host: 'localhost'}}); // -> {server: {port: 8080, host: 'localhost'}}
app.addOptions(null); // -> {server: {port: 8080, host: 'localhost'}}
app.addOptions(); // -> {server: {port: 8080, host: 'localhost'}}
app.addOptions({db: {host: '127.0.0.0'}}); // -> {server: {port: 8080, host: 'localhost'}, db: {host: '127.0.0.0'}}
app.addConfig([...config])
Add modules to the app's configuration. Merge with existing config and check the new modules and remove duplicates and null.
Kind: instance method of App
Throws:
- Error ERR_APP_013 if a module is not a Module instance.
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description | | --- | --- | --- | | [...config] | Module | Array.<Module> | The modules to add. |
Example
console.log(app.config); // -> [loggerModule]
app.addConfig([serverModule]); // -> [loggerModule, serverModule]
app.addConfig(null); // -> [loggerModule, serverModule]
app.addConfig(); // -> [loggerModule, serverModule]
app.addConfig(socketModule); // -> [loggerModule, serverModule, socketModule]
app.addConfig(socketModule, utilsModule, [dbModule, serverModule]); // -> [loggerModule, serverModule, socketModule, utilsModule, dbModule]
"resolving"
Resolving event. When the app is about to be resolved.
Kind: event emitted by App
Category: events
Since: 1.0.0
"resolved"
Resolved event. When the app has been resolved.
Kind: event emitted by App
Category: events
Since: 1.0.0
"setting_up"
Setting up event. When the app is about to be setup.
Kind: event emitted by App
Category: events
Since: 1.0.0
"setup"
Setup event. When the app has been setup.
Kind: event emitted by App
Category: events
Since: 1.0.0
"starting"
Starting event. When the app is about to be started.
Kind: event emitted by App
Category: events
Since: 1.0.0
"started"
Started event. When the app has been started.
Kind: event emitted by App
Category: events
Since: 1.0.0
"stopping"
Stopping event. When the app is about to be stopped.
Kind: event emitted by App
Category: events
Since: 1.0.0
"stopped"
Stopped event. When the app has been stopped.
Kind: event emitted by App
Category: events
Since: 1.0.0
"destroying"
Destroying event. When the app is about to be destroyed.
Kind: event emitted by App
Category: events
Since: 1.0.0
"destroyed"
Destroyed event. When the app has been destroyed.
Kind: event emitted by App
Category: events
Since: 1.0.0
app.resolve([callback])
Resolve the dependencies of the modules. This method is synchronous, callback is not required.
Kind: instance method of App
Category: lifecycle management
Throws:
- Error ERR_APP_001 if the app is started
- Error ERR_APP_006 in case of dependency cycle
- Error ERR_APP_007 in case of missing module
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description |
| --- | --- | --- |
| [callback] | function | The callback executed after resolving. Raised error is passed as first argument, no other argument: callback(err)
|
Example
const App = require('modulapp').App;
let serverModule = require('./server.js');
let dbModule = require('./db.js');
let app = new App([serverModule, dbModule]);
app.resolve((err) => {
console.log('modules resolved!');
});
Example (resolve with callback)
app.resolve((err) => {
console.error(err); // -> in case of error in resolve, the error is passed to the callback
});
Example (resolve with no callback)
try {
app.resolve();
} catch (err) {
console.error(err); // -> in case of error in resolve, the error is thrown
}
app.setup([callback])
Setup every modules following the dependency graph.
Kind: instance method of App
Category: lifecycle management
Access: public
See: Module#setup
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description |
| --- | --- | --- |
| [callback] | function | The callback executed after setting up. Raised error is passed as first argument, no other argument: callback(err)
|
Example
const App = require('modulapp').App;
let serverModule = require('./server.js');
let dbModule = require('./db.js');
let app = new App([serverModule, dbModule]);
app.setup((err) => {
console.log('modules setup!');
});
// setup() will resolve() itself if not done before
app.start([callback])
Enable every modules following the dependency graph.
Kind: instance method of App
Category: lifecycle management
Access: public
See: Module#enable
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description |
| --- | --- | --- |
| [callback] | function | The callback executed after starting. Raised error is passed as first argument, no other argument: callback(err)
|
Example
const App = require('modulapp').App;
let serverModule = require('./server.js');
let dbModule = require('./db.js');
let app = new App([serverModule, dbModule]);
app.start((err) => {
console.log('app started!');
});
// start() will setup() and resolve() itself if not done before
app.stop([callback])
Disable every modules following the dependency graph.
Kind: instance method of App
Category: lifecycle management
Access: public
See: Module#disable
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description |
| --- | --- | --- |
| [callback] | function | The callback executed after stopping. Raised error is passed as first argument, no other argument: callback(err)
|
Example
const App = require('modulapp').App;
let serverModule = require('./server.js');
let dbModule = require('./db.js');
let app = new App([serverModule, dbModule]);
app.start((err) => {
console.log('app started!');
// Do some stuff
app.stop((err) => {
console.log('app stopped!');
});
});
// app has to be started to be stopped
app.destroy([callback])
Destroy every modules following the dependency graph.
Kind: instance method of App
Category: lifecycle management
Access: public
See: Module#destroy
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description |
| --- | --- | --- |
| [callback] | function | The callback executed after destroying. Raised error is passed as first argument, no other argument: callback(err)
|
Example
const App = require('modulapp').App;
let serverModule = require('./server.js');
let dbModule = require('./db.js');
let app = new App([serverModule, dbModule]);
app.start((err) => {
console.log('app started!');
// Do some stuff
app.stop((err) => {
console.log('app stopped!');
// Do some stuff
app.destroy((err) => {
console.log('app destroyed!');
});
});
});
// app has to be stopped to be destroyed
App.events : enum
All supported events of App class.
{
RESOLVING: 'resolving',
RESOLVED: 'resolved',
SETTING_UP: 'setting_up',
SETUP: 'setup',
STARTING: 'starting',
STARTED: 'started',
STOPPING: 'stopping',
STOPPED: 'stopped',
DESTROYING: 'destroying',
DESTROYED: 'destroyed'
}
Kind: static enum of App
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
app.on(App.events.SETUP, () => {
// define behavior when app has been setup
});
App.status : enum
All supported status of App class.
Don't confuse this static method App.status with the instance method status.
{
CREATED: 'created',
RESOLVED: 'resolved',
SETUP: 'setup',
STARTED: 'started',
STOPPED: 'stopped'
}
Kind: static enum of App
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
if (app.status === App.status.ENABLED) {
app.foo();
}
Module ⇐ EventEmitter
Class representing a Module.
Kind: global class
Extends: EventEmitter
Emits: setting_up, setup, enabling, enabled, disabling, disabled, destroying, destroyed
Access: public
Since: 1.0.0
Author: nauwep [email protected]
- Module ⇐ EventEmitter
- new Module(id, [initialOptions])
- instance
- .id : String
- .status : String
- .version : String
- .options : Object
- .dependencies : Array.<String>
- .addOptions([options])
- .addDependencies([...dependencies])
- events
- lifecycle hooks
- static
new Module(id, [initialOptions])
Create a new instance of Module. The id parameter is required, it could be either a String or an Object representing the package.json.
In case of the package.json is provided, the id, version, dependencies and options will be extracted from this Object.
Throws:
- Error ERR_MOD_001 if the id parameter is null or undefined
- Error ERR_MOD_005 if something wrong on the dependency
| Param | Type | Default | Description | | --- | --- | --- | --- | | id | String | Object | | Either a String id of the module or an Object representing the package.json | | [initialOptions] | Object | {} | Options for the module |
Example
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
myModule.foo = 'foo';
myModule.bar = function() {
// this is a custom method
};
myModule.setup = function(app, options, imports, done) {
// this is overriding the setup method
let logger = imports.logger;
logger.log('setting up myModule');
done(null);
};
module.exports = myModule;
Example (constructor with a String argument)
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
console.log(myModule.id); // -> 'myModule'
console.log(myModule.status); // -> 'created'
console.log(myModule.version); // -> undefined
console.log(myModule.options); // -> {}
console.log(myModule.dependencies); // -> []
Example (constructor with a Object argument)
const packagejson = require('package.json');
// {
// name: 'myModule',
// version: '1.0.0',
// module: {
// dependencies: ['logger'],
// options: {
// port: 8080
// }
// }
// }
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
console.log(myModule.id); // -> 'myModule'
console.log(myModule.status); // ->'created'
console.log(myModule.version); // -> '1.0.0'
console.log(myModule.options); // -> {port: 8080}
console.log(myModule.dependencies); // -> ['logger']
module.id : String
The id of the module.
Kind: instance property of Module
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
console.log(myModule.id); // -> 'myModule'
myModule.id = 'anotherId'; // -> throw Error read-only
module.status : String
The status of the module. The value is part of the supported status.
Kind: instance property of Module
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
console.log(myModule.status); // -> 'created'
myModule.status = Module.status.SETUP; // -> throw Error read-only
module.version : String
The version of the module.
Kind: instance property of Module
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
console.log(myModule.version); // -> '1.0.0'
myModule.version = '1.0.1'; // -> throw Error read-only
module.options : Object
The options of the module. Getting options never return null, at least an empty Object {}. Setting null or undefined replaces the current options by an empty Object {}.
Kind: instance property of Module
Throws:
- Error ERR_MOD_002 if the module is not in created status
- Error ERR_MOD_004 if not an Object
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Default | Description | | --- | --- | --- | --- | | [newOptions] | Object | {} | The new options |
Example
console.log(myModule.options); // -> {port: 8080}
myModule.options = {host: 'localhost'}; // -> {host: 'localhost'}
myModule.options = null; // -> {}
module.dependencies : Array.<String>
The dependencies of the module. Getting dependencies never return null, at least an empty Array []. Setting null or undefined replaces the current config by an empty Array []. Setting a String will build an Array with that single String.
Kind: instance property of Module
Throws:
- Error ERR_MOD_003 if the module is not in created status
- Error ERR_MOD_005 if a non-String dependency is found
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Default | Description | | --- | --- | --- | --- | | [newDependencies] | String | Array.<String> | [] | The new dependencies |
Example
console.log(myModule.dependencies); // -> ['logger']
myModule.dependencies = ['server', 'db']; // -> ['server', 'db']
myModule.dependencies = null; // -> []
myModule.dependencies = 'server'; // -> ['server']
module.addOptions([options])
Add options to the module. Merge with existing options.
Kind: instance method of Module
Throws:
- Error ERR_MOD_004 if the options parameter is not an Object
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Default | Description | | --- | --- | --- | --- | | [options] | Object | {} | The options to add |
Example
console.log(myModule.options); // -> {port: 8080}
myModule.addOptions({host: 'localhost'}); // -> {port: 8080, host: 'localhost'}
myModule.addOptions(null); // -> {port: 8080, host: 'localhost'}
myModule.addOptions(); // -> {port: 8080, host: 'localhost'}
module.addDependencies([...dependencies])
Add dependencies to the module. Merge with existing dependencies and check the new dependencies, flatten the Array and remove duplicates and null.
Kind: instance method of Module
Throws:
- Error ERR_MOD_005 if a non-String dependency is found
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description | | --- | --- | --- | | [...dependencies] | String | Array.<String> | The dependencies to add |
Example
console.log(myModule.dependencies); // -> ['logger']
myModule.addDependencies(['server']); // -> ['logger', 'server']
myModule.addDependencies(null); // -> ['logger', 'server']
myModule.addDependencies(); // -> ['logger', 'server']
myModule.addDependencies('socket'); // -> ['logger', 'server', 'socket']
myModule.addDependencies('socket', 'utils', ['db', 'server']); // -> ['logger', 'server', 'socket', 'utils', 'db']
"setting_up"
Setting up event. When the module is beginning its setup.
Kind: event emitted by Module
Category: events
"setup"
Setup event. When the module has been setup.
Kind: event emitted by Module
Category: events
"enabling"
Enabling event. When the module is about to be enabled.
Kind: event emitted by Module
Category: events
"enabled"
Enabled event. When the module has been enabled.
Kind: event emitted by Module
Category: events
"disabling"
Disabling event. When the module is about to be disabled.
Kind: event emitted by Module
Category: events
"disabled"
Disabled event. When the module has been disabled.
Kind: event emitted by Module
Category: events
"destroying"
Destroying event. When the module is about to be destroyed.
Kind: event emitted by Module
Category: events
"destroyed"
Destroyed event. When the module has been destroyed.
Kind: event emitted by Module
Category: events
module.setup(app, options, imports, done)
The setup function of the module. Executed while the app is being setup. Could be overriden, does nothing by default. Once the app is resolved, this method is not available anymore.
Kind: instance method of Module
Category: lifecycle hooks
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description | | --- | --- | --- | | app | App | The App instance | | options | Object | The options of the module | | imports | Object | The dependencies of the module | | done | function | Callback to return passing any error as first argument done(err) |
Example
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
// override the default setup function
myModule.setup = function(app, options, imports, done) {
// place your custom code to be executed when myModule is setup
}
module.enable(app, options, imports, done)
The enable function of the module. Executed while the app is being started. Could be overriden, does nothing by default. Once the app is resolved, this method is not available anymore.
Kind: instance method of Module
Category: lifecycle hooks
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description | | --- | --- | --- | | app | App | The App instance | | options | Object | The options of the module | | imports | Object | The dependencies of the module | | done | function | Callback to return passing any error as first argument done(err) |
Example
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
// override the default enable function
myModule.enable = function(app, options, imports, done) {
// place your custom code to be executed when myModule is enable
}
module.disable(app, options, imports, done)
The disable function of the module. Executed while the app is being stopped. Could be overriden, does nothing by default. Once the app is resolved, this method is not available anymore.
Kind: instance method of Module
Category: lifecycle hooks
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description | | --- | --- | --- | | app | App | The App instance | | options | Object | The options of the module | | imports | Object | The dependencies of the module | | done | function | Callback to return passing any error as first argument done(err) |
Example
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
// override the default disable function
myModule.disable = function(app, options, imports, done) {
// place your custom code to be executed when myModule is disabled
}
module.destroy(app, options, imports, done)
The destroy function of the module. Executed while the app is being destroyed. Could be overriden, does nothing by default. Once the app is resolved, this method is not available anymore.
Kind: instance method of Module
Category: lifecycle hooks
Access: public
Since: 1.0.0
Author: nauwep [email protected]
| Param | Type | Description | | --- | --- | --- | | app | App | The App instance | | options | Object | The options of the module | | imports | Object | The dependencies of the module | | done | function | Callback to return passing any error as first argument done(err) |
Example
const Module = require('modulapp').Module;
let myModule = new Module('myModule');
// override the default destroy function
myModule.destroy = function(app, options, imports, done) {
// place your custom code to be executed when myModule is destroyed
}
Module.events : enum
All supported events of Module class.
{
SETTING_UP: 'setting_up',
SETUP: 'setup',
ENABLING: 'enabling',
ENABLED: 'enabled',
DISABLING: 'disabling',
DISABLED: 'disabled',
DESTROYING: 'destroying',
DESTROYED: 'destroyed'
}
Kind: static enum of Module
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
myModule.on(Module.events.SETUP, () => {
// define behavior when myModule has been setup
});
Module.status : enum
All supported status of Module class.
Don't confuse this static method Module.status with the instance method status.
{
CREATED: 'created',
SETUP: 'setup',
ENABLED: 'enabled',
DISABLED: 'disabled',
DESTROYED: 'destroyed'
}
Kind: static enum of Module
Access: public
Read only: true
Since: 1.0.0
Author: nauwep [email protected]
Example
if (myModule.status === Module.status.ENABLED) {
myModule.foo();
}