Last active
December 13, 2021 14:09
-
-
Save leereamsnyder/0fe4555d9bff0ce826533d35cc5085dd to your computer and use it in GitHub Desktop.
Netlify on-demand builder for taking a screen capture with puppeteer v10
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
this is the Netlify on-demand builder described here: | |
https://www.leereamsnyder.com/blog/dynamic-social-media-images-with-puppeteer-and-netlify | |
but updated to work with puppeteer 10 | |
See that article for setup on netlify, including redirects and meta tags | |
The builder code in linked article was written for puppeteer 8 | |
and things didn't work after I updated to version 10 | |
The big changes: | |
- require('puppeteer-core') directly to make sure it's bundled when the function builds | |
- invoke puppeteer.launch() instead of chromium.puppeteeer.launch() | |
- add a hard-coded path to a local Chrome install for local development. Yours might be different! | |
*/ | |
const { builder } = require('@netlify/functions') | |
const chromium = require('chrome-aws-lambda') | |
const puppeteer = require('puppeteer-core') | |
// https://blog.hootsuite.com/social-media-image-sizes-guide/#Quick_social_media_image_sizes | |
const captureWidth = 1200 | |
const captureHeight = 630 | |
const clipY = 60 | |
async function handler (event, context) { | |
console.log('enter og-image generator', event) | |
const path = event.path | |
.replace('/og-image-generator', '') | |
.replace('/og-image.jpg', '') | |
const url = `${process.env.URL}${path}` | |
const browser = await puppeteer.launch({ | |
// with `netlify dev`, the AWS_LAMBDA_FUNCTION_NAME env var exists ("handler") | |
// so chromium will calculate, wrongly, that we're running on AWS (that's chromium.headless) | |
// so we get an executablePath for linux chromium, which won't work for dev/local work | |
// so I'm checking the URL env for "localhost" | |
// and using a hard-coded executable path | |
// you can get this in Chrome itself @ chrome://version/ | |
// (hat-tip: https://spacejelly.dev/posts/how-to-use-puppeteer-to-automate-chrome-in-an-api-with-netlify-serverless-functions/) | |
executablePath: process.env.URL.includes('localhost') | |
? '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome' | |
: await chromium.executablePath, | |
args: chromium.args, | |
defaultViewport: { | |
width: 1200, | |
height: captureHeight + clipY | |
}, | |
headless: chromium.headless | |
}) | |
const page = await browser.newPage() | |
await page.emulateMediaFeatures([ | |
// no need for any animations to be going | |
{ name: 'prefers-reduced-motion', value: 'reduce' } | |
]) | |
await page.goto(url) | |
const screenshot = await page.screenshot({ | |
type: 'jpeg', | |
// netlify functions can only return strings, so base64 it is | |
encoding: 'base64', | |
quality: 70, | |
clip: { | |
x: 0, | |
y: clipY, | |
width: captureWidth, | |
height: captureHeight | |
} | |
}) | |
await browser.close() | |
return { | |
statusCode: 200, | |
headers: { | |
'Content-Type': 'image/jpg' | |
}, | |
body: screenshot, | |
isBase64Encoded: true | |
} | |
} | |
exports.handler = builder(handler) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment