diff --git a/src/runtime/browserService.ts b/src/browserService.ts similarity index 96% rename from src/runtime/browserService.ts rename to src/browserService.ts index ea31ebe8..e99dea3c 100644 --- a/src/runtime/browserService.ts +++ b/src/browserService.ts @@ -1,6 +1,5 @@ import type { Browser } from 'playwright' -import type { ScreenshotOptions } from '../types' - +import type { ScreenshotOptions } from './types' async function createLambdaBrowser() { try { diff --git a/src/module.ts b/src/module.ts index f699d936..2ae5012a 100644 --- a/src/module.ts +++ b/src/module.ts @@ -8,8 +8,9 @@ import defu from 'defu' import { createRouter as createRadixRouter, toRouteMatcher } from 'radix3' import { withBase } from 'ufo' import fg from 'fast-glob' -import { createBrowser, screenshot } from './runtime/browserService' +import { createBrowser, screenshot } from './browserService' import type { OgImageRouteEntry, ScreenshotOptions } from './types' +import { getNuxtVersion } from '@nuxt/kit' export interface ModuleOptions extends ScreenshotOptions { defaultIslandComponent: string @@ -77,14 +78,17 @@ declare module 'nitropack' { references.push({ path: resolve(nuxt.options.buildDir, 'nuxt-og-image.d.ts') }) }) - // give a warning when accessing sitemap in dev mode - addServerHandler({ - handler: resolve('./runtime/nitro/html'), - }) - if (config.runtimeImages) { + // we need edge version or 3.0.1 to use Nuxt Island + if (getNuxtVersion(nuxt) !== '3.0.0') { + // give a warning when accessing sitemap in dev mode addServerHandler({ - handler: resolve('./runtime/nitro/image'), + handler: resolve('./runtime/nitro/html'), }) + if (config.runtimeImages) { + addServerHandler({ + handler: resolve('./runtime/nitro/image'), + }) + } } addImports({ name: 'defineOgImage', diff --git a/src/runtime/nitro/image.ts b/src/runtime/nitro/image.ts index 0a1e5f74..41abed3c 100644 --- a/src/runtime/nitro/image.ts +++ b/src/runtime/nitro/image.ts @@ -1,9 +1,60 @@ import { defineEventHandler, getRequestHeader, setHeader } from 'h3' -import { createBrowser, screenshot } from '../browserService' +import type { Browser } from 'playwright' +import type { ScreenshotOptions } from '../../types' export const HtmlRendererRoute = '__og_image' export const RuntimeImageSuffix = 'og-image.png' +async function createLambdaBrowser() { + try { + const playwright = await import('playwright-core') + const awsChrome = await import('chrome-aws-lambda') + return await playwright.chromium.launch({ + args: awsChrome.args, + executablePath: await awsChrome.executablePath, + headless: awsChrome.headless, + }) + } + catch (e) {} + return false +} +export async function createBrowser() { + const lambdaBrowser = await createLambdaBrowser() + if (lambdaBrowser) + return lambdaBrowser + // fallback to core playwright + const playwright = await import('playwright') + return await playwright.chromium.launch({ + chromiumSandbox: true, + }) +} + +export async function screenshot(browser: Browser, url: string, options: ScreenshotOptions): Promise { + const page = await browser.newPage({ + colorScheme: options.colorScheme, + }) + await page.setViewportSize({ + width: options.width, + height: options.height, + }) + + await page.goto(url, { + timeout: 10000, + waitUntil: 'networkidle', + }) + + if (options.mask) { + await page.evaluate((mask) => { + for (const el of document.querySelectorAll(mask) as any as HTMLElement[]) + el.style.display = 'none' + }, options.mask) + } + if (options.selector) + await page.locator(options.selector).screenshot() + + return await page.screenshot() +} + export default defineEventHandler(async (e) => { if (!e.path?.endsWith(RuntimeImageSuffix)) return