nuxt-og-image 2.0.0-beta.6 → 2.0.0-beta.61
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 +311 -97
- package/dist/client/200.html +2 -2
- package/dist/client/404.html +2 -2
- package/dist/client/_nuxt/IconCSS.b41b9663.css +1 -0
- package/dist/client/_nuxt/IconCSS.c2e73ab2.js +1 -0
- package/dist/client/_nuxt/ImageLoader.7571516f.css +1 -0
- package/dist/client/_nuxt/ImageLoader.ed4bfccb.js +1 -0
- package/dist/client/_nuxt/entry.862302d7.css +1 -0
- package/dist/client/_nuxt/entry.f51ac6f7.js +7 -0
- package/dist/client/_nuxt/{error-404.1ff52902.js → error-404.a94c6c21.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.f7d30da5.js → error-500.3955092a.js} +1 -1
- package/dist/client/_nuxt/index.17db8b1a.js +1 -0
- package/dist/client/_nuxt/index.403133d8.css +1 -0
- package/dist/client/_nuxt/options.3e6c211b.js +1 -0
- package/dist/client/_nuxt/png.23a5e57c.js +1 -0
- package/dist/client/_nuxt/{shiki.3a930bb8.js → shiki.2980d306.js} +1 -1
- package/dist/client/_nuxt/svg.a8bba1f1.js +1 -0
- package/dist/client/_nuxt/{vnodes.a799f183.js → vnodes.64d635d6.js} +1 -1
- 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 +402 -141
- package/dist/runtime/browserUtil.d.ts +1 -0
- package/dist/runtime/browserUtil.mjs +10 -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/{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/WithoutCache.d.ts +4 -0
- package/dist/runtime/components/OgImage/WithoutCache.mjs +10 -0
- package/dist/runtime/components/OgImage/_OgImageDynamic.d.ts +8 -0
- package/dist/runtime/components/{OgImageDynamic.mjs → OgImage/_OgImageDynamic.mjs} +3 -3
- package/dist/runtime/components/OgImage/_OgImageStatic.d.ts +8 -0
- package/dist/runtime/components/{OgImageStatic.mjs → OgImage/_OgImageStatic.mjs} +3 -3
- package/dist/runtime/components/{OgImageStatic.d.ts → OgImage/index.d.ts} +2 -2
- package/dist/runtime/components/OgImage/index.mjs +10 -0
- package/dist/runtime/components/OgImageTemplate/Fallback.vue +155 -0
- package/dist/runtime/composables/defineOgImage.d.ts +12 -4
- package/dist/runtime/composables/defineOgImage.mjs +46 -20
- package/dist/runtime/nitro/middleware/og.png.mjs +54 -8
- package/dist/runtime/nitro/middleware/playground.mjs +4 -3
- 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 -10
- 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 +6 -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 -25
- package/dist/runtime/nitro/routes/options.d.ts +2 -2
- package/dist/runtime/nitro/routes/options.mjs +25 -22
- package/dist/runtime/nitro/routes/svg.mjs +5 -3
- package/dist/runtime/nitro/routes/vnode.mjs +5 -3
- package/dist/runtime/nitro/utils-pure.d.ts +3 -2
- package/dist/runtime/nitro/utils-pure.mjs +9 -10
- package/dist/runtime/nitro/utils.d.ts +11 -11
- package/dist/runtime/nitro/utils.mjs +68 -54
- 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.a041aca0.js +0 -1
- package/dist/client/_nuxt/ImageLoader.9bf39d71.js +0 -1
- package/dist/client/_nuxt/entry.74018bda.js +0 -5
- package/dist/client/_nuxt/entry.7a8c1ab2.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.cf7543e5.js +0 -3
- package/dist/client/_nuxt/index.3f356409.js +0 -1
- package/dist/client/_nuxt/options.56a3e5f9.js +0 -1
- package/dist/client/_nuxt/png.37f3e77b.js +0 -1
- package/dist/client/_nuxt/svg.186c6bd1.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,33 +1,65 @@
|
|
|
1
1
|
import { withBase } from "ufo";
|
|
2
2
|
import { renderSSRHead } from "@unhead/ssr";
|
|
3
3
|
import { createHeadCore } from "@unhead/vue";
|
|
4
|
-
import { defineEventHandler, getQuery, sendRedirect } from "h3";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
4
|
+
import { createError, defineEventHandler, getQuery, sendRedirect } from "h3";
|
|
5
|
+
import { hash } from "ohash";
|
|
6
|
+
import twemoji from "twemoji";
|
|
7
|
+
import { fetchOptions } from "../utils.mjs";
|
|
8
|
+
import { useNitroOrigin, useRuntimeConfig } from "#imports";
|
|
7
9
|
export default defineEventHandler(async (e) => {
|
|
8
|
-
const { fonts, defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const { fonts, defaults, satoriOptions } = useRuntimeConfig()["nuxt-og-image"];
|
|
11
|
+
const query = getQuery(e);
|
|
12
|
+
const path = withBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
13
|
+
const scale = query.scale;
|
|
14
|
+
const mode = query.mode || "light";
|
|
12
15
|
let options;
|
|
13
|
-
if (
|
|
14
|
-
|
|
16
|
+
if (query.options) {
|
|
17
|
+
try {
|
|
18
|
+
options = JSON.parse(query.options);
|
|
19
|
+
} catch {
|
|
20
|
+
}
|
|
21
|
+
}
|
|
15
22
|
if (!options)
|
|
16
23
|
options = await fetchOptions(e, path);
|
|
17
|
-
if (options.provider === "browser" && !options.component)
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
if (options.provider === "browser" && !options.component) {
|
|
25
|
+
const pathWithoutBase = path.replace(new RegExp(`^${useRuntimeConfig().app.baseURL}`), "");
|
|
26
|
+
return sendRedirect(e, withBase(pathWithoutBase, useNitroOrigin(e)));
|
|
27
|
+
}
|
|
28
|
+
if (!options.component) {
|
|
29
|
+
throw createError({
|
|
30
|
+
statusCode: 500,
|
|
31
|
+
statusMessage: `Nuxt OG Image trying to render an invalid component. Received options ${JSON.stringify(options)}`
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const hashId = hash([options.component, options]);
|
|
35
|
+
const island = await $fetch(`/__nuxt_island/${options.component}_${hashId}`, {
|
|
36
|
+
params: {
|
|
37
|
+
props: JSON.stringify(options)
|
|
38
|
+
}
|
|
39
|
+
});
|
|
20
40
|
const head = createHeadCore();
|
|
21
41
|
head.push(island.head);
|
|
42
|
+
let defaultFontFamily = "sans-serif";
|
|
43
|
+
const firstFont = fonts[0];
|
|
44
|
+
if (firstFont)
|
|
45
|
+
defaultFontFamily = firstFont.name;
|
|
46
|
+
let html = island.html;
|
|
47
|
+
try {
|
|
48
|
+
html = twemoji.parse(html, {
|
|
49
|
+
folder: "svg",
|
|
50
|
+
ext: ".svg"
|
|
51
|
+
});
|
|
52
|
+
} catch (e2) {
|
|
53
|
+
}
|
|
22
54
|
head.push({
|
|
23
55
|
style: [
|
|
24
56
|
{
|
|
25
57
|
// default font is the first font family
|
|
26
|
-
innerHTML: `body { font-family: '${
|
|
58
|
+
innerHTML: `body { font-family: '${defaultFontFamily.replace("+", " ")}', sans-serif; }`
|
|
27
59
|
},
|
|
28
|
-
|
|
60
|
+
{
|
|
29
61
|
innerHTML: `body {
|
|
30
|
-
transform: scale(${scale});
|
|
62
|
+
transform: scale(${scale || 1});
|
|
31
63
|
transform-origin: top left;
|
|
32
64
|
max-height: 100vh;
|
|
33
65
|
position: relative;
|
|
@@ -41,9 +73,18 @@ img.emoji {
|
|
|
41
73
|
width: 1em;
|
|
42
74
|
margin: 0 .05em 0 .1em;
|
|
43
75
|
vertical-align: -0.1em;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
76
|
+
}`
|
|
77
|
+
},
|
|
78
|
+
...fonts.filter((font) => font.path).map((font) => {
|
|
79
|
+
return `
|
|
80
|
+
@font-face {
|
|
81
|
+
font-family: '${font.name}';
|
|
82
|
+
font-style: normal;
|
|
83
|
+
font-weight: ${font.weight};
|
|
84
|
+
src: url('${font.path}') format('truetype');
|
|
85
|
+
}
|
|
86
|
+
`;
|
|
87
|
+
})
|
|
47
88
|
],
|
|
48
89
|
meta: [
|
|
49
90
|
{
|
|
@@ -54,12 +95,12 @@ img.emoji {
|
|
|
54
95
|
{
|
|
55
96
|
src: "https://cdn.tailwindcss.com"
|
|
56
97
|
},
|
|
57
|
-
// @todo merge with users tailwind
|
|
58
98
|
{
|
|
59
99
|
innerHTML: `tailwind.config = {
|
|
60
100
|
corePlugins: {
|
|
61
101
|
preflight: false,
|
|
62
|
-
}
|
|
102
|
+
},
|
|
103
|
+
theme: ${JSON.stringify(satoriOptions?.tailwindConfig?.theme || {})}
|
|
63
104
|
}`
|
|
64
105
|
}
|
|
65
106
|
],
|
|
@@ -70,19 +111,53 @@ img.emoji {
|
|
|
70
111
|
rel: "stylesheet"
|
|
71
112
|
},
|
|
72
113
|
// have to add each weight as their own stylesheet
|
|
73
|
-
...fonts.map((font) => {
|
|
74
|
-
const [name, weight] = font.split(":");
|
|
114
|
+
...fonts.filter((font) => !font.path).map((font) => {
|
|
75
115
|
return {
|
|
76
|
-
href: `https://fonts.googleapis.com/css2?family=${name}:wght@${weight}&display=swap`,
|
|
116
|
+
href: `https://fonts.googleapis.com/css2?family=${font.name}:wght@${font.weight}&display=swap`,
|
|
77
117
|
rel: "stylesheet"
|
|
78
118
|
};
|
|
79
119
|
})
|
|
80
120
|
]
|
|
81
121
|
});
|
|
82
122
|
const headChunk = await renderSSRHead(head);
|
|
83
|
-
|
|
123
|
+
let htmlTemplate = `<!DOCTYPE html>
|
|
84
124
|
<html ${headChunk.htmlAttrs}>
|
|
85
125
|
<head>${headChunk.headTags}</head>
|
|
86
|
-
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="position: relative; display: flex; margin: 0 auto; width: 1200px; height: 630px;">${
|
|
126
|
+
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="position: relative; display: flex; margin: 0 auto; width: 1200px; height: 630px;">${html}</div>${headChunk.bodyTags}</body>
|
|
87
127
|
</html>`;
|
|
128
|
+
let hasInlineStyles = false;
|
|
129
|
+
const stylesheets = htmlTemplate.match(/<link rel="stylesheet" href=".*?">/g);
|
|
130
|
+
if (stylesheets) {
|
|
131
|
+
for (const stylesheet of stylesheets) {
|
|
132
|
+
if (!stylesheet.includes(`${options.component}.vue`)) {
|
|
133
|
+
htmlTemplate = htmlTemplate.replace(stylesheet, "");
|
|
134
|
+
} else {
|
|
135
|
+
const href = stylesheet.match(/href="(.*?)"/)[1];
|
|
136
|
+
try {
|
|
137
|
+
let css = await (await $fetch(href, {
|
|
138
|
+
baseURL: useNitroOrigin(e)
|
|
139
|
+
})).text();
|
|
140
|
+
if (css.includes("const __vite__css =")) {
|
|
141
|
+
css = css.match(/const __vite__css = "(.*)"/)[1].replace(/\\n/g, "\n");
|
|
142
|
+
}
|
|
143
|
+
htmlTemplate = htmlTemplate.replace(stylesheet, `<style>${css.replace(/\/\/# sourceMappingURL=.*/, "")}</style>`);
|
|
144
|
+
hasInlineStyles = true;
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
if (hasInlineStyles) {
|
|
152
|
+
const inlineCss = await import("inline-css").then((m) => m?.default || m);
|
|
153
|
+
htmlTemplate = inlineCss(htmlTemplate, {
|
|
154
|
+
url: useNitroOrigin(e),
|
|
155
|
+
applyLinkTags: false,
|
|
156
|
+
removeLinkTags: false,
|
|
157
|
+
removeStyleTags: false
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
}
|
|
162
|
+
return htmlTemplate;
|
|
88
163
|
});
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
declare const _default: import("h3").EventHandler<false |
|
|
1
|
+
import type { RuntimeOgImageOptions } from '../../../types';
|
|
2
|
+
declare const _default: import("h3").EventHandler<false | RuntimeOgImageOptions>;
|
|
3
3
|
export default _default;
|
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import { createError, defineEventHandler,
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createError, defineEventHandler, getQuery } from "h3";
|
|
2
|
+
import { withoutBase } from "ufo";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import { extractOgImageOptions } from "../utils.mjs";
|
|
5
|
+
import { getRouteRules } from "#internal/nitro";
|
|
6
|
+
import { useRuntimeConfig } from "#imports";
|
|
4
7
|
export default defineEventHandler(async (e) => {
|
|
5
8
|
const query = getQuery(e);
|
|
6
|
-
const path = query.path || "/";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
const path = withoutBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
10
|
+
let html;
|
|
11
|
+
try {
|
|
12
|
+
html = await globalThis.$fetch(path);
|
|
13
|
+
} catch (err) {
|
|
14
|
+
throw createError({
|
|
15
|
+
statusCode: 500,
|
|
16
|
+
statusMessage: `Failed to read the path ${path} for og-image extraction. ${err.message}.`
|
|
17
|
+
});
|
|
18
|
+
}
|
|
15
19
|
const extractedPayload = extractOgImageOptions(html);
|
|
16
20
|
if (!extractedPayload) {
|
|
17
21
|
throw createError({
|
|
@@ -20,20 +24,19 @@ export default defineEventHandler(async (e) => {
|
|
|
20
24
|
});
|
|
21
25
|
}
|
|
22
26
|
e.node.req.url = path;
|
|
27
|
+
const oldRouteRules = e.context._nitro.routeRules;
|
|
23
28
|
e.context._nitro.routeRules = void 0;
|
|
24
29
|
const routeRules = getRouteRules(e)?.ogImage;
|
|
30
|
+
e.context._nitro.routeRules = oldRouteRules;
|
|
25
31
|
e.node.req.url = e.path;
|
|
26
32
|
if (routeRules === false)
|
|
27
33
|
return false;
|
|
28
34
|
const { defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
29
|
-
return
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
// use query data
|
|
37
|
-
...query
|
|
38
|
-
};
|
|
35
|
+
return defu(
|
|
36
|
+
extractedPayload,
|
|
37
|
+
routeRules,
|
|
38
|
+
// runtime options
|
|
39
|
+
{ path },
|
|
40
|
+
defaults
|
|
41
|
+
);
|
|
39
42
|
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getQuery, setHeader } from "h3";
|
|
2
2
|
import { withBase } from "ufo";
|
|
3
|
-
import { fetchOptions
|
|
3
|
+
import { fetchOptions } from "../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
6
|
export default defineEventHandler(async (e) => {
|
|
6
|
-
const
|
|
7
|
+
const query = getQuery(e);
|
|
8
|
+
const path = withBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
7
9
|
const options = await fetchOptions(e, path);
|
|
8
10
|
setHeader(e, "Content-Type", "image/svg+xml");
|
|
9
11
|
const provider = await useProvider(options.provider);
|
|
@@ -13,5 +15,5 @@ export default defineEventHandler(async (e) => {
|
|
|
13
15
|
statusMessage: `Provider ${options.provider} is missing.`
|
|
14
16
|
});
|
|
15
17
|
}
|
|
16
|
-
return provider.createSvg(
|
|
18
|
+
return provider.createSvg(options);
|
|
17
19
|
});
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createError, defineEventHandler, getQuery, setHeader } from "h3";
|
|
2
2
|
import { withBase } from "ufo";
|
|
3
|
-
import { fetchOptions
|
|
3
|
+
import { fetchOptions } from "../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
|
+
import { useRuntimeConfig } from "#imports";
|
|
5
6
|
export default defineEventHandler(async (e) => {
|
|
6
|
-
const
|
|
7
|
+
const query = getQuery(e);
|
|
8
|
+
const path = withBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
7
9
|
const options = await fetchOptions(e, path);
|
|
8
10
|
setHeader(e, "Content-Type", "application/json");
|
|
9
11
|
const provider = await useProvider(options.provider);
|
|
@@ -13,5 +15,5 @@ export default defineEventHandler(async (e) => {
|
|
|
13
15
|
statusMessage: `Provider ${options.provider} is missing.`
|
|
14
16
|
});
|
|
15
17
|
}
|
|
16
|
-
return provider.createVNode(
|
|
18
|
+
return provider.createVNode(options);
|
|
17
19
|
});
|
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
export declare function
|
|
1
|
+
import type { OgImageOptions } from '../../types';
|
|
2
|
+
export declare function decodeHtml(html: string): string;
|
|
3
|
+
export declare function extractOgImageOptions(html: string): OgImageOptions | false;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
function
|
|
1
|
+
export function decodeHtml(html) {
|
|
2
|
+
return html.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/¢/g, "\xA2").replace(/£/g, "\xA3").replace(/¥/g, "\xA5").replace(/€/g, "\u20AC").replace(/©/g, "\xA9").replace(/®/g, "\xAE").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(///g, "/").replace(/&#([0-9]+);/g, (full, int) => {
|
|
3
|
+
return String.fromCharCode(Number.parseInt(int));
|
|
4
|
+
});
|
|
5
|
+
}
|
|
6
|
+
function decodeObjectHtmlEntities(obj) {
|
|
2
7
|
Object.entries(obj).forEach(([key, value]) => {
|
|
3
|
-
if (typeof value === "string")
|
|
4
|
-
obj[key] = value
|
|
5
|
-
return String.fromCharCode(parseInt(int));
|
|
6
|
-
});
|
|
7
|
-
}
|
|
8
|
+
if (typeof value === "string")
|
|
9
|
+
obj[key] = decodeHtml(value);
|
|
8
10
|
});
|
|
9
11
|
return obj;
|
|
10
12
|
}
|
|
@@ -28,10 +30,7 @@ export function extractOgImageOptions(html) {
|
|
|
28
30
|
else
|
|
29
31
|
options.description = html.match(/<meta name="description" content="(.*?)">/)?.[1];
|
|
30
32
|
}
|
|
31
|
-
return
|
|
33
|
+
return decodeObjectHtmlEntities(options);
|
|
32
34
|
}
|
|
33
35
|
return false;
|
|
34
36
|
}
|
|
35
|
-
export function stripOgImageOptions(html) {
|
|
36
|
-
return html.replace(/<script id="nuxt-og-image-options" type="application\/json">(.*?)<\/script>/, "");
|
|
37
|
-
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import { Buffer } from 'node:buffer';
|
|
2
3
|
import type { H3Event } from 'h3';
|
|
3
|
-
import type {
|
|
4
|
-
export declare function wasmLoader(
|
|
5
|
-
|
|
6
|
-
load(): Promise<any>;
|
|
4
|
+
import type { RuntimeOgImageOptions } from '../../types';
|
|
5
|
+
export declare function wasmLoader(asyncModuleLoad: Promise<any> | Buffer | string, fallback: string): {
|
|
6
|
+
load(options: RuntimeOgImageOptions): Promise<any>;
|
|
7
7
|
};
|
|
8
|
-
export declare function fetchOptions(e: H3Event, path: string): Promise<
|
|
8
|
+
export declare function fetchOptions(e: H3Event, path: string): Promise<RuntimeOgImageOptions>;
|
|
9
9
|
export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
|
|
10
|
-
export declare function renderIsland(payload: OgImageOptions): Promise<{
|
|
11
|
-
html: string;
|
|
12
|
-
head: any;
|
|
13
|
-
}>;
|
|
14
|
-
export declare function useHostname(e: H3Event): any;
|
|
15
10
|
export declare function readPublicAsset(file: string, encoding?: BufferEncoding): Promise<string | Buffer | undefined>;
|
|
16
|
-
export declare function readPublicAssetBase64(file: string): Promise<
|
|
11
|
+
export declare function readPublicAssetBase64(file: string): Promise<{
|
|
12
|
+
src: string;
|
|
13
|
+
width?: number;
|
|
14
|
+
height?: number;
|
|
15
|
+
} | undefined>;
|
|
16
|
+
export declare function toBase64Image(fileName: string, data: string | ArrayBuffer): string;
|
|
17
17
|
export * from './utils-pure';
|
|
@@ -1,77 +1,83 @@
|
|
|
1
1
|
import { existsSync, promises as fsp } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
3
|
+
import { getQuery } from "h3";
|
|
3
4
|
import { join } from "pathe";
|
|
4
|
-
import {
|
|
5
|
-
|
|
5
|
+
import { prefixStorage } from "unstorage";
|
|
6
|
+
import sizeOf from "image-size";
|
|
7
|
+
import { useNitroOrigin, useRuntimeConfig, useStorage } from "#imports";
|
|
8
|
+
export function wasmLoader(asyncModuleLoad, fallback) {
|
|
6
9
|
let promise;
|
|
7
|
-
let
|
|
10
|
+
let wasm;
|
|
8
11
|
return {
|
|
9
|
-
|
|
10
|
-
if (loaded)
|
|
11
|
-
return true;
|
|
12
|
+
async load(options) {
|
|
12
13
|
if (typeof promise !== "undefined")
|
|
13
14
|
return promise;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
async load() {
|
|
15
|
+
if (wasm)
|
|
16
|
+
return wasm;
|
|
17
17
|
promise = promise || new Promise(async (resolve) => {
|
|
18
|
-
let wasm;
|
|
19
18
|
try {
|
|
20
|
-
wasm = await
|
|
19
|
+
wasm = await asyncModuleLoad;
|
|
21
20
|
if (typeof wasm === "string")
|
|
22
21
|
wasm = void 0;
|
|
23
22
|
} catch (e) {
|
|
24
23
|
}
|
|
25
|
-
if (!wasm)
|
|
26
|
-
wasm = await readPublicAsset(fallback);
|
|
27
24
|
if (!wasm) {
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
wasm = await readPublicAsset(fallback, "base64");
|
|
26
|
+
if (wasm)
|
|
27
|
+
wasm = Buffer.from(wasm, "base64");
|
|
28
|
+
}
|
|
29
|
+
if (!wasm) {
|
|
30
|
+
wasm = await (await globalThis.$fetch(fallback, { baseURL: options.requestOrigin })).arrayBuffer();
|
|
31
|
+
wasm = Buffer.from(wasm);
|
|
30
32
|
}
|
|
31
|
-
loaded = true;
|
|
32
33
|
resolve(wasm);
|
|
33
34
|
});
|
|
34
35
|
return promise;
|
|
35
36
|
}
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
|
-
export function fetchOptions(e, path) {
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
} :
|
|
42
|
-
|
|
39
|
+
export async function fetchOptions(e, path) {
|
|
40
|
+
const { runtimeCacheStorage } = useRuntimeConfig()["nuxt-og-image"];
|
|
41
|
+
const baseCacheKey = runtimeCacheStorage === "default" ? "/cache/og-image" : "/og-image";
|
|
42
|
+
const cache = runtimeCacheStorage || process.env.prerender ? prefixStorage(useStorage(), `${baseCacheKey}/options`) : false;
|
|
43
|
+
let key = e.node.req.url.replace("/__og_image__/og.png", "");
|
|
44
|
+
key = key === "/" || !key ? "index" : key;
|
|
45
|
+
let options;
|
|
46
|
+
if (!process.dev && cache && await cache.hasItem(key)) {
|
|
47
|
+
const cachedValue = await cache.getItem(key);
|
|
48
|
+
if (cachedValue && cachedValue.value && cachedValue.expiresAt < Date.now())
|
|
49
|
+
options = cachedValue.value;
|
|
50
|
+
else
|
|
51
|
+
await cache.removeItem(key);
|
|
52
|
+
}
|
|
53
|
+
if (!options) {
|
|
54
|
+
options = await globalThis.$fetch("/api/og-image-options", {
|
|
55
|
+
query: {
|
|
56
|
+
path
|
|
57
|
+
},
|
|
58
|
+
responseType: "json"
|
|
59
|
+
});
|
|
60
|
+
if (cache) {
|
|
61
|
+
await cache.setItem(key, {
|
|
62
|
+
value: options,
|
|
63
|
+
expiresAt: Date.now() + (options.cache ? 60 * 60 * 1e3 : 5 * 1e3)
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...options,
|
|
69
|
+
// use query data
|
|
70
|
+
...getQuery(e),
|
|
71
|
+
requestOrigin: useNitroOrigin(e)
|
|
43
72
|
};
|
|
44
|
-
return globalThis.$fetch("/api/og-image-options", {
|
|
45
|
-
query: {
|
|
46
|
-
...getQuery(e),
|
|
47
|
-
path
|
|
48
|
-
},
|
|
49
|
-
...fetchOptions2
|
|
50
|
-
});
|
|
51
73
|
}
|
|
52
74
|
export function base64ToArrayBuffer(base64) {
|
|
53
75
|
const buffer = Buffer.from(base64, "base64");
|
|
54
76
|
return new Uint8Array(buffer).buffer;
|
|
55
77
|
}
|
|
56
|
-
|
|
57
|
-
return globalThis.$fetch(`/__nuxt_island/${payload.component}`, {
|
|
58
|
-
query: { props: JSON.stringify(payload) }
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
export function useHostname(e) {
|
|
62
|
-
const config = useRuntimeConfig()["nuxt-og-image"];
|
|
63
|
-
if (!process.dev && config.siteUrl)
|
|
64
|
-
return config.siteUrl;
|
|
65
|
-
const host = getRequestHeader(e, "host") || process.env.NITRO_HOST || process.env.HOST || "localhost";
|
|
66
|
-
const protocol = getRequestHeader(e, "x-forwarded-proto") || "http";
|
|
67
|
-
const useHttp = process.env.NODE_ENV === "development" || host.includes("127.0.0.1") || host.includes("localhost") || protocol === "http";
|
|
68
|
-
const port = host.includes(":") ? host.split(":").pop() : process.env.NITRO_PORT || process.env.PORT;
|
|
69
|
-
const base = useRuntimeConfig().app.baseURL;
|
|
70
|
-
return `http${useHttp ? "" : "s"}://${host.includes(":") ? host.split(":")[0] : host}${port ? `:${port}` : ""}${base}`;
|
|
71
|
-
}
|
|
72
|
-
const r = (base, key) => {
|
|
78
|
+
function r(base, key) {
|
|
73
79
|
return join(base, key.replace(/:/g, "/"));
|
|
74
|
-
}
|
|
80
|
+
}
|
|
75
81
|
export async function readPublicAsset(file, encoding) {
|
|
76
82
|
const { assetDirs } = useRuntimeConfig()["nuxt-og-image"];
|
|
77
83
|
for (const assetDir of assetDirs) {
|
|
@@ -83,13 +89,21 @@ export async function readPublicAsset(file, encoding) {
|
|
|
83
89
|
export async function readPublicAssetBase64(file) {
|
|
84
90
|
const base64 = await readPublicAsset(file, "base64");
|
|
85
91
|
if (base64) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
type = "image/png";
|
|
92
|
-
return `data:${type};base64,${base64}`;
|
|
92
|
+
const dimensions = await sizeOf(Buffer.from(base64, "base64"));
|
|
93
|
+
return {
|
|
94
|
+
src: toBase64Image(file, base64),
|
|
95
|
+
...dimensions
|
|
96
|
+
};
|
|
93
97
|
}
|
|
94
98
|
}
|
|
99
|
+
export function toBase64Image(fileName, data) {
|
|
100
|
+
const base64 = typeof data === "string" ? data : Buffer.from(data).toString("base64");
|
|
101
|
+
let type = "image/jpeg";
|
|
102
|
+
const ext = fileName.split(".").pop();
|
|
103
|
+
if (ext === "svg")
|
|
104
|
+
type = "image/svg+xml";
|
|
105
|
+
else if (ext === "png")
|
|
106
|
+
type = "image/png";
|
|
107
|
+
return `data:${type};base64,${base64}`;
|
|
108
|
+
}
|
|
95
109
|
export * from "./utils-pure.mjs";
|
|
Binary file
|
|
Binary file
|
package/dist/types.d.ts
CHANGED
|
@@ -7,5 +7,11 @@ declare module '@nuxt/schema' {
|
|
|
7
7
|
interface NuxtHooks extends ModuleHooks {}
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
declare module 'nuxt/schema' {
|
|
11
|
+
interface NuxtConfig { ['ogImage']?: Partial<ModuleOptions> }
|
|
12
|
+
interface NuxtOptions { ['ogImage']?: ModuleOptions }
|
|
13
|
+
interface NuxtHooks extends ModuleHooks {}
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
|
|
11
17
|
export { ModuleHooks, ModuleOptions, default } from './module'
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-og-image",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
5
|
-
"packageManager": "pnpm@
|
|
4
|
+
"version": "2.0.0-beta.61",
|
|
5
|
+
"packageManager": "pnpm@8.6.0",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://github.com/sponsors/harlan-zw",
|
|
8
8
|
"homepage": "https://github.com/harlan-zw/nuxt-og-image#readme",
|
|
@@ -26,45 +26,56 @@
|
|
|
26
26
|
"dist"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@nuxt/kit": "3.
|
|
29
|
+
"@nuxt/kit": "^3.6.1",
|
|
30
|
+
"@resvg/resvg-js": "^2.4.1",
|
|
31
|
+
"@resvg/resvg-wasm": "^2.4.1",
|
|
30
32
|
"@types/fs-extra": "^11.0.1",
|
|
31
|
-
"birpc": "^0.2.
|
|
32
|
-
"chalk": "^5.
|
|
33
|
-
"chrome-launcher": "^0.15.
|
|
33
|
+
"birpc": "^0.2.12",
|
|
34
|
+
"chalk": "^5.3.0",
|
|
35
|
+
"chrome-launcher": "^0.15.2",
|
|
34
36
|
"defu": "^6.1.2",
|
|
35
37
|
"execa": "^7.1.1",
|
|
36
|
-
"fast-glob": "^3.
|
|
38
|
+
"fast-glob": "^3.3.0",
|
|
37
39
|
"flatted": "^3.2.7",
|
|
38
40
|
"fs-extra": "^11.1.1",
|
|
41
|
+
"globby": "^13.2.1",
|
|
42
|
+
"image-size": "^1.0.2",
|
|
43
|
+
"inline-css": "^4.0.2",
|
|
39
44
|
"launch-editor": "^2.6.0",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
+
"nuxt-icon": "^0.4.2",
|
|
46
|
+
"nuxt-site-config": "^0.7.5",
|
|
47
|
+
"nuxt-site-config-kit": "^0.7.5",
|
|
48
|
+
"nypm": "^0.2.2",
|
|
49
|
+
"ofetch": "^1.1.1",
|
|
50
|
+
"ohash": "^1.1.2",
|
|
51
|
+
"pathe": "^1.1.1",
|
|
52
|
+
"playwright-core": "^1.35.1",
|
|
53
|
+
"radix3": "^1.0.1",
|
|
54
|
+
"satori": "0.10.1",
|
|
45
55
|
"satori-html": "^0.3.2",
|
|
46
|
-
"sirv": "^2.0.
|
|
47
|
-
"std-env": "^3.3.
|
|
48
|
-
"svg2png-wasm": "^1.
|
|
56
|
+
"sirv": "^2.0.3",
|
|
57
|
+
"std-env": "^3.3.3",
|
|
58
|
+
"svg2png-wasm": "^1.4.0",
|
|
49
59
|
"tinyws": "^0.1.0",
|
|
50
60
|
"twemoji": "^14.0.2",
|
|
51
|
-
"ufo": "^1.1.
|
|
61
|
+
"ufo": "^1.1.2",
|
|
52
62
|
"ws": "^8.13.0",
|
|
53
63
|
"yoga-wasm-web": "^0.3.3"
|
|
54
64
|
},
|
|
55
65
|
"devDependencies": {
|
|
56
|
-
"@antfu/eslint-config": "^0.
|
|
57
|
-
"@nuxt/devtools-edge": "0.
|
|
58
|
-
"@nuxt/module-builder": "^0.
|
|
59
|
-
"@nuxt/test-utils": "3.
|
|
66
|
+
"@antfu/eslint-config": "^0.39.6",
|
|
67
|
+
"@nuxt/devtools-edge": "0.6.6-28135918.e26a136",
|
|
68
|
+
"@nuxt/module-builder": "^0.4.0",
|
|
69
|
+
"@nuxt/test-utils": "3.6.1",
|
|
60
70
|
"@nuxtjs/eslint-config-typescript": "^12.0.0",
|
|
61
|
-
"@types/ws": "^8.5.
|
|
62
|
-
"bumpp": "^9.
|
|
63
|
-
"eslint": "8.
|
|
71
|
+
"@types/ws": "^8.5.5",
|
|
72
|
+
"bumpp": "^9.1.1",
|
|
73
|
+
"eslint": "8.44.0",
|
|
64
74
|
"jest-image-snapshot": "^6.1.0",
|
|
65
|
-
"nuxt": "^3.
|
|
66
|
-
"
|
|
67
|
-
"
|
|
75
|
+
"nuxt": "^3.6.1",
|
|
76
|
+
"playwright": "^1.35.1",
|
|
77
|
+
"sass": "^1.63.6",
|
|
78
|
+
"vitest": "^0.32.2"
|
|
68
79
|
},
|
|
69
80
|
"scripts": {
|
|
70
81
|
"build": "pnpm dev:prepare && pnpm build:module && pnpm build:client",
|
|
@@ -75,6 +86,6 @@
|
|
|
75
86
|
"dev:build": "nuxi build .playground",
|
|
76
87
|
"dev:prepare": "nuxt-module-build --stub && nuxi prepare .playground",
|
|
77
88
|
"release": "bumpp package.json --commit --push --tag",
|
|
78
|
-
"test": "
|
|
89
|
+
"test": "vitest"
|
|
79
90
|
}
|
|
80
91
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as p,b as u,e as l,f as t,o as f,h as m,i as _,u as o,j as d}from"./entry.74018bda.js";const x=p({__name:"IconCSS",props:{name:{type:String,required:!0},size:{type:String,default:""}},setup(c){const s=c;u(e=>({"387181c2":o(r)}));const n=l();n?.nuxtIcon?.aliases;const i=t(()=>(n?.nuxtIcon?.aliases||{})[s.name]||s.name),r=t(()=>`url('https://api.iconify.design/${i.value.replace(":","/")}.svg')`),a=t(()=>{if(!s.size&&typeof n.nuxtIcon?.size=="boolean"&&!n.nuxtIcon?.size)return;const e=s.size||n.nuxtIcon?.size||"1em";return String(Number(e))===e?`${e}px`:e});return(e,z)=>(f(),m("span",{style:_({width:o(a),height:o(a)})},null,4))}}),g=d(x,[["__scopeId","data-v-3c47f034"]]);export{g as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as m,r as c,m as u,w as r,f as d,s as _,o as f,h as g,i as y,j as v}from"./entry.74018bda.js";const h=m({__name:"ImageLoader",props:{src:String,aspectRatio:Number,description:String},setup(a){const s=a,n=c(),o=c(0);function i(e){const t=n.value,p=Date.now();t.src="",o.value=0,t.style.opacity="0",t.onload=()=>{t.style.opacity="1",o.value=Date.now()-p},t.src=e}u(()=>{r(()=>s.src,e=>{i(e)},{immediate:!0})});const l=d(()=>s.description.replace("%s",o.value.toString()));return r(l,e=>{_.value=e}),(e,t)=>(f(),g("img",{ref_key:"image",ref:n,class:"max-h-full border-1 border-light-500 rounded",style:y({aspectRatio:a.aspectRatio})},null,4))}}),x=v(h,[["__scopeId","data-v-23ec6856"]]);export{x as _};
|