nuxt-og-image 2.0.0-beta.8 → 2.0.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 +18 -517
- package/dist/client/200.html +2 -2
- package/dist/client/404.html +2 -2
- package/dist/client/_nuxt/IconCSS.48ffa50d.js +1 -0
- package/dist/client/_nuxt/IconCSS.b41b9663.css +1 -0
- package/dist/client/_nuxt/ImageLoader.51157bac.js +1 -0
- package/dist/client/_nuxt/ImageLoader.7571516f.css +1 -0
- package/dist/client/_nuxt/entry.1311cc29.css +1 -0
- package/dist/client/_nuxt/entry.74c20cae.js +143 -0
- package/dist/client/_nuxt/{error-404.f5dc80fe.js → error-404.102f7671.js} +1 -1
- package/dist/client/_nuxt/error-404.f3dd5020.css +1 -0
- package/dist/client/_nuxt/error-500.06915589.css +1 -0
- package/dist/client/_nuxt/{error-500.a1082086.js → error-500.f8617a9a.js} +1 -1
- package/dist/client/_nuxt/index.212ef337.js +1 -0
- package/dist/client/_nuxt/index.ffbea0a9.css +1 -0
- package/dist/client/_nuxt/options.fa4f11fe.js +1 -0
- package/dist/client/_nuxt/png.eb47fcca.js +1 -0
- package/dist/client/_nuxt/{shiki.665f08b3.js → shiki.b89869e1.js} +1 -1
- package/dist/client/_nuxt/svg.04901249.js +1 -0
- package/dist/client/_nuxt/vnodes.b05f3d68.js +1 -0
- package/dist/client/index.html +2 -2
- package/dist/client/options/index.html +2 -2
- package/dist/client/png/index.html +2 -2
- package/dist/client/svg/index.html +2 -2
- package/dist/client/vnodes/index.html +2 -2
- package/dist/module.d.ts +101 -11
- package/dist/module.json +2 -2
- package/dist/module.mjs +374 -118
- package/dist/runtime/browserUtil.d.ts +1 -0
- package/dist/runtime/browserUtil.mjs +7 -5
- package/dist/runtime/components/{OgImageDynamic.d.ts → OgImage/Cached.d.ts} +2 -2
- package/dist/runtime/components/OgImage/Cached.mjs +10 -0
- package/dist/runtime/components/OgImage/Dynamic.d.ts +8 -0
- package/dist/runtime/components/{OgImageDynamic.mjs → OgImage/Dynamic.mjs} +3 -3
- package/dist/runtime/components/{OgImageScreenshot.d.ts → OgImage/Screenshot.d.ts} +2 -2
- package/dist/runtime/components/{OgImageScreenshot.mjs → OgImage/Screenshot.mjs} +2 -2
- package/dist/runtime/components/OgImage/Static.d.ts +8 -0
- package/dist/runtime/components/{OgImageStatic.mjs → OgImage/Static.mjs} +3 -3
- package/dist/runtime/components/{OgImageStatic.d.ts → OgImage/WithoutCache.d.ts} +2 -2
- package/dist/runtime/components/OgImage/WithoutCache.mjs +10 -0
- package/dist/runtime/components/OgImage/index.d.ts +5 -0
- package/dist/runtime/components/OgImage/index.mjs +10 -0
- package/dist/runtime/components/OgImageTemplate/Fallback.vue +156 -0
- package/dist/runtime/composables/defineOgImage.d.ts +12 -4
- package/dist/runtime/composables/defineOgImage.mjs +31 -49
- package/dist/runtime/composables/util.d.ts +2 -0
- package/dist/runtime/composables/util.mjs +26 -0
- package/dist/runtime/nitro/middleware/og.png.mjs +54 -8
- package/dist/runtime/nitro/plugins/prerender.d.ts +3 -0
- package/dist/runtime/nitro/plugins/prerender.mjs +28 -0
- package/dist/runtime/nitro/providers/browser/lambda.d.ts +1 -1
- package/dist/runtime/nitro/providers/browser/lambda.mjs +3 -3
- package/dist/runtime/nitro/providers/browser/{node.mjs → playwright.mjs} +0 -9
- package/dist/runtime/nitro/providers/browser/universal.d.ts +1 -0
- package/dist/runtime/nitro/providers/browser/universal.mjs +33 -0
- package/dist/runtime/nitro/providers/png/resvg-node.d.ts +4 -0
- package/dist/runtime/nitro/providers/png/resvg-node.mjs +6 -0
- package/dist/runtime/nitro/providers/png/resvg-wasm.d.ts +3 -0
- package/dist/runtime/nitro/providers/png/resvg-wasm.mjs +11 -0
- package/dist/runtime/nitro/providers/{svg2png/universal.d.ts → png/svg2png.d.ts} +2 -3
- package/dist/runtime/nitro/providers/png/svg2png.mjs +11 -0
- package/dist/runtime/nitro/providers/satori/{webworker.d.ts → yoga-wasm.d.ts} +2 -3
- package/dist/runtime/nitro/providers/satori/{webworker.mjs → yoga-wasm.mjs} +4 -5
- package/dist/runtime/nitro/renderers/browser.d.ts +2 -2
- package/dist/runtime/nitro/renderers/browser.mjs +14 -12
- package/dist/runtime/nitro/renderers/satori/index.d.ts +2 -2
- package/dist/runtime/nitro/renderers/satori/index.mjs +27 -32
- package/dist/runtime/nitro/renderers/satori/plugins/emojis.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/emojis.mjs +19 -6
- package/dist/runtime/nitro/renderers/satori/plugins/encoding.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/encoding.mjs +5 -7
- package/dist/runtime/nitro/renderers/satori/plugins/flex.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/flex.mjs +8 -10
- package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.mjs +45 -13
- package/dist/runtime/nitro/renderers/satori/plugins/twClasses.d.ts +1 -1
- package/dist/runtime/nitro/renderers/satori/plugins/twClasses.mjs +5 -7
- package/dist/runtime/nitro/renderers/satori/utils.d.ts +4 -5
- package/dist/runtime/nitro/renderers/satori/utils.mjs +28 -17
- package/dist/runtime/nitro/routes/debug.d.ts +8 -0
- package/dist/runtime/nitro/routes/debug.mjs +14 -0
- package/dist/runtime/nitro/routes/font.mjs +2 -2
- package/dist/runtime/nitro/routes/html.mjs +100 -26
- package/dist/runtime/nitro/routes/options.d.ts +2 -2
- package/dist/runtime/nitro/routes/options.mjs +21 -20
- package/dist/runtime/nitro/routes/svg.mjs +2 -2
- package/dist/runtime/nitro/routes/vnode.mjs +2 -2
- package/dist/runtime/nitro/utils-pure.d.ts +2 -2
- package/dist/runtime/nitro/utils-pure.mjs +1 -4
- package/dist/runtime/nitro/utils.d.ts +11 -11
- package/dist/runtime/nitro/utils.mjs +67 -53
- package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
- package/dist/runtime/public-assets-optional/resvg/resvg.wasm +0 -0
- package/dist/types.d.ts +6 -0
- package/package.json +38 -27
- package/dist/client/_nuxt/IconCSS.e4ca33fe.js +0 -1
- package/dist/client/_nuxt/ImageLoader.b3a6a884.js +0 -1
- package/dist/client/_nuxt/entry.0bddba71.js +0 -5
- package/dist/client/_nuxt/entry.b37a20ad.css +0 -1
- package/dist/client/_nuxt/error-404.1469f10f.css +0 -1
- package/dist/client/_nuxt/error-500.92b94fae.css +0 -1
- package/dist/client/_nuxt/error-component.a28c293c.js +0 -3
- package/dist/client/_nuxt/index.7dc20983.js +0 -1
- package/dist/client/_nuxt/options.97e2328c.js +0 -1
- package/dist/client/_nuxt/png.50aa137a.js +0 -1
- package/dist/client/_nuxt/svg.d633e908.js +0 -1
- package/dist/client/_nuxt/vnodes.63ee1c3b.js +0 -1
- package/dist/runtime/components/OgImageBasic.island.vue +0 -92
- package/dist/runtime/nitro/providers/svg2png/universal.mjs +0 -9
- /package/dist/runtime/nitro/providers/browser/{node.d.ts → playwright.d.ts} +0 -0
- /package/dist/runtime/nitro/providers/satori/{node.d.ts → default.d.ts} +0 -0
- /package/dist/runtime/nitro/providers/satori/{node.mjs → default.mjs} +0 -0
- /package/dist/runtime/{public-assets → public-assets-optional/inter-font}/inter-latin-ext-400-normal.woff +0 -0
- /package/dist/runtime/{public-assets → public-assets-optional/inter-font}/inter-latin-ext-700-normal.woff +0 -0
- /package/dist/runtime/{public-assets → public-assets-optional/svg2png}/svg2png.wasm +0 -0
- /package/dist/runtime/{public-assets → public-assets-optional/yoga}/yoga.wasm +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import type { Buffer } from 'node:buffer';
|
|
2
3
|
import type { Browser } from 'playwright-core';
|
|
3
4
|
import type { ScreenshotOptions } from '../types';
|
|
4
5
|
export declare function screenshot(browser: Browser, options: Partial<ScreenshotOptions> & Record<string, any>): Promise<Buffer>;
|
|
@@ -6,9 +6,9 @@ export async function screenshot(browser, options) {
|
|
|
6
6
|
width: options.width || 1200,
|
|
7
7
|
height: options.height || 630
|
|
8
8
|
});
|
|
9
|
-
const isHtml = options.path
|
|
9
|
+
const isHtml = options.html || options.path?.startsWith("html:");
|
|
10
10
|
if (isHtml) {
|
|
11
|
-
const html = options.html || options.path
|
|
11
|
+
const html = options.html || options.path?.substring(5);
|
|
12
12
|
await page.evaluate((html2) => {
|
|
13
13
|
document.open("text/html");
|
|
14
14
|
document.write(html2);
|
|
@@ -17,12 +17,12 @@ export async function screenshot(browser, options) {
|
|
|
17
17
|
await page.waitForLoadState("networkidle");
|
|
18
18
|
} else {
|
|
19
19
|
await page.goto(`${options.host}${options.path}`, {
|
|
20
|
-
timeout: 1e4,
|
|
20
|
+
timeout: process.env.prerender || process.dev ? 1e4 : 3500,
|
|
21
21
|
waitUntil: "networkidle"
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
24
|
const screenshotOptions = {
|
|
25
|
-
timeout: 1e4
|
|
25
|
+
timeout: process.env.prerender || process.dev ? 1e4 : 3500
|
|
26
26
|
};
|
|
27
27
|
if (options.delay)
|
|
28
28
|
await page.waitForTimeout(options.delay);
|
|
@@ -34,5 +34,7 @@ export async function screenshot(browser, options) {
|
|
|
34
34
|
}
|
|
35
35
|
if (options.selector)
|
|
36
36
|
return await page.locator(options.selector).screenshot(screenshotOptions);
|
|
37
|
-
|
|
37
|
+
const screenshot2 = await page.screenshot(screenshotOptions);
|
|
38
|
+
await page.close();
|
|
39
|
+
return screenshot2;
|
|
38
40
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
|
-
}>;
|
|
4
|
+
}, {}>;
|
|
5
5
|
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineComponent } from "vue";
|
|
2
|
+
import { defineOgImageCached } from "#imports";
|
|
3
|
+
export default defineComponent({
|
|
4
|
+
name: "OgImageCached",
|
|
5
|
+
async setup(_, { attrs }) {
|
|
6
|
+
if (process.server)
|
|
7
|
+
await defineOgImageCached(attrs);
|
|
8
|
+
return () => null;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OgImageOptions } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Use OgImageWithoutCache
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
6
|
+
[x: string]: any;
|
|
7
|
+
}, {}>;
|
|
8
|
+
export default _default;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineComponent } from "vue";
|
|
2
|
-
import {
|
|
2
|
+
import { defineOgImageWithoutCache } from "#imports";
|
|
3
3
|
export default defineComponent({
|
|
4
4
|
name: "OgImageDynamic",
|
|
5
|
-
setup(_, { attrs }) {
|
|
5
|
+
async setup(_, { attrs }) {
|
|
6
6
|
if (process.server)
|
|
7
|
-
|
|
7
|
+
await defineOgImageWithoutCache(attrs);
|
|
8
8
|
return () => null;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { OgImageScreenshotOptions } from '
|
|
1
|
+
import type { OgImageScreenshotOptions } from '../../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageScreenshotOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageScreenshotOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
[x: number]: any;
|
|
5
|
-
}>;
|
|
5
|
+
}, {}>;
|
|
6
6
|
export default _default;
|
|
@@ -2,9 +2,9 @@ import { defineComponent } from "vue";
|
|
|
2
2
|
import { defineOgImageScreenshot } from "#imports";
|
|
3
3
|
export default defineComponent({
|
|
4
4
|
name: "OgImageScreenshot",
|
|
5
|
-
setup(_, { attrs }) {
|
|
5
|
+
async setup(_, { attrs }) {
|
|
6
6
|
if (process.server)
|
|
7
|
-
defineOgImageScreenshot(attrs);
|
|
7
|
+
await defineOgImageScreenshot(attrs);
|
|
8
8
|
return () => null;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { OgImageOptions } from '../../../types';
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Use OgImageCached instead
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
6
|
+
[x: string]: any;
|
|
7
|
+
}, {}>;
|
|
8
|
+
export default _default;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { defineComponent } from "vue";
|
|
2
|
-
import {
|
|
2
|
+
import { defineOgImageCached } from "#imports";
|
|
3
3
|
export default defineComponent({
|
|
4
4
|
name: "OgImageStatic",
|
|
5
|
-
setup(_, { attrs }) {
|
|
5
|
+
async setup(_, { attrs }) {
|
|
6
6
|
if (process.server)
|
|
7
|
-
|
|
7
|
+
await defineOgImageCached(attrs);
|
|
8
8
|
return () => null;
|
|
9
9
|
}
|
|
10
10
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../../../types';
|
|
2
2
|
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
|
-
}>;
|
|
4
|
+
}, {}>;
|
|
5
5
|
export default _default;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineComponent } from "vue";
|
|
2
|
+
import { defineOgImageWithoutCache } from "#imports";
|
|
3
|
+
export default defineComponent({
|
|
4
|
+
name: "OgImageWithoutCache",
|
|
5
|
+
async setup(_, { attrs }) {
|
|
6
|
+
if (process.server)
|
|
7
|
+
defineOgImageWithoutCache(attrs);
|
|
8
|
+
return () => null;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { OgImageOptions } from '../../../types';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
|
+
[x: string]: any;
|
|
4
|
+
}, {}>;
|
|
5
|
+
export default _default;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from 'vue'
|
|
3
|
+
import { useSiteConfig } from '#imports'
|
|
4
|
+
|
|
5
|
+
// inherited attrs can mess up the satori parser
|
|
6
|
+
defineOptions({
|
|
7
|
+
inheritAttrs: false,
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
path: String,
|
|
12
|
+
title: {
|
|
13
|
+
type: String,
|
|
14
|
+
default: 'Og Image Template',
|
|
15
|
+
},
|
|
16
|
+
description: {
|
|
17
|
+
type: String,
|
|
18
|
+
default: 'Set a description to change me.',
|
|
19
|
+
},
|
|
20
|
+
color: {
|
|
21
|
+
type: String,
|
|
22
|
+
},
|
|
23
|
+
padding: {
|
|
24
|
+
type: String,
|
|
25
|
+
default: '0 100px',
|
|
26
|
+
},
|
|
27
|
+
titleFontSize: {
|
|
28
|
+
type: String,
|
|
29
|
+
default: '75px',
|
|
30
|
+
},
|
|
31
|
+
descriptionFontSize: {
|
|
32
|
+
type: String,
|
|
33
|
+
default: '35px',
|
|
34
|
+
},
|
|
35
|
+
icon: {
|
|
36
|
+
type: [String, Boolean],
|
|
37
|
+
default: false,
|
|
38
|
+
},
|
|
39
|
+
siteName: {
|
|
40
|
+
type: String,
|
|
41
|
+
required: false,
|
|
42
|
+
},
|
|
43
|
+
siteLogo: {
|
|
44
|
+
type: String,
|
|
45
|
+
required: false,
|
|
46
|
+
},
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
const backgroundAttrs = computed(() => {
|
|
50
|
+
// we want to make a
|
|
51
|
+
// const isBackgroundTw = props.background?.startsWith('bg-')
|
|
52
|
+
return {
|
|
53
|
+
style: {
|
|
54
|
+
display: 'flex',
|
|
55
|
+
position: 'absolute',
|
|
56
|
+
width: '100%',
|
|
57
|
+
height: '100%',
|
|
58
|
+
background: 'rgba(5, 5, 5,1)',
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const backgroundFlareAttrs = computed(() => {
|
|
64
|
+
// we want to make a
|
|
65
|
+
// const isBackgroundTw = props.background?.startsWith('bg-')
|
|
66
|
+
return {
|
|
67
|
+
style: {
|
|
68
|
+
display: 'flex',
|
|
69
|
+
position: 'absolute',
|
|
70
|
+
right: '-100%',
|
|
71
|
+
top: '10%',
|
|
72
|
+
width: '200%',
|
|
73
|
+
height: '200%',
|
|
74
|
+
backgroundImage: 'radial-gradient(circle, rgba(0,220,130, 0.5) 0%, rgba(5, 5, 5,0.3) 50%, rgba(5, 5, 5,0) 70%)',
|
|
75
|
+
},
|
|
76
|
+
}
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const containerAttrs = computed(() => {
|
|
80
|
+
const isColorTw = props.color?.startsWith('text-')
|
|
81
|
+
|
|
82
|
+
const classes = [
|
|
83
|
+
'w-full',
|
|
84
|
+
'h-full',
|
|
85
|
+
'flex',
|
|
86
|
+
'text-gray-100',
|
|
87
|
+
'relative',
|
|
88
|
+
'items-center',
|
|
89
|
+
'justify-center',
|
|
90
|
+
]
|
|
91
|
+
const styles: Record<string, any> = {
|
|
92
|
+
padding: props.padding,
|
|
93
|
+
}
|
|
94
|
+
if (isColorTw)
|
|
95
|
+
classes.push(props.color)
|
|
96
|
+
else
|
|
97
|
+
styles.color = props.color
|
|
98
|
+
return { class: classes, style: styles }
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
const titleAttrs = computed(() => {
|
|
102
|
+
const classes = []
|
|
103
|
+
const styles = {
|
|
104
|
+
fontWeight: 'bold',
|
|
105
|
+
marginBottom: '50px',
|
|
106
|
+
fontSize: props.titleFontSize,
|
|
107
|
+
}
|
|
108
|
+
return { class: classes, style: styles }
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
const descriptionAttrs = computed(() => {
|
|
112
|
+
const classes = []
|
|
113
|
+
const styles = {
|
|
114
|
+
fontSize: props.descriptionFontSize,
|
|
115
|
+
lineHeight: `${props.descriptionFontSize.replace('px', '') * 1.5}px`,
|
|
116
|
+
opacity: '0.8',
|
|
117
|
+
}
|
|
118
|
+
return { class: classes, style: styles }
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
const siteConfig = useSiteConfig()
|
|
122
|
+
const siteName = computed(() => {
|
|
123
|
+
return props.siteName || siteConfig.name
|
|
124
|
+
})
|
|
125
|
+
const siteLogo = computed(() => {
|
|
126
|
+
return props.siteLogo || siteConfig.logo
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
const MaybeIconComponent = resolveComponent('Icon')
|
|
130
|
+
</script>
|
|
131
|
+
|
|
132
|
+
<template>
|
|
133
|
+
<div v-bind="backgroundAttrs" />
|
|
134
|
+
<div v-bind="backgroundFlareAttrs" />
|
|
135
|
+
<div v-bind="containerAttrs">
|
|
136
|
+
<div class="flex flex-row justify-between items-center" style="margin-bottom: 100px;">
|
|
137
|
+
<div class="flex flex-col w-full" :style="icon ? { width: '65%' } : {}">
|
|
138
|
+
<div v-bind="titleAttrs">
|
|
139
|
+
{{ title || 'Null Title' }}
|
|
140
|
+
</div>
|
|
141
|
+
<div v-if="description" v-bind="descriptionAttrs">
|
|
142
|
+
{{ description }}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
<div v-if="typeof icon === 'string' && typeof MaybeIconComponent !== 'string'" style="width: 30%;" class="flex justify-end">
|
|
146
|
+
<MaybeIconComponent :name="icon" size="250px" style="margin: 0 auto 0 100px;opacity: 0.9;" />
|
|
147
|
+
</div>
|
|
148
|
+
</div>
|
|
149
|
+
<div class="flex flex-row absolute bottom-10 text-left items-start">
|
|
150
|
+
<img v-if="siteLogo" :src="siteLogo" height="30">
|
|
151
|
+
<div v-else-if="siteName" style="font-size: 25px;" class="font-bold">
|
|
152
|
+
{{ siteName }}
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</div>
|
|
156
|
+
</template>
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { OgImageOptions, OgImageScreenshotOptions } from '../../types';
|
|
2
|
-
export declare function defineOgImageScreenshot(options?: OgImageScreenshotOptions): void
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
export declare function defineOgImageScreenshot(options?: OgImageScreenshotOptions): Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Use `defineOgImage` or `defineOgImageCached` instead
|
|
5
|
+
*/
|
|
6
|
+
export declare function defineOgImageStatic(options?: OgImageOptions): Promise<void>;
|
|
7
|
+
export declare function defineOgImageCached(options?: OgImageOptions): Promise<void>;
|
|
8
|
+
export declare function defineOgImageWithoutCache(options?: OgImageOptions): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Use `defineOgImageWithoutCache` instead
|
|
11
|
+
*/
|
|
12
|
+
export declare function defineOgImageDynamic(options?: OgImageOptions): Promise<void>;
|
|
13
|
+
export declare function defineOgImage(_options?: OgImageOptions): Promise<void>;
|
|
@@ -1,70 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { useRouter, useRuntimeConfig } from "#imports";
|
|
1
|
+
import { joinURL } from "ufo";
|
|
2
|
+
import { normaliseOgImageOptions } from "./util.mjs";
|
|
3
|
+
import { useRouter, useRuntimeConfig, useServerHead, withSiteUrl } from "#imports";
|
|
5
4
|
export function defineOgImageScreenshot(options = {}) {
|
|
6
5
|
const router = useRouter();
|
|
7
6
|
const route = router?.currentRoute?.value?.path || "";
|
|
8
|
-
defineOgImage({
|
|
7
|
+
return defineOgImage({
|
|
9
8
|
alt: `Web page screenshot${route ? ` of ${route}` : ""}.`,
|
|
10
9
|
provider: "browser",
|
|
11
10
|
component: null,
|
|
12
|
-
|
|
11
|
+
cache: true,
|
|
13
12
|
...options
|
|
14
13
|
});
|
|
15
14
|
}
|
|
16
|
-
export function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
export function defineOgImageStatic(options = {}) {
|
|
16
|
+
return defineOgImageCached(options);
|
|
17
|
+
}
|
|
18
|
+
export function defineOgImageCached(options = {}) {
|
|
19
|
+
const { defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
20
|
+
if (!defaults.cacheTtl && !options.cacheTtl)
|
|
21
|
+
options.cacheTtl = 60 * 60 * 24 * 7;
|
|
22
|
+
return defineOgImage({
|
|
23
|
+
cache: true,
|
|
21
24
|
...options
|
|
22
25
|
});
|
|
23
26
|
}
|
|
24
|
-
export function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
static: true,
|
|
27
|
+
export function defineOgImageWithoutCache(options = {}) {
|
|
28
|
+
return defineOgImage({
|
|
29
|
+
cache: false,
|
|
30
|
+
cacheTtl: 0,
|
|
29
31
|
...options
|
|
30
32
|
});
|
|
31
33
|
}
|
|
32
|
-
export function
|
|
34
|
+
export function defineOgImageDynamic(options = {}) {
|
|
35
|
+
return defineOgImageWithoutCache(options);
|
|
36
|
+
}
|
|
37
|
+
export async function defineOgImage(_options = {}) {
|
|
33
38
|
if (process.server) {
|
|
34
|
-
const
|
|
35
|
-
const
|
|
36
|
-
const route = router?.currentRoute?.value?.path || "";
|
|
37
|
-
const e = useRequestEvent();
|
|
38
|
-
if ((forcePrerender || options.static) && options.provider === "satori")
|
|
39
|
-
e.res.setHeader("x-nitro-prerender", `${route === "/" ? "" : route}/__og_image__/og.png`);
|
|
39
|
+
const options = normaliseOgImageOptions(_options);
|
|
40
|
+
const src = withSiteUrl(joinURL(useRouter().currentRoute.value.path || "", "/__og_image__/og.png"));
|
|
40
41
|
const meta = [
|
|
41
|
-
{
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
name: "twitter:image:src",
|
|
47
|
-
content: () => withBase(`${route === "/" ? "" : route}/__og_image__/og.png`, siteUrl)
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
property: "og:image",
|
|
51
|
-
content: () => withBase(`${route === "/" ? "" : route}/__og_image__/og.png`, siteUrl)
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
property: "og:image:width",
|
|
55
|
-
content: options.width || defaults.width
|
|
56
|
-
},
|
|
57
|
-
{
|
|
58
|
-
property: "og:image:height",
|
|
59
|
-
content: options.height || defaults.height
|
|
60
|
-
}
|
|
42
|
+
{ name: "twitter:card", content: "summary_large_image" },
|
|
43
|
+
{ name: "twitter:image:src", content: src },
|
|
44
|
+
{ property: "og:image", content: src },
|
|
45
|
+
{ property: "og:image:width", content: options.width },
|
|
46
|
+
{ property: "og:image:height", content: options.height }
|
|
61
47
|
];
|
|
62
|
-
if (options.alt)
|
|
63
|
-
meta.push({
|
|
64
|
-
property: "og:image:alt",
|
|
65
|
-
content: options.alt
|
|
66
|
-
});
|
|
67
|
-
}
|
|
48
|
+
if (options.alt)
|
|
49
|
+
meta.push({ property: "og:image:alt", content: options.alt });
|
|
68
50
|
useServerHead({
|
|
69
51
|
meta,
|
|
70
52
|
script: [
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { unref, useRuntimeConfig } from "#imports";
|
|
2
|
+
import { componentNames } from "#build/og-image-component-names.mjs";
|
|
3
|
+
export function normaliseOgImageOptions(_options) {
|
|
4
|
+
const options = { ...unref(_options) };
|
|
5
|
+
if (options.static)
|
|
6
|
+
options.cache = options.cache || options.static;
|
|
7
|
+
if (!options.provider)
|
|
8
|
+
options.provider = "satori";
|
|
9
|
+
const { runtimeSatori } = useRuntimeConfig()["nuxt-og-image"];
|
|
10
|
+
if (options.provider === "satori" && !runtimeSatori)
|
|
11
|
+
options.provider = "browser";
|
|
12
|
+
if (options.component && componentNames) {
|
|
13
|
+
const originalName = options.component;
|
|
14
|
+
let isValid = componentNames.some((component) => component.pascalName === originalName || component.kebabName === originalName);
|
|
15
|
+
if (!isValid) {
|
|
16
|
+
for (const component of componentNames) {
|
|
17
|
+
if (component.pascalName.endsWith(originalName) || component.kebabName.endsWith(originalName)) {
|
|
18
|
+
options.component = component.pascalName;
|
|
19
|
+
isValid = true;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return options;
|
|
26
|
+
}
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import { createError, defineEventHandler, sendRedirect, setHeader } from "h3";
|
|
3
|
+
import { joinURL, parseURL, withoutTrailingSlash } from "ufo";
|
|
4
|
+
import { prefixStorage } from "unstorage";
|
|
5
|
+
import { hash } from "ohash";
|
|
6
|
+
import { fetchOptions } from "../utils.mjs";
|
|
4
7
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
8
|
+
import { useNitroOrigin, useRuntimeConfig, useStorage } from "#imports";
|
|
5
9
|
export default defineEventHandler(async (e) => {
|
|
10
|
+
const { runtimeBrowser, runtimeCacheStorage } = useRuntimeConfig()["nuxt-og-image"];
|
|
6
11
|
const path = parseURL(e.path).pathname;
|
|
7
12
|
if (!path.endsWith("__og_image__/og.png"))
|
|
8
13
|
return;
|
|
9
14
|
const basePath = withoutTrailingSlash(
|
|
10
15
|
path.replace("__og_image__/og.png", "")
|
|
11
16
|
);
|
|
12
|
-
setHeader(e, "Content-Type", "image/png");
|
|
13
|
-
setHeader(e, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
14
|
-
setHeader(e, "Pragma", "no-cache");
|
|
15
|
-
setHeader(e, "Expires", "0");
|
|
16
17
|
const options = await fetchOptions(e, basePath);
|
|
18
|
+
if (process.env.NODE_ENV === "production" && !process.env.prerender && !runtimeBrowser && options.provider === "browser")
|
|
19
|
+
return sendRedirect(e, joinURL(useNitroOrigin(e), "__nuxt_og_image__/browser-provider-not-supported.png"));
|
|
17
20
|
const provider = await useProvider(options.provider);
|
|
18
21
|
if (!provider) {
|
|
19
22
|
throw createError({
|
|
@@ -21,5 +24,48 @@ export default defineEventHandler(async (e) => {
|
|
|
21
24
|
statusMessage: `Provider ${options.provider} is missing.`
|
|
22
25
|
});
|
|
23
26
|
}
|
|
24
|
-
|
|
27
|
+
const useCache = runtimeCacheStorage && !process.dev && options.cacheTtl && options.cacheTtl > 0 && options.cache;
|
|
28
|
+
const baseCacheKey = runtimeCacheStorage === "default" ? "/cache/og-image" : "/og-image";
|
|
29
|
+
const cache = prefixStorage(useStorage(), `${baseCacheKey}/images`);
|
|
30
|
+
const key = [options.path === "/" || !options.path ? "index" : options.path, hash(options)].join(":");
|
|
31
|
+
let png;
|
|
32
|
+
if (useCache && await cache.hasItem(key)) {
|
|
33
|
+
const { value, expiresAt } = await cache.getItem(key);
|
|
34
|
+
if (expiresAt > Date.now()) {
|
|
35
|
+
setHeader(e, "Cache-Control", "public, max-age=31536000");
|
|
36
|
+
setHeader(e, "Content-Type", "image/png");
|
|
37
|
+
png = Buffer.from(value, "base64");
|
|
38
|
+
} else {
|
|
39
|
+
await cache.removeItem(key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (!png) {
|
|
43
|
+
try {
|
|
44
|
+
png = await provider.createPng(options);
|
|
45
|
+
if (useCache && png) {
|
|
46
|
+
const base64png = Buffer.from(png).toString("base64");
|
|
47
|
+
await cache.setItem(key, { value: base64png, expiresAt: Date.now() + (options.cacheTtl || 0) });
|
|
48
|
+
}
|
|
49
|
+
} catch (err) {
|
|
50
|
+
throw createError({
|
|
51
|
+
statusCode: 500,
|
|
52
|
+
statusMessage: `Failed to create og image: ${err.message}`
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (png) {
|
|
57
|
+
if (!process.dev && options.cache) {
|
|
58
|
+
setHeader(e, "Cache-Control", "public, max-age=31536000");
|
|
59
|
+
} else {
|
|
60
|
+
setHeader(e, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
61
|
+
setHeader(e, "Pragma", "no-cache");
|
|
62
|
+
setHeader(e, "Expires", "0");
|
|
63
|
+
}
|
|
64
|
+
setHeader(e, "Content-Type", "image/png");
|
|
65
|
+
return png;
|
|
66
|
+
}
|
|
67
|
+
throw createError({
|
|
68
|
+
statusCode: 500,
|
|
69
|
+
statusMessage: "Failed to create og image, unknown error."
|
|
70
|
+
});
|
|
25
71
|
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { appendHeader } from "h3";
|
|
2
|
+
import { joinURL } from "ufo";
|
|
3
|
+
import { prefixStorage } from "unstorage";
|
|
4
|
+
import { extractOgImageOptions } from "../utils-pure.mjs";
|
|
5
|
+
import { useRuntimeConfig, useStorage } from "#imports";
|
|
6
|
+
const OgImagePrenderNitroPlugin = (nitroApp) => {
|
|
7
|
+
if (!process.env.prerender)
|
|
8
|
+
return;
|
|
9
|
+
const { runtimeCacheStorage } = useRuntimeConfig()["nuxt-og-image"];
|
|
10
|
+
const baseCacheKey = runtimeCacheStorage === "default" ? "/cache/og-image" : "/og-image";
|
|
11
|
+
const cache = prefixStorage(useStorage(), `${baseCacheKey}/options`);
|
|
12
|
+
nitroApp.hooks.hook("render:html", async (ctx, { event }) => {
|
|
13
|
+
const url = event.node.req.url;
|
|
14
|
+
if (url.includes(".") || url.startsWith("/__nuxt_island/"))
|
|
15
|
+
return;
|
|
16
|
+
const options = extractOgImageOptions(ctx.head.join("\n"));
|
|
17
|
+
if (!options)
|
|
18
|
+
return;
|
|
19
|
+
await cache.setItem(url === "/" || !url ? "index" : url, {
|
|
20
|
+
value: JSON.stringify(options),
|
|
21
|
+
expiresAt: Date.now() + 60 * 60 * 1e3
|
|
22
|
+
// 60 minutes to prerender
|
|
23
|
+
});
|
|
24
|
+
if (options.provider === "satori")
|
|
25
|
+
appendHeader(event, "x-nitro-prerender", joinURL(url, "/__og_image__/og.png"));
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
export default OgImagePrenderNitroPlugin;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export default function createBrowser(): Promise<
|
|
1
|
+
export default function createBrowser(): Promise<any>;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import edgeChromium from "chrome-aws-lambda";
|
|
1
|
+
import edgeChromium from "@sparticuz/chrome-aws-lambda";
|
|
2
2
|
import puppeteer from "puppeteer-core";
|
|
3
3
|
export default async function createBrowser() {
|
|
4
|
-
return puppeteer.launch({
|
|
5
|
-
args: edgeChromium.args,
|
|
4
|
+
return await puppeteer.launch({
|
|
6
5
|
executablePath: await edgeChromium.executablePath,
|
|
6
|
+
args: edgeChromium.args,
|
|
7
7
|
headless: true
|
|
8
8
|
});
|
|
9
9
|
}
|
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
import playwrightCore from "playwright-core";
|
|
2
2
|
export default async function createBrowser() {
|
|
3
|
-
try {
|
|
4
|
-
const { Launcher } = await import(String("chrome-launcher"));
|
|
5
|
-
const chromePath = Launcher.getFirstInstallation();
|
|
6
|
-
return await playwrightCore.chromium.launch({
|
|
7
|
-
headless: true,
|
|
8
|
-
executablePath: chromePath
|
|
9
|
-
});
|
|
10
|
-
} catch (e) {
|
|
11
|
-
}
|
|
12
3
|
try {
|
|
13
4
|
return await playwrightCore.chromium.launch({
|
|
14
5
|
headless: true
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function createBrowser(): Promise<any>;
|