npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

handgrip

v0.4.0

Published

Enable generator helper for Handlebars

Downloads

12

Readme

Handgrip: Enable generator helpers for Handlebars

Handgrip is a simple wrapper the enables the use of generator inside normal Handelbars helper.

In addition to supporting generator functions, Handgrip keeps the order of executing generator helpers as you write them on template.

Build Status NPM version License

Best suited/tested with Koa or co.

Install

$ npm install handgrip

Generator Helpers

This is an example of basic usage of generator helper. Return a generator function with next as the single argument, just like Koa’s middleware. yield next tells Handgrip to continue parsing the rest of the template.

var hbs = require("handgrip");
var request = require("co-request");

hbs.registerGeneratorHelper("ip", function() {
	return function *(next) {
		var ip = yield request("http://canihazip/s");

		yield next;

		return new hbs.SafeString(ip);
	};
});

Another interesting example of generator helper is to create composable component with Handgrip/Handlebars helpers. Here, a CSS declaration helper will keep tracks of all component CSS on this page.

<!doctype html>
<html>
<head>
{{css "bootstrap"}}
</head>

<body>
<nav>...</nav>
{{component "list"}}
{{component "carousel"}}
</body>
</html>
var hbs = require("handgrip");

hbs.registerGeneratorHelper({
	// gathering all component CSS and write it in <head>
	css: function(name) {
		this._CSS = name.split(",");

		return function*(next) {
			yield next;

			var css = this._CSS.reduce(function(a, b) {
				return a + '<link href="' + b + '" rel="stylesheet" />';
			}, "");

			return new hbs.SafeString( css );
		};
	},
	// run component logic and 
	// report its CSS
	component: function(name) {
		return function *(next) {
			this._CSS = this._CSS || [];
			if (name) this._CSS.push(name);

			// insert your magic here
			...
			yield next;

			return new hbs.SafeString( ... );
		}
	}
});

Nested generator helper is also supported. Checkout test/ folder to see more example on that.

Normal Helpers

registerGeneratorHelper does support normal Handlebars helper as well, just like using the plain Handlebars. Here is an example of registered multiple helper

var hbs = require("handgrip");
var request = require("co-request");

hbs.registerGeneratorHelper({
	hello: function(name) {
		var out = '<b>' + name + '</b> says hello.';
		
		return new hbs.SafeString(out);
	},
	ip: function() {
		return function *(next) {
			var ip = yield request("http://canihazip/s");
	
			yield next;
	
			return new hbs.SafeString(ip);
		}
	}
});

Compiling

Compile template string

var handgrip = require("handgrip");

var tpl = handgrip.render(template, options);
var body = yield tpl(data);

Handgrip.render accepts the same parameters and Handlebars.compile and returns a generator function.

Convert Handblebars compiled templateFn to a Handgrip-compatible one

var handlebars = require("handlebars");
var handgrip = require("handgrip");

// create a compile templateFn
// You could use handgrip.compile(...) as well
var tpl = handlebars.compile(template);

// convert to to Handgrip-compatible
var renderer = Handgrip.createRenderer(tpl);
var body = yield renderer(data);

Handgrip.compile is the same as Handlebars.compile.

Implementaion and caveats (Must-see for layout users)

Handgrip keeps an array of generator functions for each render job.

When Handlebars finishes parsing the template, it replaces those generator helper with placeholder of UUIDs. Then Handgrip begins parsing the generator array and mutate the array as new generator helpers are found, finally Handgrip fills the results back to their corresponding places.

The common way of implementing layout (as found in express-hbs and koa-hbs) is to render the template as string, then create another separate rendering process for layout. Unfornately, this trivial approach is not feasbile with the implementation of Handgrip, since splitting the rendering process means losing track of generator helpers in main template.

However, there is also an easy way of implementing layout with Handgrip.

Layout template:

<!doctype html>
<html>
<head>
{{css}}
{{js}}
...
</head>
<body>
{{__body__}}
</body>
</html>

Main template:

{{registerCSS "foo"}}
{{registerJS "bar"}}
{{pageTitle}}

{{#layout "layoutName"}}
	<!-- your content goes here -->
	...
{{/layout}}

Layout helper (JS):

var hbs = require("handgrip");
hbs.registerHelper("layout", layout);

function layout(layoutName, options) {
	this.__body__ = options.fn.bind(null, this);

	// read layout file into template string
	var layoutTpl = findByName(layoutName);
	// this is the same as handlebars.compile(...)
	return hbs.compile(layoutTpl, this);
}

Build

This is normally used on the server side, so there is no minified version (yet).

Tests

Tested on

  • Handlebars: 2.0.2, 3.0.3, 4.0.5
  • co: 3.0+, 4.0+
  • Node: 0.11.14, 4.4.x, 5.x, 6.x
  • iojs: 1.0.2 or higher

Run the test

$ npm install
$ npm test

License

Copyright (c) 2015 Jingwei "John" Liu

Licensed under the MIT license.