express-bem
v1.1.0
Published
bem bundles renderer for express
Readme
express-bem
BEM bundles render adapter for express :palm_tree:
Why
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.
Plugins
- express-bem-bemtree
- express-bem-bemhtml
- express-bem-bh
- express-bem-tools-make bem-tools make middleware
- express-bem-enb-make enb make middleware
Dependencies
Peer
express v3.0+
TL;DR
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.jsAnd after start:
open http://localhost:3030/Look closer at stub: https://github.com/express-bem/project-stub
Installation
$ npm i express-bem --saveUsage
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-bemhtmlAllowed options for cache param object are:
loadif set tofalsewill reload any template files each timeexecif set tofalsewill 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 ...'}
});
});Directories
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.jsOtherwise 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.jsPlugins, engines, middlewares
Engine
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');Middleware
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();
};
})Plugin interface
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);
}
}]
};
});License
MIT. See also License
