elm-pages-v3-beta/examples/docs/functions/screenshot.js

95 lines
3.2 KiB
JavaScript

// thanks to Wes Bos for the initial code template https://github.com/wesbos/wesbos/blob/38e7bf5126758d17c10890832fe58542f6d19861/functions/ogimage/ogimage.js
// https://wesbos.com/new-wesbos-website
const chrome = require("chrome-aws-lambda");
const puppeteer = require("puppeteer-core");
const Airtable = require("airtable");
const base = new Airtable({ apiKey: process.env.AIRTABLE_TOKEN }).base(
"appDykQzbkQJAidjt"
);
// const wait = require('waait');
const cached = new Map();
const exePath = "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome";
async function getOptions(isDev) {
if (isDev) {
return {
product: "chrome",
args: [],
executablePath: exePath,
headless: true,
};
}
return {
product: "chrome",
args: chrome.args,
executablePath: await chrome.executablePath,
headless: chrome.headless,
defaultViewport: chrome.defaultViewport,
};
}
async function getScreenshot(url, isDev) {
console.log({ isDev, url: process.env.URL });
// first check if this value has been cached
const cachedImage = cached.get(url);
if (cachedImage) {
console.log("Found cached image!");
return cachedImage;
}
const options = await getOptions(isDev);
const browser = await puppeteer.launch(options);
const page = await browser.newPage();
// await page.setViewport({ width: 1600, height: 1600, deviceScaleFactor: 1 });
await page.setViewport({ width: 1440, height: 1024 });
// await page.goto(url, { waitUntil: "networkidle0" });
await page.goto(url);
await wait(1000);
const buffer = await page.screenshot({ type: "png" });
const base64Image = buffer.toString("base64");
cached.set(url, base64Image);
return base64Image;
}
// Docs on event and context https://www.netlify.com/docs/functions/#the-handler-method
exports.handler = async (event, context) => {
const recordId = decodeURIComponent(
event.path.replace(/^.*\/screenshot\//, "")
);
const record = await base("elm-pages showcase").find(recordId);
const url = record["fields"]["Screenshot URL"];
console.log({ url });
const photoBuffer = await getScreenshot(
url,
// Here we need to pass a boolean to say if we are on the server. Netlify has a bug where process.env.NETLIFY is undefined in functions so I'm using one of the only vars I can find
// !process.env.NETLIFY
process.env.URL.includes("http://localhost")
);
return {
statusCode: 200,
body: photoBuffer.toString("base64"),
// headers: {'Cache-Control': 'public, max-age=600, s-maxage=604800 stale-while-revalidate=31540000'},
// `stale-while-revalidate=31540000` - we never want to make the user wait to see a screenshot. No matter how stale the cached image is,
// we will go fetch it in the background but we'd prefer for the user to get a stale screenshot than waiting for a long time for images to load for the showcase
// see https://www.youtube.com/watch?v=bfLFHp7Sbkg
headers: {
"Cache-Control":
"public, max-age=600, s-maxage=60 stale-while-revalidate=31540000",
"Content-Length": photoBuffer.length.toString(),
"Content-Type": "image/png",
},
isBase64Encoded: true,
};
};
function wait(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}