问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/34866926/express-and-handlebars-implementing-multiple-themes