express-mountables v0.0.5
express-mountables
Complements for express framework: controller, middleware, template and page.
Installation
$ npm i -s express-mountables
Why?
To have a set of utilities that can easily complement express framework.
Usage
The usage is always the same:
const express = require("express");
const app = express();
const mount = require("express-mountables").mount;
mount.Controller({ app, ...});
mount.ControllerFactory({ app, ...});
mount.Middleware({ app, ...});
mount.MiddlewareFactory({ app, ...});
mount.Template({ app, ...});
mount.Page({ app, ...});
app.listen(8000);Each mountable behaves differently, you only need to know which is more appropiate for each situation.
Theory
This is a basic vocabulary to understand some differences between some of the controllers.
Mounting time: the moment in which a controller is mounted on the app.
Dispatching time: the moment in which a controller is dispatching a request.
Mountables
This is the list of mountables that offers this package:
Controller
Description:
- The
actionorfileis a function that receives:request,response,next. - Cannot see parameters provided at mounting time.
Possible parameters:
app:Object|Function, express application or router.method:String|Array<String>, HTTP method(s) covered by the handler. It defaults to"GET".route:String|Array<String>, URL route(s) covered by the handler. It defaults to"*".middleware:Function|Array<Function>, the middleware(s) attached to this controller. It defaults to[].file:String, a*.jsfile that contains the handler.action:Functionthat works as the handler. If it is present, it takes preference overfile.
Example:
mount.Controller({
app,
method: ["GET", "POST"],
route: "/",
middleware: [],
action: function(request, response, next) {
response.send("Hi!");
}
});ControllerFactory
Description:
- The
actionorfilegenerates a controller at mounting time. - Can see parameters provided at mouting time.
Possible parameters: the same as Controller.
Example:
mount.ControllerFactory({
app,
method: ["GET", "POST"],
route: "/",
middleware: [],
action: function(parameters, others) {
return function(request, response, next) {
response.send("Hi!");
};
}
});Middleware
Description:
- The
actionorfileis a function that receives:request,response,next. - Cannot see parameters provided at mounting time.
Possible parameters: the same as Controller, except method (it always uses the method app.use(...)).
Example:
mount.Middleware({
app,
route: "/",
action: function(parameters, others) {
return function(request, response, next) {
response.send("Hi!");
};
}
});MiddlewareFactory
Description:
- The
actionorfilegenerates a middleware at mounting time. - Can see parameters provided at mouting time.
Possible parameters: the same as Middleware.
Example:
mount.MiddlewareFactory({
app,
route: "/",
action: function(parameters, others) {
return function(request, response, next) {
response.send("Hi!");
};
}
});Template
Description:
- The
templateorfileprovides or points to anejstemplate that receives:request,response,next, and other parameters too (see below). - Can see parameters provided at mounting time.
Possible parameters:
app: the same asController.method: the same asController.route: the same asController.middleware: the same asController.file:*.ejsfile that contains a template.template:String,ejstemplate source code. If it is present, it takes preference overfile.options:Object,ejsrender options. You can set theasyncflag totrueto handle asynchronous templates.onRenderError:Function, function that receives:error,request,response,next. It should handle the request, when an error on render arises. There is a default handler that, inprocess.env.NODE_ENV === "production"will show a clean page, but in other cases, it will respond the error as it is.
Template parameters:
parameters: the parameters provided to the template mountable.others: the optional parameters provided to the template mountable.process: the current nodeprocessobject.require: therequirefunction.request: the expressrequestobject.response: the expressresponseobject.next: the expressnextfunction.all: all these parameters, for you to find things easily, or continue passing parameters templates down.
Considerations:
- When
templateis provided,ejswill use therendermethod. - When
fileis provided (andtemplateis not),ejswill use therenderFilemethod. - The default error handler depends on
process.env.NODE_ENV === "production"boolean.- on
production, the response will be an HTML page hiding the details of the error. - on other environments, the response will be the error as it is.
- on
- When you use the
async: trueflag forejs, doincludes with theawaitkeyword. - When you use the
cache: falseflag forejs, your file will be read in every request.- To clear the
ejscache, use the methodejs.clearCache. - Take into account that using this method implies calls to
fs.readFileSync.
- To clear the
Example:
mount.Template({
app,
route: "/",
template: "<div>Hello, <%-request.query.user || others.user %>!</div>",
options: { async: true, cache: false }
}, {
user: "anonymous user"
});Page
Description:
- The
templateorfileprovides or points to anejstemplate that receives:request,response,next, and other parameters too (see below). - Can see parameters provided at mounting time.
- They are rendered as
HTML5pages.
Possible parameters: the same as Template, and also:
dependencies:Object. This object represents the known dependencies that a template can include. For example, to includejQueryfrom its CDN, we can do this:
mount.Page({
app,
route: "/",
template: "<% Object.assign(pageDependencies, { jQuery: true }); %><p>Hello, <%-request.query.user || others.user %>!</p>",
options: { async: true, cache: false },
dependencies: {
jQuery: '<script src="https://code.jquery.com/jquery-3.5.1.min.js" defer></script>'
}
}, { user: "anonymous user" });The pageDependencies is a special parameter injected purposedly to the templates that are Pages, and not mere Templates.
In the Page parameters of this section, it is better explained what it is and what it does.
Take into account that the order of the dependencies matters: first tags are rendered before.
Use the attribute defer to load <script> tags asynchronously, but keeping the order in which they are printed.
bodyDependencies:Object. The same as thedependenciesparameter, but instead of inserting them on theheadof the HTML document, they are inserted in thebody.
Page parameters:
The templates for a Page takes the same parameters of a standard Template, but also:
pageDependencies:Object. Empty object that the template can extend to include tags in thehead(orbody) of the page.
How does pageDependencies template parameter works?
- The keys of this object must match the keys of
dependenciesorbodyDependenciesobjects passed to thePagemountable. - The values must be a simple
trueorfalse. - The values can also be direct
Strings: in that case, the code provided in thatStringis directly injected. In this case, the keys do not need to match the keys atdependenciesorbodyDependencies. - This object should be passed across all the templates that are being rendered by a specific
Page, for them to put intruetheir dependencies. - This way, on the top of each template, we can set to this object the resources that we need for that specific template to render adecuatedly.
- This way, we can define the dependencies (
css,js,metatags, etc.) per each template, and reuse that templates without caring about its dependencies.
Handlers API
The Handlers API lets you reuse the code of the mountables without mounting: you pass the parameters, and you get the controller: the function that can handle (request, response, next) parameters.
To access the handlers, instead of accessing to:
require("express-mountables").mount.Controller(...)You access to:
require("express-mountables").handler.Controller(...)Every mountable has its handler defined separatedly.
You only need to access to it, and instantiate it the same way you would do with the mountable.
The only difference between the mountables and the handlers are the parameters that are not required by the handler specifically.
For example, the handlers do not require:
app: ahandlerdoes not need to know about theapporrouterused to mount itself.method: ahandlerdoes not need to know which is the method of the request.route: ahandlerdoes not need to know the route in which, asmountable, it used be restricted to.middleware: ahandlerdoes not need to know the middlewares that, asmountable, it should apply before the handler to be executed.
Utilities API
The following methods are also available from the package to reuse them at convenience:
mountables.createParameters(params = {}). Method to create the parameters used by the templates.mountables.wrapPage(contents = "", dependencies = {}, headDeps = {}, bodyDeps = {}). Method to wrap the contents of an HTML5 document.mountables.errorHandler(error, request, response, next). Method to handle errors in production or non-production environments.
License
This project is licensed under WTFPL or What The Fuck Public License, which means, in short terms, do what you want.
Issues
Please, address issues here.