If all you want is to generate a .json structure and add it to a file with Gulp, you can do this in one of several ways. The first two use pure Gulp techniques:
You can write a stream plugin using
through
orthrough2
, which will basically have to build up the data structure one file at a time, then in a second operation, will create (i.e.push()
orqueue()
) a file at the endYou can use a Highland pipeline to
.reduce()
the files to a data structure, then.map()
the result to a file, maybe doing a.merge()
with the original stream
In both cases, you'll need your generated new vinyl
file to have an appropriate .base
and .path
, which your plugin won't actually know, due to the file you're creating not existing yet. Thus, your code will have to make up a phony absolute path so that gulp.dest()
will put it in the right place.
The third technique is to write a Metalsmith plugin instead, which will look something like this:
function generate_json(files, smith, done) {
var menu = {};
Object.keys(files).forEach(function(path) {
var file = files[path];
if (path.slice(-5)===".html") {
menu[path] = ... // whatever you want to store about `file`
}
});
files["path/to/menu.json"] = { contents: new Buffer(JSON.stringify(menu)) };
done();
}
While not much shorter than the code required for the other methods, you will need to understand a lot less in order to do it correctly. Just make sure that if you have an error, you call done(err)
in order to pass the error on.
If you would like to combine this plugin with a Gulp pipeline, you can wrap it like so, using Gulpsmith:
gulp.src(...)
.pipe( things() )
.pipe( gulpsmith().use(generate_json) )
.pipe( other_stuff() )
.pipe( gulp.dest(...);
It's true that Gulp has certain advantages over Metalsmith. Ease of writing plugins, sadly, is not one of them. Creating new files from a Gulp plugin is harder than it should be, as is correct error handling. There's also a strong impedance mismatch between the streaming approach, and the nature of static sites to need cross-file operations.
For example, if you wanted to embed your menu in every .html page after creating it, you would need a more complex Gulp plugin, because by the time your plugin had "seen" all the files, they would have "gone downstream", or else you'd have to hang on to them, then stream them out again after you were done. In the Metalsmith plugin, you'd just add a second loop after you generated the menu, to go back over the files again to insert the data, in-place. You don't have to do anything to pass along the files you're not doing anything to.
For these kind of tasks, the Metalsmith plugin API is unequivocally superior to Gulp's. But for tasks that can work on streamed files alone, use existing Gulp plugins for the win.
Basically, Metalsmith is really the Gulp of static site generators, while Gulp is the Gulp of streaming build systems. And you can combine the strengths of both, using Gulpsmith.
(By the way, depending on your actual task, you may find some existing Metalsmith plugins that do all or part of it. For example the metalsmith-collections
plugin creates indexes for files matching certain patterns, there's a metalsmith-title
that extracts an HTML header to a title property, etc.)