@muffin-dev/kapp v0.7.2
Muffin Dev for Node - Kapp
Kapp is a lightweight framework for making any kind of easily configurable app made of modules and services.
Core features:
- Very friendly learning curve: a few things are abstracted, no complex system to use, and really easy setup
- Simple module system: create a
module.jsonsomewhere, and you get a module - Reusable services: services are just classes stored in an
Kapp, and can be reused easily in other projects - Configuration system: you can define default configuration for your modules, and override it from environment files
- Hooks management: application and services provide a useful hooks management for triggering events and running asynchronous operations when something happens anywhere in your app
This framework is designed to be used for projects made from scratch, or as an addition of another framework. Since there is a very few abstractions and automatic processes, many things has to be done by yourself, but you can be sure about how your app is working!
That being said, even if there's no default workflow for routing, authentication, etc., the Kapp documentation contains some guides and tutorials for making services that allows your app to work with common frameworks (e.g. routing with express, authentication with passportjs, ...).
Installation
Install it with npm:
npm i @mufifn-dev/kappGetting started
Create a new Node project:
npm initCreate your main app file. Call it as you want, but for this example, let's say app.js:
// app.js
const Kapp = require('@muffin-dev/kapp').Kapp;
const app = new Kapp(__dirname);
app.run();Run the application:
node app.jsDone, your app is running!
Modules
For Kapp, modules are just directories that contain services and configurations, all declared in a module.json file. Here is an example of a module configuration:
{
"name": "routing",
"displayName": "Express Routing",
"services": {
"routing": "./routing.service.js"
},
"config": {
"port": 3000
}
}When you load a Kapp Kapp (with Kapp.load() or Kapp.run() as in the example above), the framework will automatically check for module.json or module.js files in the application directory. For each module file, Kapp will load the declared services (from services property) and the default configuration (from config property) of the module.
Note that module files must at least set the name property.
This module system allows you to store the entire module setup in one file, making it more reusable in other Kapp projects. But you can also register service and define configurations without using module declarations.
=> Learn more modules configuration
Services
Services are classes that provide new functionalities to your app. You can extend the Service class, or make a custom class that implements the IService interface to create a service. Here is an example of a service class:
// my-service.js
const Service = require('@muffin-dev/kapp').Service;
class MyService extends Service {
// init() is called on every registered service when the app is initializing
public init(app, name) {
super.init(app, name);
console.log('MyService initialized');
}
public test() {
console.log('Hello World!');
}
}
// Don't forget to export the service class, or Kapp won't be able to load it!
module.exports = MyService;Now you have a service, you must register it in your application in order to use it. To register a service, you can use the Kapp.addService() method, or as a common usage, the Kapp.use() method (which is just an alias of addService()). These methods requires a name for your new service, and an instance:
// app.js
const Kapp = require('@muffin-dev/kapp').Kapp;
const MyService = require('./my-service');
const app = new Kapp(__dirname);
app.use('my-service', new MyService());
app.run();Now you can run the app and see what happens:
node app.jsYou should see a log "MyService initialized" in your console. This is because when you use Kapp.run(), the app is initialized and started. And during initialization, the init() method of all registered services is called.
If you want to use your service anywhere else in your app, you can use Kapp.service().
Hooks
Hooks allow you to send messages from a service or a regular class to listeners.
This system is handled by the HooksManager class, which allow you to create hooks, add listeners and execute them. Note that the Kapp class has its own, and the Service class implements it for you.
You can use them as regular events, or asynchronous operations stack. There is two methods to add listeners for hooks:
HooksManager.add(): adds a new asynchronous callback to a hook. Asynchronous callbacks can be ordered, and are called one after the other, taking account of asynchronous methodsHooksManager.on(): adds a common event listener. Unlinke the callbacks, event listeners are all called simultaneously
The little difference between hook callbacks and hook listeners can be very handy in some cases. For example, you can use hooks to process a data through several services (for example in a web application, add some data to the user object before sending a response). In that case, you will prefer to use callbacks instead of listeners, because you can be sure that a callback is called before another, and the data is not currently processed by another service at the same time.
As an example, hooks are used in the Kapp class as lifecycle events. In a service, you can listen to the "afterInitServices" hook in order to execute an operation only after all services have been initialized:
// my-service.js
const Service = require('@muffin-dev/kapp').Service;
class MyService extends Service {
public init(app, name) {
super.init(app, name);
console.log('MyService initialized');
// Add a hook callback at service initialization
app.hook('afterInitServices', () => {
console.log('All services have been initialized!');
});
}
}
module.exports = MyService;Configuration
As explained in the Modules section, modules can declare a "default configuration". You can also add configuration from your main app file or from a service with the Kapp.setConfig() method.
Note that even if it's not declared in a module.json file, if there's a file named config.json or config.js at the root of a module directory, its content is loaded as default configuration.
That being said, you can override this "default" configuration before running the app (or even at runtime), which is useful to use "environment" cnfiguration. For example, if your app uses a database, you can setup default credentials, and override them in a dev or a prod environment. Here is an example of the default configuration of a module:
{
"name": "orm",
"displayName": "ORM",
"config": {
"host": "localhost",
"port": 3306,
"username": "root",
"password": ""
}
}Here is an example of a ./env/dev.json environment config file:
{
"host": "localhost",
"port": 3306,
"username": "JohnDoe",
"password": "s3cr3t"
}And now, you can override the existing configuration depending on your environment:
// app.js
const Kapp = require('@muffin-dev/kapp').Kapp;
const app = new Kapp(__dirname);
app.setConfig(`./env/${process.env.NODE_ENV || 'dev'}.json`);
app.run();=> Learn more about configuration
Have fun!
Now you known all the basics of the framework, let's make applications!
Guides & tutorials
You can find several guides and tutorials in the Kapp documentation, where you can learn how to make useful services that brings the power of common tools to your Kapp applications such as Express for authentication, Passport JS for authentication, Electron for making desktop apps, and many more!