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.