Node.js + Express - How to get Mustache partials working? - node.js

I'm trying to get Mustache working properly with Express, and as one can guess, I'm having troubles.
The following line initializes Mustache nice and clean. Variables render as expected.
app.register('html', require(__dirname+'/public/js/libs/mustache.js'));
However, the problems start to rise when partials are thrown in the mix. With Mustache, this here partial should invoke header view/partial.
{{> header}}
But alas, nothing happens. :/ Even when I offer the partial directly, Mustache fails to render it.
app.get('/', function(req, res) {
res.render('welcome', {
partials: {
header: '<h1>Header</h1>'
}
});
});
So, it seems that the partials aren't working at all. I've found one hack that get's the partials somewhat working:
http://bitdrift.com/post/2376383378/using-mustache-templates-in-express
After that the partials render when offered directly at render call (see above), but it still fails on rendering the partials directly to views/layouts:
Layout looks something like this:
Behold, the header
{{> header}}
<p>Let's move to more important stuff...</p>
Header view looks something like this:
<h1>Header</h1>
Express can load the views by themselves just ok, but it doesn't know how to handle the Mustache partials...

Using express (at least version 3) and mustache-express, You can load partials as usual using double mustaches that begin with a greater than sign.
First consider the following is appended within our app.js file:
/** import the module */
import mustache from 'mustache-express';
/** view engine setup */
app.engine('mst', mustache());
app.set('view engine', 'mst');
app.set('views', path.join(__dirname, 'mvc/views'));
/** the route where we will display the partials */
app.get('/', (req, res) => {
let view = {
title: 'Homepage',
// ...
};
/** we are going to use a file called template.mst for rendering */
res.render('template', view);
});
Any double mustaches that begin with a greater than sign (i.e. {{> file}}) will be considered a partial. The file within the partial will be rendered at runtime. Consider this file to be a partial we want to insert:
mvc/views/partial.mst
<h2>418 | I'm a teapot</h2>
And here is our template:
mvc/views/template.mst
<h1>template.mst file</h1>
<!-- output: <h2>418 | I'm a teapot</h2> -->
{{> partial}}

Managed to get this working with the latest version of hogan-express.
https://github.com/vol4ok/hogan-express
All that is needed is to install hogan-express and use it as template engine on express. No hacking or tuning required.

I'm not sure what's exactly in your ./public/js/libs/mustache.js ... I use the mustache module from npm + a variation of the templating object you linked to.
In any case, the object you pass to app.register needs to call mustache.to_html(template, locals, partials) at some point.
You need to pass the partials object as the third argument to mustache's to_html.

Related

Using i18n + handlebars in an express app, but not to generate output html, how to localize?

I have an Express app in which I want to use handlebars to generate localised templated emails to be sent out. The problem is that handlebars requires a globally registered helper to translate items inside the .hbs files, while I need to use a construct such as app.use(i18n.init) to make sure my __ function translates according to the right locale in the context of the current request. Setting a locale globally will lead to concurrency issues.
The only 'solutions' (which aren't because they don't solve my problem) I found consist of using handlebars middleware to output html using Express, but that is not what I want to do. I want to generate content that's completely independent from what Express sends back to the client.
This is what I am currently doing, which obviously isn't the way to do it
const i18n = require("i18n")
const Handlebars = require('handlebars')
i18n.configure({
directory: './i18n',
defaultLocale: 'en',
objectNotation: true,
syncFiles: true
})
Handlebars.registerHelper('i18n',
function (str) {
if(!str) return str
return i18n.__(str)
}
)
to be used as
<td>
{{i18n "title"}}
</td>
A possible solution is to do the translations in code by calling i18n.__({phrase: "someText", locale: locale}) but I would like to keep this inside the template.
How can I make sure handlebars uses the i18n instance bound to the Express response object?

Express and Handlebars: Implementing multiple themes

I and the team got a task to implement multiple themes for our project (keeping in mind that we have a single-theme project right now).
By theme I don't mean just CSS, I mean different markup files, certain features for certain things, etc. (If you don't like the word 'theme' in this context don't use it, I hope you get the idea: some things need to be reused across the codebase, some things need to be specific to a theme). Overall, we have no problem of structuring it in a maintainable way and implementing the most of it, but we don't know how to make multiple express-handlebars configs, which we can switch based on certain factors.
Right now we have a pretty standard express-handlebars project structure like such:
views/
index
layouts/
main.hbs
content.hbs
whatever.hbs
What we want is something like this:
views/
themes
theme1
layouts/
main.hbs
index.hbs
content.hbs
theme2
layouts/
main.hbs
index
We use a pretty standard way to initialize express-handlebars in our app startup file like this:
var handlebars = exphbs.create({
defaultLayout: 'main',
extname: '.hbs',
helpers: require('./server/hbsHelpers')
});
app.engine('.hbs', handlebars.engine);
app.set('view engine', '.hbs');
app.set('views', __dirname + '/views');
I was thinking to initialize several exphbs objects and switch them at runtime (request time) but this is not going to work since app.set would be an app-wide setting (long story short we host multiple websites with one app and can't afford change anything on app level, only on the express request level).
Desired behaviour is something like this:
res.render(‘/theme1/file.hbs’);
looks like there's no problem just to render directly without a configuration, but then we also need to specify that handlebars needs to grab layouts and partials for a specific theme from a specific source
or
res.render(‘file.hbs’, { theme: ‘theme1’ });
We're using this variant of express handlebars – https://github.com/ericf/express-handlebars
(May be you can advice an alternative that allows what I described above that we can interchange and not break a lot of things - our code base is pretty huge)?
Any of your help, ideas or advice would be highly appreciated.
You didn't mention how you would determine which theme each request would be rendered with but I think the simplest approach is to override the res.render() method.
app.use(function(req, res, next) {
// cache original render
var _render = res.render;
res.render = function(view, options, done) {
// custom logic to determine which theme to render
var theme = getThemeFromRequest(req);
// ends up rendering /themes/theme1/index.hbs
_render.call(this, 'themes/' + theme + '/' + view, options, done);
};
next();
});
function getThemeFromRequest(req) {
// in your case you probably would get this from req.hostname or something
// but this example will render the file from theme2 if you add ?theme=2 to the url
if(req.query && req.query.theme) {
return 'theme' + req.query.theme;
}
// default to theme1
return 'theme1';
}
The nice thing about this is your calls in your controller will still be clean - res.render('feature/index.hbs') as long as you have that file in each theme folder you should be good.
You could make getThemeFromRequest a lot smarter and it could check to see if the template exists for that theme and if not render the file from the default theme which may help prevent a bunch of duplicate html.

using dustjs-linkedin templates in node.js and express3.x

I can't figure out how to use the dustjs-linkedin templates for express 3.x
#app.js
var dust = require('dustjs-linkedin');
app.set('view engine', 'dust');
app.get('/test1', routes.test1);
#./routes/test.js
exports.test1 = function(req, res){
res.locals.session = req.session;
res.render('test1', { title: 'Test 1' } );
};
#./views/test1.dust
{+base.dust/}
{<main}
Child Content
{/main}
#./views/base.dust
{+main}
Base Content
{/main}
I get the following error when going to /test1
500 Error: Cannot find module 'dust'
I had the same problems as you. And to ease the use of dustjs-linkedin together with express 3.x i put together the small library klei-dust. The library is simple to setup and you can set the root folder for views, which applies to base-templates and partials.
So if you have a views folder at views/ with home.dust and base.dust templates, the home.dust can look like this:
{>base/}
{<main}
Hello world
{/main}
So there's no need to write views/base.dust for it to work.
I've managed to get a working version of dustjs-linkedin with consolidate module.
https://github.com/chovy/express-template-demo
FYI, the layout has to be double quoted...that was a major gotcha for me, and its relative to app.js file, and it needs a trailing /
{+"views/base.dust"/}
<p>Page content here</p>
I will explain u how you should use express 3.x with dustjs-linkedin.
1) express has 2 config to set. 'view engine' and app.engine
"view engine" just sets the default and that app.engine just maps what engine to use for a given file extension.
so you should do something like this:
app.set('view engine', 'dustjs-linkedin');
app.set('views', __dirname + '/views');
app.engine('dust', dust.compileFromPath);
There is only one problem with this is that the method compileFromPath doesn't exist in dust :p.
You should add a method in the dust object with this signature that Express expects: (path, options, callback)
you can read more about this here: http://expressjs.com/api.html#app.engine.
Another option would be to use consolidate (http://spalatnik.com/blog/?p=54) but unfortunately Consolidate doesn't support the dustjs-linkedin version it only support the old dust version.

Mustache(-like) template engine for Express?

Is there a template engine for Express (node.js) which is based on Mustache or uses a similar syntax?
All I could find is haml, jade, ejs, jquery templates and one based on CoffeeScript (I write plain JS).
I want to write "normal" html, so only ejs and jqtpl would fit. I already use mustache with backbone so it would be best to also use it on the server side with Node.js
Just stumbled on this ancient thread but no one has mentioned consolidate.js, which seems to be the "right" way under Express 3 (refer to http://expressjs.com/faq.html). It also provides an easy way to switch/experiment with templating systems.
Here's a simple example - http://invitingthebell.com/2012/12/24/mustache-templates-in-express-3-0/.
Code, in case it disappears is:
var express = require('express')
, cons = require('consolidate')
, app = express();
// assign the mustache engine to .html files
app.engine('html', cons.mustache);
// set .html as the default extension
app.set('view engine', 'html');
app.set('views', __dirname + '/views');
// test mustache
app.get('/', function(req, res){
var viewdata = { 'test' : 'Hey now.'};
res.render('index', viewdata);
});
app.listen(3000);
The index.html file in the views directory:
<html>
<head><title>Some CMS</title></head>
<body>
<h1>Mustache</h1>
<p>What do you say?</p>
<p>{{test}}</p>
</body>
</html>
You could probably add Mustache as a rendering engine by following the Express manual:
View filenames take the form “.”, where is the name of the module >that will be required. For example the view layout.ejs will tell the view system to >require(‘ejs’), the module being loaded must export the method exports.compile(str, >options), and return a Function to comply with Express.
Edit:
From the Mustache manual under Usage:
Below is quick example how to use mustache.js:
var view = {
title: "Joe",
calc: function () {
return 2 + 4;
}
};
var output = Mustache.render("{{title}} spends {{calc}}", view);
In this example, the Mustache.render function takes two parameters: 1) the mustache >template and 2) a view object that contains the data and code needed to render the >template.
From the above I suspect you could just export Mustache.render, but I haven't tested it. The object literals used as data look the same, but if they do happen to be different, you could probably just wrap Mustache.render in a function that formats it correctly.
Edit: Xomby's wrapper link contains an example of how to wrap handlebars for express, Mustache should be similar.
Try Hogan.js http://twitter.github.com/hogan.js/
I think it's what Twitter and LinkedIn uses in production.
Here's a working example/tutorial on using NodeJS, ExpressJS and MustacheJS Template Engine:
http://devcrapshoot.com/javascript/nodejs-expressjs-and-mustachejs-template-engine
You can build out a complete web page like you normally would, placing the mustacheJS fields where you like. Use express to route to the page, use node fs.readFileSync(); to get the html file, use mustache to update the data on the page then spit it out to the client.
It's kinda neat. I hope it helps!
-A-
Have you already tried stache ? It is no longer maintained but you can follow some links and get more recent stuff ..
I found Handlebars.js which is an extension of the Mustache template system/language.
And there is a really simple wrapper to use it with Express.
Sure, the best way to do this is the post here:
http://iamtherockstar.com/blog/2011/11/21/using-mustache-templates-express-apps/
So far, this has worked great for me. The only problem I have found is not using partials at the root path for views. For example partials in view/partials - the engine by default only finds partials as view. Let me know if you figure that out!
Check out Handlerbars. " Handlebars provides the power necessary to let you build semantic templates effectively with no frustration.
Handlebars is largely compatible with Mustache templates. In most cases it is possible to swap out Mustache with Handlebars and continue using your current templates. Complete details can be found here " - Handlebars

How can express and jade does not compress html?

I using express and jade, but when I debug I doesn't want jade compress my html, are there any way to pass an option jade globally and make it does not compress html.
If you use Express 3.x, you can control compression via app.locals.pretty. I usually enable it while development:
app.configure('development', function () {
app.locals.pretty = true;
});
In the time since this answer was written an option has been added to control this behaviour.
app.locals.pretty = true;
At the moment, no. This feature has been discussed here:
https://github.com/visionmedia/jade/pull/205
The html doesn't actually get compressed or minified by default, though. It's just not formatted nicely. The simplest way I've found to make it human-readable is to use Chrome's dev tools, which give you a nice foldable representation of the source.
You can use Jade Comments to annotate your code for viewing in the browser.
//h1
h1 Some Title
//p
p some content
will output
<!--h1-->
<h1>Some Title</h1>
<!--p-->
<p>some content</p>
The template is already compiled once it leaves the server, so if you wanted to view the template in the browser you would have to write a plugin that de-compiles html to jade and than display the decompiled version.
Huh, new to nodejs so maybe missing something here; but in app.js adding app.set('view options', {pretty: true}); was ineffectual (using express 3.0.3).
..doesn't appear to be supported? did find a workaround, e.g. on a per route basis:
exports.index = function(req, res){
res.render('index', {
[... other stuff ...]
pretty: true
});
};
For whom using pug-cli, you need to add --pretty in cmd(terminal). Like the following,
pug --pretty -w -o dist/html/ assets/pug/index.pug

Resources