Skip to content

Commit

Permalink
fix: improve prerendering error debugging (#281)
Browse files Browse the repository at this point in the history
  • Loading branch information
harlan-zw authored Nov 24, 2024
1 parent 001c345 commit 2f338b9
Showing 1 changed file with 54 additions and 29 deletions.
83 changes: 54 additions & 29 deletions src/runtime/server/og-image/context.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { H3Error, H3Event } from 'h3'
import type { FetchResponse, FetchOptions } from 'ofetch'
import type {
OgImageOptions,
OgImageRenderEventContext,
Expand All @@ -19,6 +20,7 @@ import { decodeObjectHtmlEntities } from '../util/encoding'
import { createNitroRouteRuleMatcher } from '../util/kit'
import { normaliseOptions } from '../util/options'
import { useChromiumRenderer, useSatoriRenderer } from './instances'
import {logger} from "#og-image/server/util/logger";

export function resolvePathCacheKey(e: H3Event, path?: string) {
const siteConfig = e.context.siteConfig.get()
Expand Down Expand Up @@ -64,9 +66,9 @@ export async function resolveContext(e: H3Event): Promise<H3Error | OgImageRende
const key = resolvePathCacheKey(e, basePath)
let options: OgImageOptions | null | undefined = queryParams.options as OgImageOptions
if (!options) {
if (import.meta.prerender)
options = await prerenderOptionsCache?.getItem(key)

if (import.meta.prerender) {
options = await prerenderOptionsCache!.getItem(key)
}
if (!options) {
const payload = await fetchPathHtmlAndExtractOptions(e, basePath, key)
if (payload instanceof Error)
Expand Down Expand Up @@ -189,6 +191,24 @@ export function extractAndNormaliseOgImageOptions(html: string): OgImageOptions
return payload
}

function handleNon200Response(res: FetchResponse<string>, path: string) {
let errorDescription
// if its a redirect let's get the redirect path
if (res.status >= 300 && res.status < 400) {
errorDescription = `${res.status} redirected to ${res.headers.get('location') || 'unknown'}`
}
else if (res.status >= 400) {
// try get the error message from the response
errorDescription = `${res.status} error: ${res.statusText}`
}
if (errorDescription) {
return createError({
statusCode: 500,
statusMessage: `[Nuxt OG Image] Failed to parse \`${path}\` for og-image extraction. ${errorDescription}`,
})
}
}

// TODO caching
async function fetchPathHtmlAndExtractOptions(e: H3Event, path: string, key: string): Promise<H3Error | OgImageOptions> {
const cachedHtmlPayload = await htmlPayloadCache.getItem(key)
Expand All @@ -198,41 +218,46 @@ async function fetchPathHtmlAndExtractOptions(e: H3Event, path: string, key: str
// extract the payload from the original path
let _payload: string | null = null
let html: string
try {
html = await e.$fetch(path, {
// follow redirects
redirect: 'follow',
headers: {
accept: 'text/html',
},
})
_payload = getPayloadFromHtml(html)
// fallback to globalThis.fetch
if (!_payload) {
const fallbackHtml = await globalThis.$fetch(path, {
// follow redirects
redirect: 'follow',
headers: {
accept: 'text/html',
},
})
_payload = getPayloadFromHtml(fallbackHtml)
if (_payload) {
html = fallbackHtml
}
const fetchOptions: FetchOptions = {
// follow redirects
redirect: 'follow',
ignoreResponseError: true,
headers: {
accept: 'text/html',
},
} as const
const htmlRes = await e.fetch(path, fetchOptions)
const err = handleNon200Response(htmlRes, path)
if (err) {
logger.warn(err)
}
html = await htmlRes.text()
_payload = getPayloadFromHtml(html)
// fallback to globalThis.fetch
if (!_payload) {
const fallbackHtmlRes = await globalThis.$fetch.raw(path, fetchOptions)
const err = handleNon200Response(fallbackHtmlRes, path)
if (err) {
return err
}
const fallbackHtml = await fallbackHtmlRes.text()
_payload = getPayloadFromHtml(fallbackHtml)
if (_payload) {
html = fallbackHtml
}
}
catch (err) {

if (!html) {
return createError({
statusCode: 500,
statusMessage: `[Nuxt OG Image] Failed to read the path ${path} for og-image extraction. ${err.message}.`,
statusMessage: `[Nuxt OG Image] Failed to read the path ${path} for og-image extraction, returning no HTML.`,
})
}

if (!_payload || !html) {
if (!_payload) {
return createError({
statusCode: 500,
statusMessage: `[Nuxt OG Image] Got invalid response from ${path} for og-image extraction.`,
statusMessage: `[Nuxt OG Image] HTML response from ${path} is missing the #nuxt-og-image-options script tag. Check you have used defined an og image for this page.`,
})
}

Expand Down

0 comments on commit 2f338b9

Please sign in to comment.