A little bit of a self-plug here but I just recently did the same thing with a project called kb-hologram.
It basically takes handlebar templates (either SVG or HTML), and renders that to either an SVG or png.
Basically, after having a ready HTML file, I load the HTML into a puppeteer instance (which actually runs a headless chrome browser), take a snapshot of the rendered HTML, and saves it.
it can generate things like a test report image (obviously fake numbers), or a changelog image similar to what vscode publishes in their tweets:

HTML
Here's the gist of it:
// handles rendering the HTML templates
// https://github.com/puppeteer/puppeteer
import puppeteer from 'puppeteer';
import { writeFile } from 'fs-extra';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({
height: this.options.height,
width: this.options.width
});
// If your HTML is saved to a file, you load it like this:
await page.goto('file://' + this.templateFilePath);
// if your HTML is in memory (as a string), you load it like this:
// page.setContent(htmlString);
const imageBuffer = await page.screenshot({});
await browser.close();
// write file to disk as buffer
await writeFile('rendered.png', imageBuffer);
// convert to base64 string if you want to:
console.log(imageBuffer.toString('base64'));
})();
SVG
Generating an SVG is much simpler since it's basically a text file:
import { compile } from 'handlebars';
(async (data) => {
// generate the svg template as string
const template = await this.getTemplateAsString();
// make it a handlebars template
const handlebarsTemplate = compile(template);
// load the data into the template
// this is basically the content of the SVG file
const svgString = handlebarsTemplate(data);
// from here on, it's basically the same thing :-)
const svgBuffer = Buffer.from(svgString, 'utf8');
})(data);
Headless browser
To me, handling things like external resources is easier on a real browser if you want to load fonts and styles from CDNs.
There are solutions out there to take a screenshot from jsdom directly if you don't want to introduce another "browser" module into the mix.
Also, take note that this will download an instance of chrome as a dependency
kb-hologram
The project is still in early stages. Feel free to contribute to kb-hologram, fork the code, or write your own using the example. I personally use it on Travis CI to publish tweets and images as PR comments on GitHub.