UNPKG

fastify-prerender-plugin

Version:
107 lines (102 loc) 3.1 kB
'use strict'; var Fs = require('node:fs'); var Path = require('node:path'); var fastifyPlugin = require('fastify-plugin'); var isbot = require('isbot'); var sanitize = require('sanitize-filename'); var tmp = require('tmp'); var test = require('@playwright/test'); async function requestFromBrowser(url) { const browser = await test.chromium.launch({ args: [ "--disable-dev-shm-usage", "--no-sandbox", "--disable-setuid-sandbox", "--disable-background-timer-throttling", "--disable-backgrounding-occluded-windows", "--disable-renderer-backgrounding", "--disable-extensions", "--disable-sync", "--disable-translate", "--single-process", // Run in a single process "--no-zygote", // Disable the zygote process for reduced memory usage "--disable-gpu" // Disable GPU hardware acceleration ], headless: true }); const page = await browser.newPage({ userAgent: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" }); await page.goto(url); let html; try { html = await page.content(); } catch (error) { console.error(error); return ""; } await browser.close(); return html; } const prerenderPlugin = fastifyPlugin.fastifyPlugin( (app, options, done) => { const tmpobj = tmp.dirSync(); app.addHook("onRequest", async (request, reply) => { const requestFromBot = isbot.isbot(request.headers["user-agent"]); if (!requestFromBot || request.method !== "GET") { return; } request.log.info({ requestFromBot }); let matches = false; for (const url2 of options.urls) { if (typeof url2 === "string") { if (url2 === request.url) { matches = true; break; } } else { if (url2.test(request.url)) { matches = true; break; } } } if (!matches) { return; } const url = `http://${options.host}:${options.port}${request.url}`; const filepath = Path.join( options.tmpPath ?? tmpobj.name, sanitize(`${url}.html`) ); if (Fs.existsSync(filepath)) { const fileStat = Fs.statSync(filepath); const fileAgeInMinutes = (Date.now() - fileStat.mtime.getTime()) / 1e3 / 60; if (fileAgeInMinutes <= 5) { return reply.status(200).type("text/html").send(Fs.readFileSync(filepath)); } Fs.rmSync(filepath); } request.log.info(`request-from-browser: ${url}`); const html = await requestFromBrowser(url).catch((error) => { console.error(error); }) ?? ""; try { Fs.writeFileSync(filepath, html); } catch (error) { request.log.error(`Couldn't write cache in ${filepath}`); } reply.status(200).type("text/html").send(html); }); done(); }, { fastify: "^5.x", name: "fastify-prerender" } ); exports.prerenderPlugin = prerenderPlugin; exports.requestFromBrowser = requestFromBrowser;