UNPKG

nuxt-og-image

Version:

Enlightened OG Image generation for Nuxt.

90 lines (89 loc) 3.71 kB
import { useRequestEvent, withSiteUrl } from "#imports"; import { TemplateParamsPlugin } from "@unhead/vue/plugins"; import { defu } from "defu"; import { parse, stringify } from "devalue"; import { createRouter as createRadixRouter, toRouteMatcher } from "radix3"; import { parseURL, withoutBase } from "ufo"; import { toValue } from "vue"; import { createOgImageMeta } from "../../app/utils.js"; import { isInternalRoute, separateProps } from "../../pure.js"; import { getOgImagePath } from "../../shared.js"; export function ogImageCanonicalUrls(nuxtApp) { nuxtApp.hooks.hook("app:rendered", async (ctx) => { const { ssrContext } = ctx; const e = useRequestEvent(); const path = parseURL(e.path).pathname; if (isInternalRoute(path)) return; ssrContext?.head.use(TemplateParamsPlugin); ssrContext?.head.use({ key: "nuxt-og-image:overrides-and-canonical-urls", hooks: { "tags:resolve": async (ctx2) => { const hasPrimaryPayload = ctx2.tags.some((tag) => tag.tag === "script" && tag.props.id === "nuxt-og-image-options"); let overrides; for (const tag of ctx2.tags) { if (tag.tag === "script" && tag.props.id === "nuxt-og-image-overrides") { if (hasPrimaryPayload) { overrides = separateProps(parse(tag.innerHTML || "{}")); delete ctx2.tags[ctx2.tags.indexOf(tag)]; } else { tag.props.id = "nuxt-og-image-options"; tag.innerHTML = stringify(separateProps(parse(tag.innerHTML || "{}"))); tag._d = "script:id:nuxt-og-image-options"; } break; } } ctx2.tags = ctx2.tags.filter(Boolean); for (const tag of ctx2.tags) { if (tag.tag === "meta" && (tag.props.property === "og:image" || ["twitter:image:src", "twitter:image"].includes(tag.props.name))) { if (!tag.props.content) { tag.props = {}; continue; } if (!tag.props.content?.startsWith("https")) { await nuxtApp.runWithContext(() => { tag.props.content = toValue(withSiteUrl(tag.props.content, { withBase: true })); }); } } else if (overrides && tag.tag === "script" && tag.props.id === "nuxt-og-image-options") { tag.innerHTML = stringify(defu(overrides, parse(tag.innerHTML))); } } } } }); }); } export function routeRuleOgImage(nuxtApp) { nuxtApp.hooks.hook("app:rendered", async (ctx) => { const { ssrContext } = ctx; const e = useRequestEvent(); const path = parseURL(e.path).pathname; if (isInternalRoute(path)) return; const _routeRulesMatcher = toRouteMatcher( createRadixRouter({ routes: ssrContext?.runtimeConfig?.nitro?.routeRules }) ); let routeRules = defu({}, ..._routeRulesMatcher.matchAll( withoutBase(path.split("?")[0], ssrContext?.runtimeConfig?.app.baseURL) ).reverse()).ogImage; if (typeof routeRules === "undefined") return; const ogImageInstances = nuxtApp.ssrContext._ogImageInstances || []; if (routeRules === false) { ogImageInstances?.forEach((e2) => { e2.dispose(); }); nuxtApp.ssrContext._ogImagePayload = void 0; nuxtApp.ssrContext._ogImageInstances = void 0; return; } routeRules = defu(nuxtApp.ssrContext?.event.context._nitro?.routeRules?.ogImage, routeRules); const src = getOgImagePath(ssrContext.url, routeRules); createOgImageMeta(src, routeRules, nuxtApp.ssrContext); }); }