Skip to content

Instantly share code, notes, and snippets.

@nmoutschen
Last active August 16, 2020 17:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nmoutschen/fb06d5abead872eead4b63262960b9b5 to your computer and use it in GitHub Desktop.
Save nmoutschen/fb06d5abead872eead4b63262960b9b5 to your computer and use it in GitHub Desktop.
Generate social media images based on a series of Markdown documents with front matter.
// Some imports
const fs = require('fs');
const matter = require('gray-matter');
const nodeHtmlToImage = require('node-html-to-image');
const path = require('path');
// Defining some constants, such as the content folder, image folder, etc.
const articlesDir = path.join(process.cwd(), 'content/articles');
const imagesDir = path.join(process.cwd(), 'assets/imgs/social');
const articleExt = '.md';
const imageExt = '.png';
// Customize this part
// I recommend setting the body size to 1200 x 628 px.
const htmlTemplate: `<html><head>
<style>
body {
position: relative;
width: 1200px;
height: 628px;
}
</style>
</head>
<body>
<h1>{{ title }}</h1>
{{#if tags}}
<ul id="tags">
{{#each tags}}
<li class="tag">#{{this}}</li>
{{/each}}
</ul>
{{/if}}
</body></html>`;
// Find all articles
function walk(dir: string): string[] {
const files: string[] = [];
fs.readdirSync(dir).forEach((file: string) => {
const filePath = path.join(dir, file);
const stats = fs.statSync(filePath);
if (stats.isDirectory()) {
files.push(...walk(filePath));
} else if (stats.isFile()) {
files.push(filePath);
}
});
return files;
}
// Retrieve the front matter from an article
function getFrontMatter(filePath: string): Record<string, any> {
return matter(fs.readFileSync(filePath)).data;
}
// Return the complete image path from an article path
// E.g. 'content/articles/2020/hello-world.md' will return
// 'assets/imgs/social/2020/hello-world.png'.
function getImagePath(
origDir: string, destDir: string,
origExt: string, destExt: string,
filePath: string,
): string {
return filePath
.replace(origDir, destDir)
.replace(origExt, destExt);
}
// Generate an image from metadata
function genImage(imageData: Array<Record<string, any>>) {
nodeHtmlToImage({
html: htmlTemplate,
// In this case, this contains an array with information from all the
// articles
content: imageData,
// This is needed to run the script in AWS Amplify Console
puppeteerArgs: ['--no-sandbox'],
});
}
// Let's put everything together
const files = walk(articlesDir);
const fileData = files.map((filePath: string) => {
const data = getFrontMatter(filePath);
data.output = getImagePath(articlesDir, imagesDir, articleExt, imageExt, filePath);
return data;
});
genImage(fileData);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment