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

How to generate multiple files based in a Json

fega opened this issue · comments

Hello Shannon, I've been using gul-hb as an Static website generator.

Now, I want to generate multiple files based on a Json file array.

how can I achieve that?

thanks!

Glad this has been helpful to you. There are many ways you could generate multiple files, so I'll need a little more context. What does your array look like and what output are you trying to get from it?

Ok!
my looks like:

{ "products" :[{
    "name" : "name of the product",
    "price" : "price of the product",
    "features" : ["feature of the product","feature of the product2"],
    "img" : "url"
}]
}

and I want to generate a html output like this, for every item in the array
http://ekus-group.github.io/productos/producto-test.html

Have I explained that okay?

thanks Shannon.

@fega Sorry for the delay in replying. Generating files based on data objects gets a little more complicated as you have to create the virtual files manually. If you can, having the json as separate files is pretty slick:

https://github.com/shannonmoeller/tmp

Otherwise, something like this might work (untested; note the npm dependencies being imported):

const File = require('vinyl');
const gulp = require('gulp');
const hb = require('gulp-hb');
const streamArray = require('stream-array');
const through = require('through2');

const products = [{
    "id": "foo",
    "name" : "name of the product",
    "price" : "price of the product",
    "features" : ["feature of the product","feature of the product2"],
    "img" : "url"
}];

function makeProducts() {
    return streamArray(products)
        .pipe(through.obj(function (product, enc, cb) {
            const file = new File({
                path: `${product.id}.html`,
                contents: new Buffer('{{name}}'),
                data: product,
            });

            this.push(file);
            cb();
        }))
        .pipe(hb())
        .pipe(gulp.dest('dist/products'));
}

gulp.task('products', makeProducts);

Your milage may vary and this is just one of a few ways this could be tackled. Really depends on your specific needs.

Closing due to inactivity and that this isn't a bug or feature-related thread. Feel free to reopen if needed.

commented

Thought I might just post my problem here, since it's the same concept.

I've got a directory called 'dynamic' that has a bunch of json files. Each one is an array, containing info for a file. I'm wanting to iterate over the array in each JSON file, creating a file for each one using the template file they reference.

This is my current attempt:

gulp.task('createDynamicPages', function createDynamicPages(done) {
    // the global handlebars partials/data/etc for each file to be able to use
    var hbStream = hb()
        .partials(paths.partials)
        .helpers(paths.helpers)
        .data(paths.data);

    // Go through each JSON file in our special directory
    glob.sync("_src/hbs/data/dynamic/*.json").forEach(function(filePath) {
        // Read it as a JSON object
        var jsonFile = JSON.parse(fs.readFileSync(filePath));
        jsonFile.forEach(function(fileData) {
            // They should all be arrays, so iterate over them
            // create a file for each one, using the template + filename they specify
            gulp.src("_src/hbs/partials/" + fileData.partialsName + ".hbs")
                .pipe(data( function(file) { 
                    return fileData
                }))
                .pipe(hbStream)
                .pipe(rename({
                    basename: fileData.slug,
                    extname: '.html'
                }))
                .pipe(gulp.dest(paths.dest + "/" + fileData.dest))
                .pipe(gulp.dest('dist/' + fileData.dest))
                .pipe(livereload())
        });
    });
});

It seems to loop through each correctly. I tried using gutil.log() to check that it's reading everything correctly, and it seems to be all good in that regard. The problem is that it ends up only using the data from the last JSON file it reads. So if the directory has three JSON files, it loops through all three, but only creates the last one three times.

EDIT: Here's my second stab at it.

gulp.task('createDynamicPages', function createDynamicPages(done) {
    // the global handlebars partials/data/etc for each file to be able to use
    var hbStream = hb()
        .partials(paths.partials)
        .helpers(paths.helpers)
        .data(paths.data);

    // this lets us merge all the streams
    var tasks = [];

    // Go through each JSON file in our special directory
    glob.sync("_src/hbs/data/dynamic/*.json").forEach(function(filePath) {
        var jsonFile = JSON.parse(fs.readFileSync(filePath));
        var fileDest = jsonFile[0].dest;

        var currentTask = streamArray(jsonFile)
            .pipe(through.obj(function (fileData, enc, cb) {
                // create the new file to add to the pipe
                const newFile = new File({
                    path: `${fileData.slug}.html`,
                    contents: new Buffer(fs.readFileSync(`_src/hbs/partials/${fileData.partialsName}.hbs`, "utf-8")),
                    data: fileData 
                });

                this.push(newFile);
                cb();
            }))
            .pipe(hbStream)
            .pipe(gulp.dest(paths.dest + "/" + jsonFile[0].dest))
            .pipe(gulp.dest('dist/' + jsonFile[0].dest))
            .pipe(livereload());

        tasks.push(currentTask);
    });
    return merge(tasks);
});

Now it successfully creates the files using the appropriate template + data for each one. The only problem now is that it places them all into each others directories. IE: three json files each with one element in their array will end up creating 9 files; each directory contains every file.

Currently looking into gulp-ignore to see if I can have it only include the files it needs.

EDIT 2: Problem solved!

I was super close with my first attempt. I simply had to make the handlebars stream local.

var hb = require('gulp-hb');
var merge = require('merge-stream');
var fs = require('fs');
var data = require('gulp-data');
var glob = require("glob");

gulp.task('createDynamicPages', function createDynamicPages(done) {
    var tasks = []; // will hold our streams so we can merge them

    // Go through each JSON file in our special directory
    glob.sync("_src/hbs/data/dynamic/*.json").forEach(function(filePath) {
        // Read it as a JSON object
        var jsonFile = JSON.parse(fs.readFileSync(filePath));
        jsonFile.forEach(function(fileData) {
            // They should all be arrays, so iterate over them

            // the handlebars partials/data/etc for each file to use
            var hbStream = hb()
                .partials(paths.partials)
                .helpers(paths.helpers)
                .data(paths.data);

            // create a file for each one, using the template + filename they specify
            var currentTask = gulp.src("_src/hbs/partials/" + fileData.partialsName + ".hbs")
                .pipe(data( function(file) { 
                    return fileData
                }))
                .pipe(hbStream)
                .pipe(rename({
                    basename: fileData.slug,
                    extname: '.html'
                }))
                .pipe(gulp.dest(paths.dest + "/" + fileData.dest))
                .pipe(gulp.dest('dist/' + fileData.dest))
                .pipe(livereload());

            // Add this to our task list
            tasks.push(currentTask);
        });
    });

    // Return all our tasks so gulp knows when everything's done
    return merge(tasks);
});