Skip to content

Instantly share code, notes, and snippets.

@leereamsnyder
Last active December 13, 2021 14:09
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 leereamsnyder/0fe4555d9bff0ce826533d35cc5085dd to your computer and use it in GitHub Desktop.
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 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