shannonmoeller / gulp-hb

A sane Gulp plugin to compile Handlebars templates. Useful as a static site generator.

Home Page:http://npm.im/gulp-hb

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Providing data as input rather than templates

pushred opened this issue · comments

Hi! Great plugin.

In the two projects I've used it for so far I seem to be using it backwards however.. I'm trying to generate many pages from collections of data using just one or a few templates, similar to Jekyll posts/layouts. Something like gulp-wrap is maybe a better fit, but I much prefer having Handlebars helpers, partials, etc. at my disposal.

Currently gulp-hb only accepts templates as input, so in my first project I worked around this by fetching data in another task, storing it as a var, and iterating through that collection in my templates task. Each item is passed to an individual gulp stream with gulp-hb. It's very fast despite this but the method of passing data between tasks feels a bit nasty.

In the second project I wanted to try to do it all in one task. So I source the data rather than templates, pipe it to through2 where I pass the data to another rendering stream. I also use dataEach to access the vinyl file object and update the path for routing to a destination away from the source data, which in this case are Markdown files. I end the stream by pushing the rendered HTML onto the original stream, again with through2. This also works alright but is pretty much a hack, or at least some sort of wrapper plugin of it's own. I guess I could at least do the path update at the end to avoid the dataEach hackery.

Ideally I'm after a workflow like this:

  • Raw data (Markdown or JSON from files/HTTP requests)
  • Preprocessing as needed (Markdown → JSON)
  • Template rendering

This could be achievable in gulp-hb with a new option, template or layout that serves as an alternative to data, which would instead be piped to gulp-hb as JSON files. The stream would output rendered HTML for each data file. All else would remain the same other than perhaps parseDataName which I'm not sure would be applicable since each file would be coming through individually. I've built similar merged objects by piping data files to the gulp-util buffer method and working with the array it produces. This could be another way of supporting that in this workflow.

Anyway just wanted to see if you'd considered this use case, had any better ideas on going about it, and whether you've any interest in this alternative workflow option? I'd be happy to put a PR together if so!

Hi back and thanks! I'll create a more fleshed out example in the examples/ directory, but would something like this fit the bill?:

var gulp = require('gulp');

gulp.task('default', function () {
    var hb = require('gulp-hb'),
        rename = require('gulp-rename');

    return gulp
        .src('src/**/*.json')
        .pipe(hb({
            partials: 'src/partials/**/*.hbs',
            dataEach: function (context, file) {
                // the content IS the data
                file.data = JSON.parse(String(file.content));

                // replace content with minimal handlebars template
                // that loads appropriate layout partial
                file.content = new Buffer('{{> (file.data.layout) }}');

                return context;
            }
        }))
        .pipe(rename({
            // convert `json` extension to `html`
            extname: '.html'
        }))
        .pipe(gulp.dest('dist'));
});

Gulp works best for me when composing plugins that only do one thing and do it well. In this case, gulp-hb takes handlebars templates and renders them. Accepting data as the input feels a bit outside that goal of "only do one thing" to me right now.

Thoughts?

Yup! With a couple of tweaks this works great — I think you meant file.contents and I had to move template compilation after dataEach to use the set template. But definitely a much more elegant solution. These tapping functions really help avoid more options and that whole slippery slope. Code over configuration!

I think I didn't use dataEach for this initially because it didn't feel right modifying file as I thought it was only there to make file properties available to the context. But I was doing that anyway, just not to the extent of this switcharoo. The semantics still feel right, so why not?

Thanks for the super quick response.

Glad to hear that worked out! Sorry for the typos. I should probably rename dataEach to something like prerender so it doesn't feel so wrong.

I moved the template compilation to after the dataEach call and released as v2.6.4.