fmk v0.0.0
A modular web framework
https://www.npmjs.com/package/fmk
Disclaimer:
This module is not production ready.
It is part of a personal project aiming to improve my coding skills.
cli-tool is coming is this week
Fmk
aims to be a modular framework. It's promise is to enhance your project by a single drag and drop.
Fmk
can manage a large variety of templates. (see templating section).
- Installation
- Project structure
- Module structure
- Controller structure
- Templates
- Router structure
- Model structure
- Crud Model structure
- Server config
- Sequelize config
- Template engines
- Routes in views
- Modules in views
Installation:
Fmk
runs on nodejs.
Use npm to install it.
$ npm install --save fmk
Running the server is easy.
const { Fmk } = require("fmk");
Fmk.start();
Fmk
is based on the MVC design pattern.
Project structure`:
Fmk
structure must be respected as follow:
- /config
- index.js
- /models
- model1.js
- model2.js
- ...
- inxdx.js
- each model must be in a seperate file and imported by index.js
- /modules
- /module1
- /module2
- ...
- index.js
- each module must be in a seperate folder. Index should not be touched as it imports and rexports the modules
- /templates
- template1.ejs|pug|hbs|html...
- template2.ejs|pug|hbs|html...
- ...
- /public
- /css
- /js
- /img
- ...
- app.js
Module structure Fmk
Fmk
is module based
A module must contain a controller, routes, an optionnal model and optionnal views
A module should be seen as an independant brick that you can add and remove without causing a breakdown of the app.
This is the structure of a module
- /modules
- /module1
- controller.js
- model.js
- routes.js
- index.js
- /views
- view1.ejs|pug|hbs|html...
- view2.ejs|pug|hbs|html...
- /module2
- controller.js
- model.js
- routes.js
- index.js
- /views
- view1.ejs|pug|hbs|html...
- view2.ejs|pug|hbs|html...
- ...
Fmk
requires every module when running the start
method
and the Controller base class receives all those modules.
Controller example:
const { Controller } = require('fmk');
module.exports = class Foo extends Controller {
static getIndex(req, res) {
res.end(Foo.render('index.ejs', 'template.ejs', { title: "coucou twé" }));
}
};
The controller methods are used as callbacks by express, they should receive req
and res
in order to manipulate users inputs and render data or views.
The render
method receives the name of one of the views in his module. It is important that the name of the view keeps it's etension since it will determinate wich template engine to use. Second parameter is an optional template placed in the templates
folder of the project. Third argument will be the data to pass in the views.
the view and the template can be written in different template languages only if both template engines are defined in the config.
Templating:
Fmk
aims to manage many template engines. Controller.render
calls the render
or compile
method of those template engines.
- ejs,
- pug,
- handlebars,
- doT,
- mustache,
- twig,
- underscore,
- hogan,
- nunjucks,
- markdown-it
(I didn't test all the template engines for now but implemented their rendering/compiling method)
<!--view.html-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Am a html template</title>
</head>
<body>
<app /><!-- `render` calls str.replace on this tag in order to nest the view in the template -->
</body>
</html>
The template and the view will be compiled from their template language to html separately then merged
Routing:
module.exports = [
['/', []], //[prefix,mainMiddlewares]
[
['index : GET / getIndex', "i'm the index title", []]
//['routeName : method path controllerAction', title for link generation, routeMiddlewares]
]
]
The routes.js
file exports an Array of 2 Arrays.
First is for the main route, second is an array of all the sub routes.
Models:
Models definition follows Sequelize
schema.
const { Model, DataTypes } = require('sequelize');
const { Fmk } = require('fmk');
class BlankModel extends Model { }
BlankModel.init({
name: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
is: /^[a-z]{3,18}$/
}
}
}, {
sequelize: Fmk.sequelize,
tableName: "blank"
});
module.exports = BlankModel;
CRUD models:
Fmk aims to generate Modules from Models (generation cli-tool coming soons)
CRUD models must have a path
and prefix
parameters to generate
personalized routing
class BlankModel extends Model{ }
...
...
BlankModel.prefix = "prefix";
BlankModel.path = "path";
module.exports = BlankModel;
Server configuration:
// config/index.js
...
server = {
port: 80,
host: "localhost",
},
...
Configuration de la base de données:
Fmk
uses Sequelize
as its ORM.
// config/index.js
const {Sequelize} = require('sequelize');
...
sequelize = new Sequelize({
storage: 'db.sqlite',
dialect: 'sqlite',
//database : '',
//host: '',
//username:'',
//passwrod: '',
//port: '',
//...
})
...
template engines:
Template engines must be installed first:
$ npm install --save ejs, handlebars, dot, mustache ....
Engines are defined in the config file at engines
.
The template engine must be called the same name as it's require name.
template:{
engines : [
//"ejs", // : .ejs
//"dot", // : .dot
//"handlebars", // : .hbs
//"hogan.js", // : .hog
//"mustache", // : .must
//"nunjucks", // : .nunj
//"pug", // : .pug
//"twig", // : .twig
//"markdown-it", // : .md
"underscore.template" : require("underscore.template")//: .und
]
};
Routes in templates:
Every route of the module is an instance of the Route
class and are passed to every view in the datas as the routes
parameter.
//view.ejs
...
<%= routes.name %>
...
routes only calls the routes of the module
Route.link()
return an hypertext link and has label
and title
optional parameters since the label is by default the route name and the title is defined in the routes.js
file.
//view.ejs
<%- routes['some-route'].link(label,title) %>
The Route.resolve
method resolves a route with params
let resolved = routes.someRoute.resolve({ id: 4, name: "hello" });
Other routes in views:
Other modules are passed in the views as the modules
parameter.
Since every module has a controller and every controller gets the routes, youi can call modules['moduleName'].controller.routes['routeName'].link/resolve()
.
Official docs:
2 years ago
2 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago