Skip to content

Instantly share code, notes, and snippets.

@charisTheo
Created April 23, 2024 10:35
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 charisTheo/3c0a20804b1898c2ee67be8488842113 to your computer and use it in GitHub Desktop.
Save charisTheo/3c0a20804b1898c2ee67be8488842113 to your computer and use it in GitHub Desktop.
npm init -y && npm i puppeteer && node prerender-skyscanner.js
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch({
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
headless: false,
args: [
'--window-size=1818,1328',
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-dev-shm-usage",
"--disable-accelerated-2d-canvas",
"--no-first-run",
"--no-zygote",
"--disable-gpu",
'--deterministic-fetch',
'--disable-features=IsolateOrigins',
'--disable-site-isolation-trials',
],
defaultViewport: {
width: 1818,
height: 1328,
deviceScaleFactor: 1,
isMobile: false,
hasTouch: false,
isLandscape: false
}
})
const page = await browser.newPage()
const TEST_PRERENDER = false
async function delay(milliseconds) {
return await new Promise(res => setTimeout(() => res(true), milliseconds))
}
await Promise.all([
page.goto('https://www.skyscanner.net/flights'),
page.waitForNavigation()
])
await page.click('#acceptCookieButton')
const clickOnFirstLinkCard = async (page) => {
await page.exposeFunction('delay', delay);
return await page.evaluate(async (TEST_PRERENDER) => {
const linkCard = document.querySelector('[data-testid="deal-grid-layout"] a')
if (TEST_PRERENDER) {
const prerenderScript = document.createElement('script')
prerenderScript.type = 'speculationrules'
prerenderScript.innerHTML = `{
"prerender": [
{
"urls": ["${linkCard.href}"],
"eagerness": "eager"
}
]
}`
document.body.appendChild(prerenderScript)
}
// add a red circle in the page to mark start of recording and remove after the delay
const redDotEl = document.createElement('div')
redDotEl.style.cssText += 'width:30px;height:30px;position:fixed;left:10px;top:10px;z-index:10;background:red;border-radius:50%;'
document.body.appendChild(redDotEl)
await delay(2000)
redDotEl.remove()
await delay(500)
document.getElementsByTagName('html')[0].style.scrollBehavior = 'smooth'
linkCard.scrollIntoView()
await delay(1000)
linkCard.click()
}, TEST_PRERENDER)
}
await Promise.all([
clickOnFirstLinkCard(page),
page.waitForNavigation(),
])
const LCP = await page.evaluate(() => {
return new Promise(resolve => {
const getActivationStart = () => {
const navEntry = window.performance &&
performance.getEntriesByType &&
performance.getEntriesByType('navigation')[0]
return (navEntry && navEntry.activationStart) || 0;
};
new PerformanceObserver((entryList) => {
const entries = entryList.getEntries()
const lastEntry = entries[entries.length - 1]
resolve(
lastEntry
? Math.max(lastEntry.startTime - getActivationStart(), 0)
: null
)
}).observe({ type: 'largest-contentful-paint', buffered: true })
})
})
// https://developer.chrome.com/docs/web-platform/prerender-pages#detecting_prerender_in_javascript
const prerendered = await page.evaluate(() => {
return (
document.prerendering ||
self.performance?.getEntriesByType?.('navigation')[0]?.activationStart > 0
)
})
console.log('Prerendered:', prerendered)
console.log('LCP:', LCP)
await delay(2000)
await browser.close()
process.exit(0)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment