|
/* Mostly taken from |
|
https://andrewingram.net/posts/automatic-social-cards-with-gatsby/ */ |
|
|
|
const { writeFile } = require("fs") |
|
const { resolve } = require("path") |
|
const { createHash } = require("crypto") |
|
const { promisify } = require("util") |
|
const React = require("react") |
|
const ReactDOMServer = require("react-dom/server") |
|
const writeFileAsync = promisify(writeFile) |
|
|
|
/** |
|
* Writes a file to the cache location |
|
*/ |
|
async function writeCachedFile(CACHE_DIR, key, contents, extension) { |
|
// I'm using the title as the key for the hash, because it's the only |
|
// thing which impacts the final image. If you were to have something |
|
// more elaborate, you should just use the HTML as the hash instead. |
|
const fileName = createHash("md5").update(key).digest("hex") + "." + extension |
|
const absolutePath = resolve(CACHE_DIR, fileName) |
|
await writeFileAsync(absolutePath, contents) |
|
return absolutePath |
|
} |
|
|
|
/* |
|
* Returns the path to an image generated from the provided HTML. |
|
*/ |
|
async function imageFromHtml(CACHE_DIR, browser, title, html) { |
|
// Write the HTML to a file and get its filename |
|
const filePath = await writeCachedFile(CACHE_DIR, title, html, "html") |
|
const page = await browser.newPage() |
|
// Navigate to our saved HTML |
|
await page.goto(`file://${filePath}`) |
|
// My HTML includes webfonts, so make sure they're ready |
|
await page.evaluateHandle("document.fonts.ready") |
|
// Set the viewport to the desired dimensions of the image |
|
await page.setViewport({ width: 1200, height: 630 }) |
|
// Take a screenshot, we use PNG because it's higher quality - and the |
|
// compression works well for images which contain a lot of areas of |
|
// solid colour. |
|
const file = await page.screenshot({ type: "png" }) |
|
// Write the screenshot to a file, and return its filename |
|
return writeCachedFile(CACHE_DIR, title, file, "png") |
|
} |
|
|
|
exports.default = async function postToImage( |
|
CACHE_DIR, |
|
browser, |
|
title, |
|
componentPath, |
|
props |
|
) { |
|
const UserComponent = require(componentPath).default |
|
const element = React.createElement(UserComponent, props) |
|
const html = ReactDOMServer.renderToStaticMarkup(element) |
|
return imageFromHtml(CACHE_DIR, browser, title, html) |
|
} |