nuxt-og-image 3.0.0-beta.8 → 3.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/client/200.html +6 -5
- package/dist/client/404.html +6 -5
- package/dist/client/_nuxt/IconCSS.9f95294e.js +1 -0
- package/dist/client/_nuxt/IconCSS.f0b56d3e.css +1 -0
- package/dist/client/_nuxt/builds/latest.json +1 -1
- package/dist/client/_nuxt/builds/meta/01a72661-4cae-4637-8364-242cd0ee1a35.json +1 -0
- package/dist/client/_nuxt/entry.a30f63d0.css +1 -0
- package/dist/client/_nuxt/entry.c5e613a6.js +108 -0
- package/dist/client/_nuxt/{error-404.66c6f07b.js → error-404.e1564a51.js} +1 -1
- package/dist/client/_nuxt/{error-500.fed3c621.js → error-500.90b12af8.js} +1 -1
- package/dist/client/_nuxt/vanilla-picker-NKbIFE8h.23409a58.js +8 -0
- package/dist/client/index.html +6 -5
- package/dist/module.d.mts +63 -48
- package/dist/module.d.ts +63 -48
- package/dist/module.json +2 -2
- package/dist/module.mjs +343 -164
- package/dist/runtime/cache.d.ts +7 -10
- package/dist/runtime/cache.mjs +40 -27
- package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
- package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
- package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
- package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
- package/dist/runtime/components/Templates/{Official → Community}/BrandedLogo.vue +3 -2
- package/dist/runtime/components/Templates/Community/Nuxt.vue +6 -5
- package/dist/runtime/components/Templates/Community/NuxtSeo.vue +137 -0
- package/dist/runtime/components/Templates/Community/Pergel.vue +104 -0
- package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
- package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
- package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
- package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
- package/dist/runtime/composables/defineOgImage.d.ts +2 -23
- package/dist/runtime/composables/defineOgImage.mjs +33 -117
- package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
- package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
- package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
- package/dist/runtime/composables/defineOgImageScreenshot.mjs +13 -0
- package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
- package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
- package/dist/runtime/core/bindings/resvg/wasm-fs.d.ts +40 -0
- package/dist/runtime/core/bindings/resvg/wasm-fs.mjs +6 -0
- package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -5
- package/dist/runtime/core/bindings/satori/wasm-fs.mjs +13 -0
- package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
- package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
- package/dist/runtime/core/cache/emojis.d.ts +1 -0
- package/dist/runtime/core/cache/emojis.mjs +5 -0
- package/dist/runtime/core/cache/fonts.d.ts +3 -0
- package/dist/runtime/core/cache/fonts.mjs +6 -0
- package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
- package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
- package/dist/runtime/core/cache/prerender.d.ts +1 -5
- package/dist/runtime/core/cache/prerender.mjs +1 -2
- package/dist/runtime/core/env/assets.d.ts +0 -1
- package/dist/runtime/core/env/assets.mjs +0 -4
- package/dist/runtime/core/font/fetch.d.ts +2 -3
- package/dist/runtime/core/font/fetch.mjs +26 -19
- package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
- package/dist/runtime/core/html/applyEmojis.mjs +37 -0
- package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
- package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
- package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
- package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
- package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
- package/dist/runtime/core/html/fetchIsland.mjs +17 -0
- package/dist/runtime/core/options/fetch.d.ts +1 -1
- package/dist/runtime/core/options/fetch.mjs +10 -5
- package/dist/runtime/core/renderers/chromium/index.mjs +12 -15
- package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
- package/dist/runtime/core/renderers/chromium/screenshot.mjs +20 -15
- package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
- package/dist/runtime/core/renderers/satori/index.mjs +51 -25
- package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
- package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
- package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
- package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +60 -30
- package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
- package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +45 -0
- package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
- package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
- package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
- package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
- package/dist/runtime/core/utils/resolveRendererContext.mjs +47 -29
- package/dist/runtime/core/utils/wasm.d.ts +3 -0
- package/dist/runtime/core/utils/wasm.mjs +16 -0
- package/dist/runtime/nitro/plugins/nuxt-content.mjs +7 -6
- package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
- package/dist/runtime/nitro/plugins/prerender.mjs +20 -18
- package/dist/runtime/nitro/utils.d.ts +2 -0
- package/dist/runtime/nitro/utils.mjs +17 -0
- package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +43 -0
- package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -51
- package/dist/runtime/nuxt/utils.d.ts +3 -0
- package/dist/runtime/nuxt/utils.mjs +69 -0
- package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +2 -3
- package/dist/runtime/server/routes/__og-image__/debug.json.mjs +5 -7
- package/dist/runtime/server/routes/__og-image__/image.mjs +88 -0
- package/dist/runtime/types.d.ts +96 -27
- package/dist/runtime/utils.d.ts +4 -0
- package/dist/runtime/utils.mjs +11 -0
- package/dist/runtime/utils.pure.d.ts +6 -0
- package/dist/runtime/utils.pure.mjs +63 -0
- package/package.json +33 -38
- package/virtual.d.ts +49 -0
- package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
- package/dist/client/_nuxt/IconCSS.b9d753bf.js +0 -1
- package/dist/client/_nuxt/builds/meta/720964ec-8728-4ffb-b268-2e25afc2779b.json +0 -1
- package/dist/client/_nuxt/entry.434c2c45.css +0 -1
- package/dist/client/_nuxt/entry.56d31ea0.js +0 -137
- package/dist/client/grid.png +0 -0
- package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
- package/dist/runtime/components/OgImage/Cached.mjs +0 -10
- package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
- package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
- package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
- package/dist/runtime/components/OgImage/Static.d.ts +0 -8
- package/dist/runtime/components/OgImage/Static.mjs +0 -10
- package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
- package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
- package/dist/runtime/components/OgImage/index.d.ts +0 -5
- package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
- package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
- package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
- package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
- package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
- package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
- package/dist/runtime/core/font/cache.d.ts +0 -1
- package/dist/runtime/core/font/cache.mjs +0 -1
- package/dist/runtime/core/html/fetch.d.ts +0 -3
- package/dist/runtime/core/options/normalise.d.ts +0 -2
- package/dist/runtime/core/options/normalise.mjs +0 -26
- package/dist/runtime/core/renderers/satori/fonts.d.ts +0 -3
- package/dist/runtime/core/renderers/satori/fonts.mjs +0 -8
- package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
- package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
- package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
- package/dist/runtime/utilts.d.ts +0 -2
- package/dist/runtime/utilts.mjs +0 -8
- /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → wasm-fs.d.ts} +0 -0
- /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
- /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
- /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
- /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export declare function walkSatoriTree(e: H3Event, node: VNode, plugins: (SatoriTransformer | SatoriTransformer[])[]): Promise<void>;
|
|
1
|
+
import type { OgImageRenderEventContext, SatoriTransformer, VNode } from '../../../types';
|
|
2
|
+
export declare function walkSatoriTree(e: OgImageRenderEventContext, node: VNode, plugins: (SatoriTransformer | SatoriTransformer[])[]): Promise<void>;
|
|
4
3
|
export declare function defineSatoriTransformer(transformer: SatoriTransformer | SatoriTransformer[]): SatoriTransformer | SatoriTransformer[];
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
export declare function createVNodes(e: H3Event, options: RendererOptions): Promise<VNode>;
|
|
1
|
+
import type { OgImageRenderEventContext, VNode } from '../../../types';
|
|
2
|
+
export declare function createVNodes(ctx: OgImageRenderEventContext): Promise<VNode>;
|
|
@@ -1,16 +1,26 @@
|
|
|
1
1
|
import { html as convertHtmlToSatori } from "satori-html";
|
|
2
|
-
import {
|
|
2
|
+
import { fetchIsland } from "../../html/fetchIsland.mjs";
|
|
3
|
+
import { applyInlineCss } from "../../html/applyInlineCss.mjs";
|
|
4
|
+
import { applyEmojis } from "../../html/applyEmojis.mjs";
|
|
3
5
|
import { walkSatoriTree } from "./utils.mjs";
|
|
6
|
+
import unocss from "./plugins/unocss.mjs";
|
|
4
7
|
import emojis from "./plugins/emojis.mjs";
|
|
5
8
|
import twClasses from "./plugins/twClasses.mjs";
|
|
6
9
|
import imageSrc from "./plugins/imageSrc.mjs";
|
|
7
10
|
import flex from "./plugins/flex.mjs";
|
|
8
11
|
import encoding from "./plugins/encoding.mjs";
|
|
9
|
-
export async function createVNodes(
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export async function createVNodes(ctx) {
|
|
13
|
+
let html = ctx.options.html;
|
|
14
|
+
if (!html) {
|
|
15
|
+
const island = await fetchIsland(ctx);
|
|
16
|
+
await applyInlineCss(ctx, island);
|
|
17
|
+
await applyEmojis(ctx, island);
|
|
18
|
+
html = island.html;
|
|
19
|
+
}
|
|
20
|
+
const template = `<div data-v-inspector-ignore="true" style="position: relative; display: flex; margin: 0 auto; width: ${ctx.options.width}px; height: ${ctx.options.height}px; overflow: hidden;">${html}</div>`;
|
|
21
|
+
const satoriTree = convertHtmlToSatori(template);
|
|
22
|
+
await walkSatoriTree(ctx, satoriTree, [
|
|
23
|
+
unocss,
|
|
14
24
|
emojis,
|
|
15
25
|
twClasses,
|
|
16
26
|
imageSrc,
|
|
@@ -1,7 +1,3 @@
|
|
|
1
1
|
import type { H3Error, H3Event } from 'h3';
|
|
2
|
-
import type {
|
|
3
|
-
export declare function resolveRendererContext(e: H3Event): Promise<H3Error |
|
|
4
|
-
extension: RuntimeOgImageOptions['extension'];
|
|
5
|
-
renderer: Renderer;
|
|
6
|
-
options: RuntimeOgImageOptions;
|
|
7
|
-
}>;
|
|
2
|
+
import type { OgImageRenderEventContext } from '../../types';
|
|
3
|
+
export declare function resolveRendererContext(e: H3Event): Promise<H3Error | OgImageRenderEventContext>;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { parseURL, withoutBase,
|
|
1
|
+
import { parseURL, withoutBase, withoutTrailingSlash } from "ufo";
|
|
2
2
|
import { createError, getQuery } from "h3";
|
|
3
3
|
import { defu } from "defu";
|
|
4
4
|
import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
|
|
5
5
|
import { fetchPathHtmlAndExtractOptions } from "../options/fetch.mjs";
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { prerenderOptionsCache } from "../cache/prerender.mjs";
|
|
7
|
+
import { useChromiumRenderer, useSatoriRenderer } from "../renderers/satori/instances.mjs";
|
|
8
|
+
import { separateProps, useOgImageRuntimeConfig } from "../../utils.mjs";
|
|
9
|
+
import { resolvePathCacheKey } from "../../nitro/utils.mjs";
|
|
10
|
+
import { useNitroApp, useRuntimeConfig } from "#internal/nitro";
|
|
10
11
|
export async function resolveRendererContext(e) {
|
|
11
|
-
const runtimeConfig =
|
|
12
|
+
const runtimeConfig = useOgImageRuntimeConfig();
|
|
12
13
|
const path = parseURL(e.path).pathname;
|
|
13
14
|
const extension = path.split(".").pop();
|
|
14
15
|
if (!extension) {
|
|
@@ -17,22 +18,29 @@ export async function resolveRendererContext(e) {
|
|
|
17
18
|
statusMessage: `Missing OG Image type.`
|
|
18
19
|
});
|
|
19
20
|
}
|
|
21
|
+
if (!["png", "jpeg", "jpg", "svg", "html", "json"].includes(extension)) {
|
|
22
|
+
return createError({
|
|
23
|
+
statusCode: 400,
|
|
24
|
+
statusMessage: `Unknown OG Image type ${extension}.`
|
|
25
|
+
});
|
|
26
|
+
}
|
|
20
27
|
const basePath = withoutTrailingSlash(
|
|
21
|
-
path.replace(
|
|
28
|
+
path.replace(`/__og-image__/image`, "").replace(`/og.${extension}`, "")
|
|
22
29
|
);
|
|
23
|
-
|
|
30
|
+
let queryParams = { ...getQuery(e) };
|
|
31
|
+
queryParams.props = JSON.parse(queryParams.props || "{}");
|
|
32
|
+
queryParams = separateProps(queryParams);
|
|
33
|
+
const isDebugJsonPayload = extension === "json" && runtimeConfig.debug;
|
|
34
|
+
const key = resolvePathCacheKey(e, basePath);
|
|
24
35
|
let options = queryParams.options;
|
|
25
36
|
if (!options) {
|
|
26
|
-
if (import.meta.prerender)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
if (payloadOptions instanceof Error)
|
|
34
|
-
return payloadOptions;
|
|
35
|
-
options = payloadOptions;
|
|
37
|
+
if (import.meta.prerender)
|
|
38
|
+
options = await prerenderOptionsCache?.getItem(key);
|
|
39
|
+
if (!options) {
|
|
40
|
+
const payload = await fetchPathHtmlAndExtractOptions(e, basePath, key);
|
|
41
|
+
if (payload instanceof Error)
|
|
42
|
+
return payload;
|
|
43
|
+
options = payload;
|
|
36
44
|
}
|
|
37
45
|
}
|
|
38
46
|
delete queryParams.options;
|
|
@@ -41,8 +49,15 @@ export async function resolveRendererContext(e) {
|
|
|
41
49
|
);
|
|
42
50
|
const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
|
|
43
51
|
withoutBase(basePath.split("?")[0], useRuntimeConfig().app.baseURL)
|
|
44
|
-
).reverse())
|
|
45
|
-
|
|
52
|
+
).reverse());
|
|
53
|
+
if (typeof routeRules.ogImage === "undefined" && !options) {
|
|
54
|
+
return createError({
|
|
55
|
+
statusCode: 400,
|
|
56
|
+
statusMessage: "The route is missing the Nuxt OG Image payload or route rules."
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
const ogImageRouteRules = separateProps(routeRules.ogImage);
|
|
60
|
+
options = defu(queryParams, ogImageRouteRules, options, runtimeConfig.defaults);
|
|
46
61
|
if (!options) {
|
|
47
62
|
return createError({
|
|
48
63
|
statusCode: 404,
|
|
@@ -52,25 +67,28 @@ export async function resolveRendererContext(e) {
|
|
|
52
67
|
let renderer;
|
|
53
68
|
switch (options.renderer) {
|
|
54
69
|
case "satori":
|
|
55
|
-
renderer =
|
|
70
|
+
renderer = await useSatoriRenderer();
|
|
56
71
|
break;
|
|
57
72
|
case "chromium":
|
|
58
|
-
renderer =
|
|
73
|
+
renderer = await useChromiumRenderer();
|
|
59
74
|
break;
|
|
60
75
|
}
|
|
61
|
-
if (!renderer) {
|
|
76
|
+
if (!renderer || renderer.__unenv__) {
|
|
62
77
|
throw createError({
|
|
63
78
|
statusCode: 400,
|
|
64
79
|
statusMessage: `Renderer ${options.renderer} is missing.`
|
|
65
80
|
});
|
|
66
81
|
}
|
|
67
|
-
|
|
82
|
+
const ctx = {
|
|
83
|
+
e,
|
|
84
|
+
key,
|
|
68
85
|
renderer,
|
|
86
|
+
isDebugJsonPayload,
|
|
69
87
|
extension,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
path: basePath
|
|
74
|
-
}
|
|
88
|
+
basePath,
|
|
89
|
+
options,
|
|
90
|
+
_nitro: useNitroApp()
|
|
75
91
|
};
|
|
92
|
+
await ctx._nitro.hooks.callHook("nuxt-og-image:context", ctx);
|
|
93
|
+
return ctx;
|
|
76
94
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolvePath } from "mlly";
|
|
3
|
+
export async function importWasm(input) {
|
|
4
|
+
const _input = await input;
|
|
5
|
+
const _module = _input.default || _input;
|
|
6
|
+
if (typeof _module === "function") {
|
|
7
|
+
const fnRes = await _module();
|
|
8
|
+
const _instance = fnRes.instance || fnRes;
|
|
9
|
+
return _instance.exports || _instance || _module;
|
|
10
|
+
}
|
|
11
|
+
return _module;
|
|
12
|
+
}
|
|
13
|
+
export async function readWasmFile(input) {
|
|
14
|
+
const path = await resolvePath(input);
|
|
15
|
+
return readFile(path);
|
|
16
|
+
}
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
|
|
2
2
|
import { defu } from "defu";
|
|
3
|
-
import { getOgImagePath } from "../../
|
|
4
|
-
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { getOgImagePath, useOgImageRuntimeConfig } from "../../utils.mjs";
|
|
5
4
|
export default defineNitroPlugin((nitroApp) => {
|
|
6
5
|
nitroApp.hooks.hook("content:file:afterParse", async (content) => {
|
|
7
6
|
if (content._draft || content._extension !== "md" || content._partial || content.indexable === false || content.index === false)
|
|
8
7
|
return;
|
|
9
8
|
if (content.path && content.ogImage) {
|
|
10
9
|
const ogImageConfig = typeof content.ogImage === "object" ? content.ogImage : {};
|
|
11
|
-
const { defaults } =
|
|
10
|
+
const { defaults } = useOgImageRuntimeConfig();
|
|
12
11
|
const optionsWithDefault = defu(ogImageConfig, defaults);
|
|
13
|
-
const src = getOgImagePath(content.path, optionsWithDefault
|
|
12
|
+
const src = getOgImagePath(content.path, optionsWithDefault);
|
|
14
13
|
const payload = {
|
|
15
14
|
title: content.title,
|
|
16
15
|
excerpt: content.description || content.excerpt,
|
|
@@ -22,12 +21,14 @@ export default defineNitroPlugin((nitroApp) => {
|
|
|
22
21
|
content.head = defu({
|
|
23
22
|
script: [
|
|
24
23
|
{
|
|
25
|
-
id: "nuxt-og-image-
|
|
24
|
+
id: "nuxt-og-image-overrides",
|
|
26
25
|
type: "application/json",
|
|
27
26
|
processTemplateParams: true,
|
|
28
27
|
innerHTML: payload,
|
|
29
28
|
// we want this to be last in our head
|
|
30
|
-
tagPosition: "bodyClose"
|
|
29
|
+
tagPosition: "bodyClose",
|
|
30
|
+
tagPriority: 30
|
|
31
|
+
// slighty higher priority
|
|
31
32
|
}
|
|
32
33
|
],
|
|
33
34
|
meta: [
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: import("nitropack
|
|
1
|
+
declare const _default: import("nitropack").NitroAppPlugin;
|
|
2
2
|
export default _default;
|
|
@@ -1,17 +1,27 @@
|
|
|
1
|
-
import { parseURL,
|
|
2
|
-
import { getRouteRules } from "nitropack/dist/runtime/route-rules";
|
|
3
|
-
import { extractAndNormaliseOgImageOptions } from "../../core/options/extract.mjs";
|
|
4
|
-
import { prerenderCache, prerenderChromiumContext } from "../../core/cache/prerender.mjs";
|
|
5
|
-
import { isInternalRoute } from "../../utilts.mjs";
|
|
1
|
+
import { parseURL, withoutBase } from "ufo";
|
|
6
2
|
import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
|
|
3
|
+
import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
|
|
4
|
+
import { defu } from "defu";
|
|
5
|
+
import { extractAndNormaliseOgImageOptions } from "../../core/options/extract.mjs";
|
|
6
|
+
import { prerenderOptionsCache } from "../../core/cache/prerender.mjs";
|
|
7
|
+
import { isInternalRoute } from "../../utils.pure.mjs";
|
|
8
|
+
import { resolvePathCacheKey } from "../utils.mjs";
|
|
9
|
+
import { useRuntimeConfig } from "#internal/nitro";
|
|
7
10
|
export default defineNitroPlugin(async (nitro) => {
|
|
8
11
|
if (!import.meta.prerender)
|
|
9
12
|
return;
|
|
10
|
-
nitro.hooks.hook("render:html", async (
|
|
11
|
-
const
|
|
13
|
+
nitro.hooks.hook("render:html", async (html, ctx) => {
|
|
14
|
+
const { head, bodyAppend } = html;
|
|
15
|
+
const path = parseURL(ctx.event.path).pathname;
|
|
12
16
|
if (isInternalRoute(path))
|
|
13
17
|
return;
|
|
14
|
-
const
|
|
18
|
+
const runtimeConfig = useRuntimeConfig();
|
|
19
|
+
const _routeRulesMatcher = toRouteMatcher(
|
|
20
|
+
createRadixRouter({ routes: runtimeConfig.nitro?.routeRules })
|
|
21
|
+
);
|
|
22
|
+
const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
|
|
23
|
+
withoutBase(path.split("?")[0], runtimeConfig.app.baseURL)
|
|
24
|
+
).reverse()).ogImage;
|
|
15
25
|
if (routeRules === false)
|
|
16
26
|
return;
|
|
17
27
|
const options = extractAndNormaliseOgImageOptions([
|
|
@@ -20,15 +30,7 @@ export default defineNitroPlugin(async (nitro) => {
|
|
|
20
30
|
].join("\n"));
|
|
21
31
|
if (!options)
|
|
22
32
|
return;
|
|
23
|
-
const key =
|
|
24
|
-
|
|
25
|
-
].join(":");
|
|
26
|
-
await prerenderCache.setItem(key, options);
|
|
27
|
-
});
|
|
28
|
-
nitro.hooks.hook("close", () => {
|
|
29
|
-
if (prerenderChromiumContext.browser) {
|
|
30
|
-
prerenderChromiumContext.browser.close();
|
|
31
|
-
prerenderChromiumContext.browser = void 0;
|
|
32
|
-
}
|
|
33
|
+
const key = resolvePathCacheKey(ctx.event);
|
|
34
|
+
await prerenderOptionsCache.setItem(key, options);
|
|
33
35
|
});
|
|
34
36
|
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { withoutLeadingSlash, withoutTrailingSlash } from "ufo";
|
|
2
|
+
import { hash } from "ohash";
|
|
3
|
+
import { normalizeKey } from "unstorage";
|
|
4
|
+
import { getQuery } from "h3";
|
|
5
|
+
import { useSiteConfig } from "#imports";
|
|
6
|
+
export function resolvePathCacheKey(e, path) {
|
|
7
|
+
const siteConfig = useSiteConfig(e);
|
|
8
|
+
const basePath = withoutTrailingSlash(withoutLeadingSlash(normalizeKey(path || e.path)));
|
|
9
|
+
return [
|
|
10
|
+
!basePath ? "index" : basePath,
|
|
11
|
+
hash([
|
|
12
|
+
basePath,
|
|
13
|
+
siteConfig.url,
|
|
14
|
+
hash(getQuery(e))
|
|
15
|
+
])
|
|
16
|
+
].join(":");
|
|
17
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { parseURL } from "ufo";
|
|
2
|
+
import { toValue } from "vue";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import { isInternalRoute, separateProps } from "../../utils.pure.mjs";
|
|
5
|
+
import { defineNuxtPlugin, useRequestEvent, withSiteUrl } from "#imports";
|
|
6
|
+
export default defineNuxtPlugin({
|
|
7
|
+
setup(nuxtApp) {
|
|
8
|
+
nuxtApp.hooks.hook("app:rendered", async (ctx) => {
|
|
9
|
+
const { ssrContext } = ctx;
|
|
10
|
+
const e = useRequestEvent();
|
|
11
|
+
const path = parseURL(e.path).pathname;
|
|
12
|
+
if (isInternalRoute(path))
|
|
13
|
+
return;
|
|
14
|
+
ssrContext?.head.use({
|
|
15
|
+
key: "nuxt-og-image:overrides-and-canonical-urls",
|
|
16
|
+
hooks: {
|
|
17
|
+
"tags:resolve": async (ctx2) => {
|
|
18
|
+
let overrides;
|
|
19
|
+
for (const tag of ctx2.tags) {
|
|
20
|
+
if (tag.tag === "script" && tag.props.id === "nuxt-og-image-overrides") {
|
|
21
|
+
overrides = separateProps(JSON.parse(tag.innerHTML || "{}"));
|
|
22
|
+
delete ctx2.tags[ctx2.tags.indexOf(tag)];
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
ctx2.tags = ctx2.tags.filter(Boolean);
|
|
27
|
+
for (const tag of ctx2.tags) {
|
|
28
|
+
if (tag.tag === "meta" && (tag.props.property === "og:image" || tag.props.name === "twitter:image:src")) {
|
|
29
|
+
if (!tag.props.content.startsWith("https")) {
|
|
30
|
+
await nuxtApp.runWithContext(() => {
|
|
31
|
+
tag.props.content = toValue(withSiteUrl(tag.props.content));
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
} else if (overrides && tag.tag === "script" && tag.props.id === "nuxt-og-image-options") {
|
|
35
|
+
tag.innerHTML = JSON.stringify(defu(overrides, JSON.parse(tag.innerHTML)));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
});
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { defu } from "defu";
|
|
2
2
|
import { parseURL, withoutBase } from "ufo";
|
|
3
3
|
import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { defineNuxtPlugin, useRequestEvent
|
|
4
|
+
import { getOgImagePath, isInternalRoute, useOgImageRuntimeConfig } from "../../utils.mjs";
|
|
5
|
+
import { createOgImageMeta, normaliseOptions } from "../utils.mjs";
|
|
6
|
+
import { defineNuxtPlugin, useRequestEvent } from "#imports";
|
|
7
7
|
export default defineNuxtPlugin((nuxtApp) => {
|
|
8
8
|
nuxtApp.hooks.hook("app:rendered", async (ctx) => {
|
|
9
9
|
const { ssrContext } = ctx;
|
|
@@ -14,59 +14,24 @@ export default defineNuxtPlugin((nuxtApp) => {
|
|
|
14
14
|
const _routeRulesMatcher = toRouteMatcher(
|
|
15
15
|
createRadixRouter({ routes: ssrContext?.runtimeConfig?.nitro?.routeRules })
|
|
16
16
|
);
|
|
17
|
-
|
|
17
|
+
let routeRules = defu({}, ..._routeRulesMatcher.matchAll(
|
|
18
18
|
withoutBase(path.split("?")[0], ssrContext?.runtimeConfig?.app.baseURL)
|
|
19
19
|
).reverse()).ogImage;
|
|
20
20
|
if (typeof routeRules === "undefined")
|
|
21
21
|
return;
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const ogImageInstances = nuxtApp.ssrContext._ogImageInstances || [];
|
|
23
|
+
if (routeRules === false) {
|
|
24
|
+
ogImageInstances?.forEach((e2) => {
|
|
25
|
+
e2.dispose();
|
|
26
|
+
});
|
|
27
|
+
nuxtApp.ssrContext._ogImagePayload = void 0;
|
|
28
|
+
nuxtApp.ssrContext._ogImageInstances = void 0;
|
|
27
29
|
return;
|
|
28
30
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
const src = getOgImagePath(ssrContext.url, optionsWithDefault.extension);
|
|
35
|
-
ssrContext?.head.push({
|
|
36
|
-
script: [
|
|
37
|
-
{
|
|
38
|
-
id: "nuxt-og-image-options",
|
|
39
|
-
type: "application/json",
|
|
40
|
-
processTemplateParams: true,
|
|
41
|
-
innerHTML: () => {
|
|
42
|
-
const payload = {
|
|
43
|
-
title: "%s"
|
|
44
|
-
};
|
|
45
|
-
Object.entries(options).forEach(([key, val]) => {
|
|
46
|
-
payload[key.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = val;
|
|
47
|
-
});
|
|
48
|
-
return payload;
|
|
49
|
-
},
|
|
50
|
-
// we want this to be last in our head
|
|
51
|
-
tagPosition: "bodyClose"
|
|
52
|
-
}
|
|
53
|
-
],
|
|
54
|
-
meta: [
|
|
55
|
-
{ property: "og:image", content: src },
|
|
56
|
-
{ property: "og:image:width", content: optionsWithDefault.width },
|
|
57
|
-
{ property: "og:image:height", content: optionsWithDefault.height },
|
|
58
|
-
{ property: "og:image:type", content: `image/${optionsWithDefault.extension}` },
|
|
59
|
-
{ property: "og:image:alt", content: optionsWithDefault.alt },
|
|
60
|
-
// twitter
|
|
61
|
-
{ name: "twitter:card", content: "summary_large_image" },
|
|
62
|
-
{ name: "twitter:image:src", content: src },
|
|
63
|
-
{ name: "twitter:image:width", content: optionsWithDefault.width },
|
|
64
|
-
{ name: "twitter:image:height", content: optionsWithDefault.height },
|
|
65
|
-
{ name: "twitter:image:alt", content: optionsWithDefault.alt }
|
|
66
|
-
]
|
|
67
|
-
}, {
|
|
68
|
-
mode: "server",
|
|
69
|
-
tagPriority: 35
|
|
70
|
-
});
|
|
31
|
+
routeRules = defu(nuxtApp.ssrContext?.event.context._nitro?.routeRules?.ogImage, routeRules);
|
|
32
|
+
const { defaults } = useOgImageRuntimeConfig();
|
|
33
|
+
const resolvedOptions = normaliseOptions(defu(routeRules, defaults));
|
|
34
|
+
const src = getOgImagePath(ssrContext.url, resolvedOptions);
|
|
35
|
+
createOgImageMeta(src, routeRules, resolvedOptions, nuxtApp.ssrContext);
|
|
71
36
|
});
|
|
72
37
|
});
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { DefineOgImageInput, OgImageOptions, OgImagePrebuilt } from '../types';
|
|
2
|
+
export declare function createOgImageMeta(src: string | null, input: OgImageOptions | OgImagePrebuilt, resolvedOptions: OgImageOptions, ssrContext: Record<string, any>): void;
|
|
3
|
+
export declare function normaliseOptions(_options: DefineOgImageInput): OgImageOptions | OgImagePrebuilt;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { defu } from "defu";
|
|
2
|
+
import { separateProps } from "../utils.mjs";
|
|
3
|
+
import { unref, useServerHead } from "#imports";
|
|
4
|
+
import { componentNames } from "#build/nuxt-og-image/components.mjs";
|
|
5
|
+
export function createOgImageMeta(src, input, resolvedOptions, ssrContext) {
|
|
6
|
+
const _input = separateProps(defu(input, ssrContext._ogImagePayload));
|
|
7
|
+
const url = src || input.url || resolvedOptions.url;
|
|
8
|
+
let urlExtension = (url.split("/").pop() || url).split(".").pop() || resolvedOptions.extension;
|
|
9
|
+
if (urlExtension === "jpg")
|
|
10
|
+
urlExtension = "jpeg";
|
|
11
|
+
const meta = [
|
|
12
|
+
{ property: "og:image", content: url },
|
|
13
|
+
{ property: "og:image:type", content: `image/${urlExtension}` },
|
|
14
|
+
{ name: "twitter:card", content: "summary_large_image" },
|
|
15
|
+
{ name: "twitter:image:src", content: url }
|
|
16
|
+
];
|
|
17
|
+
if (resolvedOptions.width) {
|
|
18
|
+
meta.push({ property: "og:image:width", content: resolvedOptions.width });
|
|
19
|
+
meta.push({ name: "twitter:image:width", content: resolvedOptions.width });
|
|
20
|
+
}
|
|
21
|
+
if (resolvedOptions.height) {
|
|
22
|
+
meta.push({ property: "og:image:height", content: resolvedOptions.height });
|
|
23
|
+
meta.push({ name: "twitter:image:height", content: resolvedOptions.height });
|
|
24
|
+
}
|
|
25
|
+
if (resolvedOptions.alt) {
|
|
26
|
+
meta.push({ property: "og:image:alt", content: resolvedOptions.alt });
|
|
27
|
+
meta.push({ name: "twitter:image:alt", content: resolvedOptions.alt });
|
|
28
|
+
}
|
|
29
|
+
ssrContext._ogImageInstances = ssrContext._ogImageInstances || [];
|
|
30
|
+
const script = [];
|
|
31
|
+
if (src) {
|
|
32
|
+
script.push({
|
|
33
|
+
id: "nuxt-og-image-options",
|
|
34
|
+
type: "application/json",
|
|
35
|
+
processTemplateParams: true,
|
|
36
|
+
innerHTML: () => {
|
|
37
|
+
if (!_input.props.title)
|
|
38
|
+
_input.props.title = "%s";
|
|
39
|
+
delete _input.url;
|
|
40
|
+
return _input;
|
|
41
|
+
},
|
|
42
|
+
// we want this to be last in our head
|
|
43
|
+
tagPosition: "bodyClose"
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const instance = useServerHead({
|
|
47
|
+
script,
|
|
48
|
+
meta
|
|
49
|
+
}, {
|
|
50
|
+
tagPriority: 35
|
|
51
|
+
});
|
|
52
|
+
ssrContext._ogImagePayload = _input;
|
|
53
|
+
ssrContext._ogImageInstances.push(instance);
|
|
54
|
+
}
|
|
55
|
+
export function normaliseOptions(_options) {
|
|
56
|
+
const options = { ...unref(_options) };
|
|
57
|
+
if (!options)
|
|
58
|
+
return options;
|
|
59
|
+
if (options.component && componentNames) {
|
|
60
|
+
const originalName = options.component;
|
|
61
|
+
for (const component of componentNames) {
|
|
62
|
+
if (component.pascalName.endsWith(originalName) || component.kebabName.endsWith(originalName)) {
|
|
63
|
+
options.component = component.pascalName;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return options;
|
|
69
|
+
}
|
|
@@ -4,8 +4,7 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
|
|
|
4
4
|
source: any;
|
|
5
5
|
};
|
|
6
6
|
componentNames: any;
|
|
7
|
-
runtimeConfig:
|
|
8
|
-
|
|
9
|
-
cachedKeys: string[];
|
|
7
|
+
runtimeConfig: import("../../../types").OgImageRuntimeConfig;
|
|
8
|
+
compatibility: any;
|
|
10
9
|
}>>;
|
|
11
10
|
export default _default;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { defineEventHandler, setHeader } from "h3";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { useOgImageRuntimeConfig } from "../../../utils.mjs";
|
|
3
|
+
import { useSiteConfig } from "#imports";
|
|
4
|
+
import compatibility from "#nuxt-og-image/compatibility";
|
|
4
5
|
import { componentNames } from "#nuxt-og-image/component-names.mjs";
|
|
5
6
|
export default defineEventHandler(async (e) => {
|
|
6
7
|
setHeader(e, "Content-Type", "application/json");
|
|
7
|
-
const runtimeConfig =
|
|
8
|
+
const runtimeConfig = useOgImageRuntimeConfig();
|
|
8
9
|
const siteConfig = await useSiteConfig(e, { debug: true });
|
|
9
|
-
const baseCacheKey = runtimeConfig.runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${runtimeConfig.version}` : `/nuxt-og-image@${runtimeConfig.version}`;
|
|
10
|
-
const cache = prefixStorage(useStorage(), `${baseCacheKey}/`);
|
|
11
10
|
return {
|
|
12
11
|
siteConfigUrl: {
|
|
13
12
|
value: siteConfig.url,
|
|
@@ -15,7 +14,6 @@ export default defineEventHandler(async (e) => {
|
|
|
15
14
|
},
|
|
16
15
|
componentNames,
|
|
17
16
|
runtimeConfig,
|
|
18
|
-
|
|
19
|
-
cachedKeys: await cache.getKeys()
|
|
17
|
+
compatibility
|
|
20
18
|
};
|
|
21
19
|
});
|