og-images-generator
Version:
Generate OG images from a static folder and / or a middleware. Extract metadata from HTML pages. No headless browser involved. Comes as a CLI, API or plugins.
66 lines (65 loc) • 3.04 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import c from 'picocolors';
import { collectHtmlPages } from './collect.js';
import { renderAllPagesOg } from './render.js';
export const CONFIG_FILE_NAME = 'og-images.config.js';
export const CONFIG_FILE_PATH = path.join(process.cwd(), CONFIG_FILE_NAME);
export async function loadUserConfig(configPath) {
// eslint-disable-next-line no-console
console.log(CONFIG_FILE_PATH);
const config = await import(configPath || CONFIG_FILE_PATH).catch((error) => {
// eslint-disable-next-line no-console
console.error(error);
throw new Error('Configuration not found.');
});
if (typeof config !== 'object' || !config)
throw new Error('Configuration is invalid.');
if (!('template' in config))
throw new Error('No template found in configuration.');
if (typeof config.template !== 'function')
throw new Error('Template should be a returning function.');
if (!('renderOptions' in config) || !config.renderOptions)
throw new Error('No render options found in configuration.');
if (typeof config.renderOptions !== 'object')
throw new Error('Return options should be an object.');
if (!('satori' in config.renderOptions))
throw new Error('Satori options are mandatory.');
// We assume the user has their config. properly typed from there,
// further libs will throw in case of an invalid config.
const resvg = ('resvg' in config.renderOptions ? config.renderOptions.resvg : {});
const satori = config.renderOptions.satori;
return {
template: config.template,
renderOptions: { satori, resvg },
};
}
export async function save(renderedImages, out) {
await Promise.all(renderedImages.map(async (rendered) => {
const fileDestination = rendered.path.replace(/\/index\.html$/, '').replace(/\.html$/, '') +
'.png';
const destination = path.join(process.cwd(), out, fileDestination);
await fs.promises
.mkdir(path.dirname(destination), { recursive: true })
.catch(() => null);
await fs.promises.writeFile(destination, rendered.data);
}));
// eslint-disable-next-line no-console
console.log(c.bold(c.green(renderedImages.length + ' images generated.')));
}
export async function generateOgImages(options) {
const optionsOrDefaults = {
base: options?.base || './dist',
out: options?.out || './dist/og',
json: options?.json || './dist/og/index.json',
additionalPatterns: options?.additionalPatterns || [],
globber: options?.globber || {},
};
const pages = await collectHtmlPages(optionsOrDefaults);
const config = await loadUserConfig();
const renderedImages = await renderAllPagesOg(pages, config);
await save(renderedImages, optionsOrDefaults.out);
// eslint-disable-next-line no-console
console.log(c.magenta('OG images generation completed successfully. ') +
c.blue('Now exiting.'));
}