BEM bundles render adapter for express 🌴
Because laziness and short memory. And because simple solutions rocks.
And now it's just a npm i express-bem
and 3 lines of code to use bem blocks library in any app.
- express-bem-bemtree
- express-bem-bemhtml
- express-bem-bh
- express-bem-tools-make bem-tools make middleware
- express-bem-enb-make enb make middleware
express v3.0+
Quick start guide. Run it in your shell:
git clone https://github.com/express-bem/project-stub.git ./express-bem-project-stub
cd express-bem-project-stub
npm install
PORT=3030 node app.js
And after start:
open http://localhost:3030/
Look closer at stub: https://github.com/express-bem/project-stub
$ npm i express-bem --save
To load and init module you can use this snippet:
var Express = require('express');
var ExpressBem = require('express-bem');
// create app and bem
var app = Express();
var bem = ExpressBem({
projectRoot: './path-to/bem-project', // bem project root, used for bem make only
path: './custom.bundles' // path to your bundles
});
// here to lookup bundles at your path you need small patch
app.bem = bem.bindTo(app);
// register engines
bem.usePlugin('express-bem-bemtree'); // requires module express-bem-bemtree
bem.usePlugin('express-bem-bemhtml'); // ... express-bem-bemhtml
Allowed options for cache
param object are:
load
if set tofalse
will reload any template files each timeexec
if set tofalse
will exec template files each time
But also can be set to boolean.
Examples:
var bem = ExpressBem({
cache: {
load: true, // don't reload
exec: false // but execute with context
}
});
var cachingbem = ExpressBem({
cache: true // cache all
});
Also you can add your custom engine
bem.engine('.bh.js', function (name, options, cb) {
// some custom .bh.js realisation
cb(null, 'result');
});
Or even more complex (call this before loading plugins or set default engine by self):
bem.engine('fullstack', '.bem', ['.bemhtml.js', '.bemtree.js'], function (name, options, cb) {
var view = this;
// pass options.bemjson directly to bemhtml
if (options.bemjson) return view.thru('bemhtml');
// return bemjson if requested
if (options.raw === true) return view.thru('bemtree');
// full stack
view.thru('bemtree', name, options, function (err, bemjson) {
if (err) return cb(err);
options.bemjson = bemjson;
view.thru('bemhtml', name, options, function (err, data) {
if (err) return cb(err);
cb(null, data);
});
});
});
See also ExpressBem.prototype.bindTo
method.
And then just use res.render
(or app.render
) in your code and pass
some data (or bemjson
tree) there:
app.get('/', function (req, res) {
res.render('your-bundle', {
bemjson: { // view-oriented bemjson tree here
block: 'page',
content: [
'Hello!'
]
}
}
});
Or raw data to execute bemtree
app.get('/', function (req, res) {
res.render('your-bundle', {
title: 'Cool story #1',
storyId: req.query.id,
story: {title: 'Cool', content: '... Lorem Ipsum ...'}
});
});
If you want to use your bem
repo you can just pull it with git
submodules
or install as npm
package and then just use it as your special bundles path.
.
├── app.js
└── node_modules
└── my-super-mockup
├── desktop.blocks
│ └──...
└── desktop.bundles
├── index
│ ├── index.bemhtml.js
│ └── index.bemtree.js
└── layout
├── layout.bemhtml.js
└── layout.bemtree.js
Otherwise you can import somehow bemhtml.js
and/or bemtree.js
files
to your views
path and use them with default View.prototype.lookup
.
.
├── app.js
└── views
├── index.bemhtml.js
├── index.bemtree.js
├── layout.bemhtml.js
└── layout.bemtree.js
Very simple async render engine
/**
* At least one name/ext definition required in params or engine
* @method engine
* @param {String} [name] optional name of engine
* @param {String} [ext] optional extension of engine
* @param {Object|Function} engine can be function or object with render, name, extension properties
*/
// canonical
bem.engine('even-simpler', '.espl.js', function (name, options, cb) {
cb(null, 'rendered result');
});
// name will be espl
bem.engine('.espl.js', function (name, options, cb) {
cb(null, 'rendered result');
});
// ext will be .espl.js
bem.engine('espl', function (name, options, cb) {
cb(null, 'rendered result');
});
// via function
function evenSimpler(name, options, cb) {
cb(null, 'rendered result');
}
evenSimpler.extension = '.espl.js';
bem.engine(evenSimpler);
// via blackbox (function/object)
bem.engine(require('express-bem-even-simpler-engine'));
// via object
bem.engine({
extension: '.blo.js', // name will be 'blo'
targetExtensions: ['.blo.js'],
render: function (name, options, cb) {
cb(null, 'rendered result');
}
});
You should know that you should set by self default engine if you don't use .bindTo
method. Default engine is the first declared engine.
Like that:
// set first available engine as default
app.set('view engine', bem.defaultViewEngine);
// set concrete default engine
app.set('view engine', '.espl.js');
Middlewares usually calls betweed express' View.prototype.render
and engine's .render
.
/**
* @method use
* @param {Function} middleware depends on arity it can be generator or middleware itself
* @param {Object} opts options passed to middlewares
*/
// using as simple middleware
bem.use(function (ctx, next) {
// current view
var view = this;
// slow down render
setTimeout(next, 2000);
});
// using as generator
bem.use(function (opts) {
// expressBem context
var bem = this;
/**
* @param {Object} ctx Object with name, options, cb properties that can be modified
* @param {Function} next done callback
*/
return function (ctx, next) {
// dump current extension and passed name to render
console.log(this.ext, ctx.name);
// fixup context
ctx.options.raw = 1;
// all is fine go ahead
next();
};
})
It should have engines
(engine
if one) and/or middlewares
(middleware
) properties.
To load plugin into express-bem
instance just call usePlugin
method with some parameters:
/**
* @method usePlugin
* @param {String|Object|Function} plugin name, object or generator
* @param {Object} opts options passed to middlewares
*/
// by module require
bem.usePlugin(require('express-bem-module-name'), { /* options */ });
// by object declaration
bem.usePlugin({
middleware: function (opts) { // middleware generator
return function (ctx, next) {
console.log(ctx.options);
next();
};
}
}, { /* options for middleware */ });
// by function generator
bem.usePlugin(function () { // plugin generator
return {
engines: [{
extension: '.q.js',
render: function (name, options, cb) {
cb(null, name);
}
}, {
extension: '.w.js',
render: function (name, options, cb) {
cb(null, this.ext);
}
}]
};
});
MIT. See also License