I'm creating a simple, static site where, in development, I'm using Handlebars.js and making some API calls to fill in the Handlebars templates. But for production, I want to precompile all the templates into static HTML.
I'm trying to automate that process with Gulp, so I've got a task that looks like this:
gulp.task('compileHtml', () => {
return gulp
.src('index.html')
.pipe(someThing())
.pipe(anotherThing())
.pipe(compileTemplates())
.pipe(someOtherThing())
.pipe(gulp.dest('build'));
});
In my compileTemplates
function, I'm using gulp-tap and jsdom to basically run the file with relevant scripts to make the API calls and fill in the Handlebars templates, then remove those scripts and send back the compiled HTML to the next pipe. But I'm having trouble deferring sending back the new DOM until jsdom
has had ample time to run all the scripts.
Here's what I have so far:
const compileTemplates = file => {
return tap(file => {
const dom = new JSDOM(file.contents,
{
runScripts: 'dangerously',
resources: 'usable',
beforeParse(window) {
window.fetch = require('node-fetch');
},
},
);
const document = dom.window.document;
const script = document.querySelector('script[src$="handlebars.min.js"]');
// dom.serialize() still contains my uncompiled templates at this point
setTimeout(() => {
script.remove();
file.contents = Buffer.from(dom.serialize()); // this is what I want to return from this function
}, 2500);
});
};
I know I probably need to use a promise to send back file.contents
when it's ready, but I'm not great with promises or with Gulp.
I've tried returning a promise that resolves inside the timeout, but I end up with TypeError: dest.on is not a function
because the next pipe is ultimately expecting file
and not a promise.
How could I refactor to either defer sending back my manipulated file
to the next pipe or to send back a promise from this function and then resolve that promise to the new file
in my compileHtml
task?
I'm using Gulp 4.