
Security News
Security Community Slams MIT-linked Report Claiming AI Powers 80% of Ransomware
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.
express3-handlebars
Advanced tools
express-handlebarsThis package has been renamed to express-handlebars, be sure to
update your package.json files.
See: https://www.npmjs.org/package/express-handlebars
A Handlebars view engine for Express which doesn't suck.
I created this project out of frustration with the existing Handlebars view engines for Express. As of version 3.x, Express got out of the business of being a generic view engine — this was a great decision — leaving developers to implement the concepts of layouts, partials, and doing file I/O for their template engines of choice.
After building a half-dozen Express apps, I developed requirements and opinions about what a Handlebars view engine should provide and how it should be implemented. The following is that list:
Add back the concept of "layout", which was removed in Express 3.x.
Add back the concept of "partials" via Handlebars' partials mechanism.
Support a directory of partials; e.g., {{> foo/bar}} which exists on the
file system at views/partials/foo/bar.handlebars by default.
Smart file system I/O and template caching. When in development, templates are always loaded from disk. In production, raw files and compiled templates are cached, including partials.
All async and non-blocking. File system I/O is slow and servers should not be blocked from handling requests while reading from disk. I/O queuing is used to avoid doing unnecessary work.
Ability to expose precompiled templates and partials to the client, enabling template sharing and reuse.
Ability to use a different Handlebars module/implementation other than the Handlebars npm package.
This package was designed to work great for both the simple and complex use cases. I intentionally made sure the full implementation is exposed and is easily overrideable.
The package exports a function which can be invoked with no arguments or with a
config object and it will return a function (closed over sane defaults) which
can be registered with an Express app. It's an engine factory function.
This exported engine factory has two properties which expose the underlying implementation:
ExpressHandlebars(): The constructor function which holds the internal
implementation on its prototype. This produces instance objects which store
their configuration, compiled and precompiled templates, and expose an
engine() function which can be registered with an Express app.
create(): A convenience factory function for creating ExpressHandlebars
instances.
An instance-based approach is used so that multiple ExpressHandlebars
instances can be created with their own configuration, templates, partials, and
helpers.
Install using npm:
$ npm install express3-handlebars
This view engine uses sane defaults that leverage the "Express-way" of structuring an app's views. This makes it trivial to use in basic apps:
Directory Structure:
.
├── app.js
└── views
    ├── home.handlebars
    └── layouts
        └── main.handlebars
2 directories, 3 files
app.js:
Creates a super simple Express app which shows the basic way to register a Handlebars view engine using this package.
var express = require('express'),
    exphbs  = require('express3-handlebars'),
    app = express();
app.engine('handlebars', exphbs({defaultLayout: 'main'}));
app.set('view engine', 'handlebars');
app.get('/', function (req, res) {
    res.render('home');
});
app.listen(3000);
views/layouts/main.handlebars:
The main layout is the HTML page wrapper which can be reused for the different
views of the app. {{{body}}} is used as a placeholder for where the main
content should be rendered.
<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Example App</title>
</head>
<body>
    {{{body}}}
</body>
</html>
views/home.handlebars:
The content for the app's home view which will be rendered into the layout's
{{{body}}}.
<h1>Example App: Home</h1>
The above example is bundled in this package's examples directory, where it can be run by:
$ cd examples/basic/ && node app
Another way to use this view engine is to create an instance(s) of
ExpressHandlebars, allowing access to the full API:
var express = require('express'),
    exphbs  = require('express3-handlebars'),
    app = express(),
    hbs = exphbs.create({ /* config */ });
// Register `hbs.engine` with the Express app.
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
// ...still have a reference to `hbs`, on which methods like `loadPartials()`
// can be called.
Note: The Advanced Usage example demonstrates how ExpressHandlebars
instances can be leveraged.
This view engine uses a smart template caching strategy. In development, templates will always be loaded from disk, i.e., no caching. In production, raw files and compiled Handlebars templates are aggressively cached.
The easiest way to control template/view caching is through Express' view cache setting:
app.enable('view cache');
Express enables this setting by default when in production mode, i.e.,
process.env.NODE_ENV === "production".
Note: All of the public API methods accept options.cache, which gives
control over caching when calling these methods directly.
A layout is simply a Handlebars template with a {{{body}}} placeholder.
Usually it will be an HTML page wrapper into which views will be rendered.
This view engine adds back the concept of "layout", which was removed in Express
3.x. It can be configured with a path to the layouts directory, by default it's
set to "views/layouts/".
There are two ways to set a default layout: configuring the view engine's
defaultLayout property, or setting Express locals app.locals.layout.
The layout into which a view should be rendered can be overridden per-request
by assigning a different value to the layout request local. The following
will render the "home" view with no layout:
app.get('/', function (req, res, next) {
    res.render('home', {layout: false});
});
Helper functions, or "helpers" are functions that can be registered with Handlebars and can be called within a template. Helpers can be used for transforming output, iterating over data, etc. To keep with the spirit of logic-less templates, helpers are the place where logic should be defined.
Handlebars ships with some built-in helpers, such as: with, if, each,
etc. Most application will need to extend this set of helpers to include
app-specific logic and transformations. Beyond defining global helpers on
Handlebars, this view engine supports ExpressHandlebars instance-level
helpers via the helpers configuration property, and render-level helpers via
options.helpers when calling the render() and renderView() methods.
The following example shows helpers being specified at each level:
app.js:
Creates a super simple Express app which shows the basic way to register
ExpressHandlebars instance-level helpers, and override one at the
render-level.
var express = require('express'),
    exphbs  = require('express3-handlebars'),
    app = express(),
    hbs;
hbs = exphbs.create({
    // Specify helpers which are only registered on this instance.
    helpers: {
        foo: function () { return 'FOO!'; },
        bar: function () { return 'BAR!'; }
    }
});
app.engine('handlebars', hbs.engine);
app.set('view engine', 'handlebars');
app.get('/', function (req, res, next) {
    res.render('home', {
        showTitle: true,
        // Override `foo` helper only for this rendering.
        helpers: {
            foo: function () { return 'foo.'; }
        }
    });
});
app.listen(3000);
views/home.handlebars:
The app's home view which uses helper functions to help render the contents.
<!doctype html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Example App - Home</title>
</head>
<body>
    <!-- Uses built-in `if` helper. -->
  {{#if showTitle}}
    <h1>Home</h1>
  {{/if}}
    <!-- Calls `foo` helper, overridden at render-level. -->
    <p>{{foo}}</p>
    <!-- Calls `bar` helper, defined at instance-level. -->
    <p>{{bar}}</p>
</body>
</html>
Refer to the Handlebars website for more information on defining helpers:
There are two main ways to use this package: via its engine factory function, or
creating ExpressHandlebars instances; both use the same configuration
properties and defaults.
var exphbs = require('express3-handlebars');
// Using the engine factory:
exphbs({ /* config */ });
// Create an instance:
exphbs.create({ /* config */ });
The following is the list of configuration properties and their default values (if any):
defaultLayoutThe string name or path of a template in the layoutsDir to use as the default
layout. This is overridden by a layout specified in the app or response
locals. Note: A falsy value will render without a layout; e.g.,
res.render('home', {layout: false});.
extname=".handlebars"The string name of the file extension used by the templates. This value should
correspond with the extname under which this view engine is registered with
Express when calling app.engine().
The following example sets up an Express app to use .hbs as the file extension
for views:
var express = require('express'),
    exphbs  = require('express3-handlebars'),
    app = express();
app.engine('.hbs', exphbs({extname: '.hbs'}));
app.set('view engine', '.hbs');
Note: Setting the app's "view engine" setting will make that value the
default file extension used for looking up views.
handlebars=require('handlebars')The Handlebars module/implementation. This allows for the ExpressHandlebars
instance to use a different Handlebars module/implementation than that provided
by the Handlebars npm package.
helpersAn object which holds the helper functions used when rendering templates with
this ExpressHandlebars instance. When rendering a template, a collection of
helpers will be generated by merging: handlebars.helpers (global), helpers
(instance), and options.helpers (render-level). This allows Handlebars'
registerHelper() function to operate as expected, will providing two extra
levels over helper overrides.
layoutsDir="views/layouts/"The string path to the directory where the layout templates reside.
partialsDir="views/partials/"The string path to the directory where the partials templates reside.
The public API properties are provided via ExpressHandlebars instances. In
additional to the properties listed in the Configuration and Defaults
section, the following are additional public properties:
compiledAn object cache which holds compiled Handlebars template functions in the
format: {"path/to/template": [Function]}.
engineA function reference to the renderView() method which is bound to this
ExpressHandlebars instance. This bound function should be used when
registering this view engine with an Express app.
handlebarsVersionThe version number of handlebars as a semver. This is unsed internally to
branch on certain operations which differ between Handlebars releases.
precompiledAn object cache which holds precompiled Handlebars template strings in the
format: {"path/to/template": [String]}.
The following is the list of public API methods provided via ExpressHandlebars
instances:
loadPartials(options|callback, [callback])Retrieves the partials in the partialsDir and passes an object mapping the
partials in the form {name: partial} to the callback.
By default each partial will be a compiled Handlebars template function. Use
options.precompiled to receive the partials as precompiled templates — this is
useful for sharing templates with client code.
Parameters:
[options]: Optional object containing any of the following properties:
[cache]: Whether cached templates can be used if they have already been
requested. This is recommended for production to avoid unnecessary file I/O.
[precompiled=false]: Whether precompiled templates should be provided,
instead of compiled Handlebars template functions.
callback: Function to call once the partials are retrieved.
The name of each partial corresponds to its location in partialsDir. For
example, consider the following directory structure:
views
└── partials
    ├── foo
    │   └── bar.handlebars
    └── title.handlebars
2 directories, 2 files
loadPartials() would produce the following result:
var hbs = require('express3-handlebars').create();
hbs.loadPartials(function (err, partials) {
    console.log(partials);
    // => { 'foo.bar': [Function],
    // =>    title: [Function] }
});
Note: The partial name "foo.bar" would ideally be "foo/bar", but this is
being prevented by a Handlebars bug. Once this bug is fixed, a future
version will use a "/" separator. Templates requiring the partial still use:
{{> foo/bar}}.
loadTemplate(filePath, options|callback, [callback])Retrieves the template at the specified filePath and passes a compiled
Handlebars template function to the callback.
Use options.precompiled to receive a precompiled Handlebars template.
Parameters:
filePath: String path to the Handlebars template file.
[options]: Optional object containing any of the following properties:
[cache]: Whether a cached template can be used if it have already been
requested. This is recommended for production to avoid necessary file I/O.
[precompiled=false]: Whether a precompiled template should be provided,
instead of a compiled Handlebars template function.
callback: Function to call once the template is retrieved.
loadTemplates(dirPath, options|callback, [callback])Retrieves the all the templates in the specified dirPath and passes an object
mapping the compiled templates in the form {filename: template} to the
callback.
Use options.precompiled to receive precompiled Handlebars templates — this is
useful for sharing templates with client code.
Parameters:
dirPath: String path to the directory containing Handlebars template files.
[options]: Optional object containing any of the following properties:
[cache]: Whether cached templates can be used if it have already been
requested. This is recommended for production to avoid necessary file I/O.
[precompiled=false]: Whether precompiled templates should be provided,
instead of a compiled Handlebars template function.
callback: Function to call once the templates are retrieved.
render(filePath, options|callback, [callback])Renders the template at the specified filePath using this instance's helpers
and partials, and passes the resulting string to the callback.
The options will be used both as the context in which the Handlebars template
is rendered, and to signal this view engine on how it should behave, e.g.,
options.cache = false will load always load the templates from disk.
Parameters:
filePath: String path to the Handlebars template file.
[options]: Optional object which will serve as the context in which the
Handlebars template is rendered. It may also contain any of the following
properties which affect this view engine's behavior:
[cache]: Whether a cached template can be used if it have already been
requested. This is recommended for production to avoid unnecessary file I/O.
[helpers]: Render-level helpers should be merged with (and will override)
instance and global helper functions.
callback: Function to call once the template is retrieved.
renderView(viewPath, options|callback, [callback])Renders the template at the specified viewPath as the {{{body}}} within the
layout specified by the defaultLayout or options.layout. Rendering will use
this instance's helpers and partials, and passes the resulting string to the
callback.
This method is called by Express and is the main entry point into this Express
view engine implementation. It adds the concept of a "layout" and delegates
rendering to the render() method.
The options will be used both as the context in which the Handlebars templates
are rendered, and to signal this view engine on how it should behave, e.g.,
options.cache=false will load always load the templates from disk.
Parameters:
viewPath: String path to the Handlebars template file which should serve as
the {{{body}}} when using a layout.
[options]: Optional object which will serve as the context in which the
Handlebars templates are rendered. It may also contain any of the following
properties which affect this view engine's behavior:
[cache]: Whether cached templates can be used if they have already been
requested. This is recommended for production to avoid unnecessary file I/O.
[helpers]: Render-level helpers should be merged with (and will override)
instance and global helper functions.
[layout]: Optional string path to the Handlebars template file to be used
as the "layout". This overrides any defaultLayout value. Passing a falsy
value will render with no layout (even if a defaultLayout is defined).
callback: Function to call once the template is retrieved.
The following is the list of static API properties and methods provided on the
ExpressHandlebars constructor:
getHandlebarsSemver(handlebars)Returns a semver-compatible version string for the specified handlebars
module/implementation.
This utility function is used to compute the value for an ExpressHandlebars
instance's handlebarsVersion property.
This example shows the most basic way to use this view engine.
This example is more comprehensive and shows how to use many of the features of this view engine, including helpers, partials, multiple layouts, etc.
As noted in the Package Design section, this view engine's implementation is
instance-based, and more advanced usages can take advantage of this. The
Advanced Usage example demonstrates how to use an ExpressHandlebars instance
to share templates with the client, among other features.
This software is free to use under the Yahoo! Inc. BSD license. See the LICENSE file for license text and copyright information.
FAQs
A Handlebars view engine for Express which doesn't suck.
The npm package express3-handlebars receives a total of 221 weekly downloads. As such, express3-handlebars popularity was classified as not popular.
We found that express3-handlebars demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Experts push back on new claims about AI-driven ransomware, warning that hype and sponsored research are distorting how the threat is understood.

Security News
Ruby's creator Matz assumes control of RubyGems and Bundler repositories while former maintainers agree to step back and transfer all rights to end the dispute.

Research
/Security News
Socket researchers found 10 typosquatted npm packages that auto-run on install, show fake CAPTCHAs, fingerprint by IP, and deploy a credential stealer.