nuxt-og-image 2.0.0-beta.9 → 2.0.1
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.685477c5.js +1 -0
- package/dist/client/_nuxt/IconCSS.b41b9663.css +1 -0
- package/dist/client/_nuxt/ImageLoader.7571516f.css +1 -0
- package/dist/client/_nuxt/ImageLoader.fb4e5eb3.js +1 -0
- package/dist/client/_nuxt/entry.0fc037e0.js +143 -0
- package/dist/client/_nuxt/entry.1311cc29.css +1 -0
- package/dist/client/_nuxt/{error-404.02537f9e.js → error-404.068f19dd.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.a60bf0b5.js → error-500.4d72610e.js} +1 -1
- package/dist/client/_nuxt/index.33389497.js +1 -0
- package/dist/client/_nuxt/index.ffbea0a9.css +1 -0
- package/dist/client/_nuxt/options.e1a971ea.js +1 -0
- package/dist/client/_nuxt/png.110ab8f5.js +1 -0
- package/dist/client/_nuxt/{shiki.aace8ca2.js → shiki.3fe159de.js} +1 -1
- package/dist/client/_nuxt/svg.1a58cdf3.js +1 -0
- package/dist/client/_nuxt/vnodes.42fbc6e6.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 +117 -11
- package/dist/module.json +2 -2
- package/dist/module.mjs +391 -114
- 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/inline-css/mock.d.ts +5 -0
- package/dist/runtime/nitro/providers/inline-css/mock.mjs +3 -0
- package/dist/runtime/nitro/providers/inline-css/node.d.ts +5 -0
- package/dist/runtime/nitro/providers/inline-css/node.mjs +11 -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 +102 -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 +0 -1
- 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.ef0613e7.js +0 -1
- package/dist/client/_nuxt/ImageLoader.a4418cab.js +0 -1
- package/dist/client/_nuxt/entry.09f25aaf.css +0 -1
- package/dist/client/_nuxt/entry.fc9150b0.js +0 -5
- 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.8148b615.js +0 -3
- package/dist/client/_nuxt/index.80f38ec7.js +0 -1
- package/dist/client/_nuxt/options.cc3fd02b.js +0 -1
- package/dist/client/_nuxt/png.62758167.js +0 -1
- package/dist/client/_nuxt/svg.853cdaad.js +0 -1
- package/dist/client/_nuxt/vnodes.69b24963.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,41 +1,74 @@
|
|
|
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 { defu } from "defu";
|
|
8
|
+
import { fetchOptions } from "../utils.mjs";
|
|
9
|
+
import { useNitroOrigin, useRuntimeConfig } from "#imports";
|
|
10
|
+
import loadInlineCSS from "#nuxt-og-image/inline-css";
|
|
7
11
|
export default defineEventHandler(async (e) => {
|
|
8
|
-
const { fonts,
|
|
12
|
+
const { fonts, satoriOptions } = useRuntimeConfig()["nuxt-og-image"];
|
|
9
13
|
const query = getQuery(e);
|
|
10
14
|
const path = withBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
11
15
|
const scale = query.scale;
|
|
12
16
|
const mode = query.mode || "light";
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const nitroOrigin = useNitroOrigin(e);
|
|
18
|
+
let queryOptions;
|
|
19
|
+
if (query.options) {
|
|
20
|
+
try {
|
|
21
|
+
queryOptions = JSON.parse(query.options);
|
|
22
|
+
} catch {
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
let options = await fetchOptions(e, path);
|
|
26
|
+
if (queryOptions)
|
|
27
|
+
options = defu(queryOptions, options);
|
|
18
28
|
if (options.provider === "browser" && !options.component) {
|
|
19
29
|
const pathWithoutBase = path.replace(new RegExp(`^${useRuntimeConfig().app.baseURL}`), "");
|
|
20
|
-
return sendRedirect(e, withBase(pathWithoutBase,
|
|
30
|
+
return sendRedirect(e, withBase(pathWithoutBase, nitroOrigin));
|
|
31
|
+
}
|
|
32
|
+
if (!options.component) {
|
|
33
|
+
throw createError({
|
|
34
|
+
statusCode: 500,
|
|
35
|
+
statusMessage: `Nuxt OG Image trying to render an invalid component. Received options ${JSON.stringify(options)}`
|
|
36
|
+
});
|
|
21
37
|
}
|
|
22
|
-
const
|
|
38
|
+
const hashId = hash([options.component, options]);
|
|
39
|
+
const island = await $fetch(`/__nuxt_island/${options.component}_${hashId}`, {
|
|
40
|
+
params: {
|
|
41
|
+
props: JSON.stringify(options)
|
|
42
|
+
}
|
|
43
|
+
});
|
|
23
44
|
const head = createHeadCore();
|
|
24
45
|
head.push(island.head);
|
|
46
|
+
let defaultFontFamily = "sans-serif";
|
|
47
|
+
const firstFont = fonts[0];
|
|
48
|
+
if (firstFont)
|
|
49
|
+
defaultFontFamily = firstFont.name;
|
|
50
|
+
let html = island.html;
|
|
51
|
+
try {
|
|
52
|
+
html = twemoji.parse(html, {
|
|
53
|
+
folder: "svg",
|
|
54
|
+
ext: ".svg"
|
|
55
|
+
});
|
|
56
|
+
} catch (e2) {
|
|
57
|
+
}
|
|
25
58
|
head.push({
|
|
26
59
|
style: [
|
|
27
60
|
{
|
|
28
61
|
// default font is the first font family
|
|
29
|
-
innerHTML: `body { font-family: '${
|
|
62
|
+
innerHTML: `body { font-family: '${defaultFontFamily.replace("+", " ")}', sans-serif; }`
|
|
30
63
|
},
|
|
31
|
-
|
|
64
|
+
{
|
|
32
65
|
innerHTML: `body {
|
|
33
|
-
transform: scale(${scale});
|
|
66
|
+
transform: scale(${scale || 1});
|
|
34
67
|
transform-origin: top left;
|
|
35
68
|
max-height: 100vh;
|
|
36
69
|
position: relative;
|
|
37
|
-
width: ${
|
|
38
|
-
height: ${
|
|
70
|
+
width: ${options.width}px;
|
|
71
|
+
height: ${options.height}px;
|
|
39
72
|
overflow: hidden;
|
|
40
73
|
background-color: ${mode === "dark" ? "#1b1b1b" : "#fff"};
|
|
41
74
|
}
|
|
@@ -44,9 +77,18 @@ img.emoji {
|
|
|
44
77
|
width: 1em;
|
|
45
78
|
margin: 0 .05em 0 .1em;
|
|
46
79
|
vertical-align: -0.1em;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
80
|
+
}`
|
|
81
|
+
},
|
|
82
|
+
...fonts.filter((font) => font.path).map((font) => {
|
|
83
|
+
return `
|
|
84
|
+
@font-face {
|
|
85
|
+
font-family: '${font.name}';
|
|
86
|
+
font-style: normal;
|
|
87
|
+
font-weight: ${font.weight};
|
|
88
|
+
src: url('${font.path}') format('truetype');
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
})
|
|
50
92
|
],
|
|
51
93
|
meta: [
|
|
52
94
|
{
|
|
@@ -57,12 +99,12 @@ img.emoji {
|
|
|
57
99
|
{
|
|
58
100
|
src: "https://cdn.tailwindcss.com"
|
|
59
101
|
},
|
|
60
|
-
// @todo merge with users tailwind
|
|
61
102
|
{
|
|
62
103
|
innerHTML: `tailwind.config = {
|
|
63
104
|
corePlugins: {
|
|
64
105
|
preflight: false,
|
|
65
|
-
}
|
|
106
|
+
},
|
|
107
|
+
theme: ${JSON.stringify(satoriOptions?.tailwindConfig?.theme || {})}
|
|
66
108
|
}`
|
|
67
109
|
}
|
|
68
110
|
],
|
|
@@ -73,19 +115,53 @@ img.emoji {
|
|
|
73
115
|
rel: "stylesheet"
|
|
74
116
|
},
|
|
75
117
|
// have to add each weight as their own stylesheet
|
|
76
|
-
...fonts.map((font) => {
|
|
77
|
-
const [name, weight] = font.split(":");
|
|
118
|
+
...fonts.filter((font) => !font.path).map((font) => {
|
|
78
119
|
return {
|
|
79
|
-
href: `https://fonts.googleapis.com/css2?family=${name}:wght@${weight}&display=swap`,
|
|
120
|
+
href: `https://fonts.googleapis.com/css2?family=${font.name}:wght@${font.weight}&display=swap`,
|
|
80
121
|
rel: "stylesheet"
|
|
81
122
|
};
|
|
82
123
|
})
|
|
83
124
|
]
|
|
84
125
|
});
|
|
85
126
|
const headChunk = await renderSSRHead(head);
|
|
86
|
-
|
|
127
|
+
let htmlTemplate = `<!DOCTYPE html>
|
|
87
128
|
<html ${headChunk.htmlAttrs}>
|
|
88
129
|
<head>${headChunk.headTags}</head>
|
|
89
|
-
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="position: relative; display: flex; margin: 0 auto; width:
|
|
130
|
+
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="position: relative; display: flex; margin: 0 auto; width: ${options.width}px; height: ${options.height}px; overflow: hidden;">${html}</div>${headChunk.bodyTags}</body>
|
|
90
131
|
</html>`;
|
|
132
|
+
const inlineCss = loadInlineCSS();
|
|
133
|
+
if (!inlineCss.__mock) {
|
|
134
|
+
let hasInlineStyles = false;
|
|
135
|
+
const stylesheets = htmlTemplate.match(/<link rel="stylesheet" href=".*?">/g);
|
|
136
|
+
if (stylesheets) {
|
|
137
|
+
for (const stylesheet of stylesheets) {
|
|
138
|
+
if (!stylesheet.includes(`${options.component.replace("OgImageTemplate", "").replace("OgImage", "")}.vue`)) {
|
|
139
|
+
htmlTemplate = htmlTemplate.replace(stylesheet, "");
|
|
140
|
+
} else {
|
|
141
|
+
const href = stylesheet.match(/href="(.*?)"/)[1];
|
|
142
|
+
try {
|
|
143
|
+
let css = await (await $fetch(href, {
|
|
144
|
+
baseURL: nitroOrigin
|
|
145
|
+
})).text();
|
|
146
|
+
if (css.includes("const __vite__css =")) {
|
|
147
|
+
css = css.match(/const __vite__css = "(.*)"/)[1].replace(/\\n/g, "\n");
|
|
148
|
+
}
|
|
149
|
+
css = css.replace(/\/\*# sourceMappingURL=.*?\*\//g, "").replaceAll("! important", "").replaceAll("!important");
|
|
150
|
+
htmlTemplate = htmlTemplate.replace(stylesheet, `<style>${css}</style>`);
|
|
151
|
+
hasInlineStyles = true;
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (hasInlineStyles) {
|
|
158
|
+
try {
|
|
159
|
+
htmlTemplate = await inlineCss(htmlTemplate, {
|
|
160
|
+
url: nitroOrigin
|
|
161
|
+
});
|
|
162
|
+
} catch {
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return htmlTemplate;
|
|
91
167
|
});
|
|
@@ -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,19 +1,21 @@
|
|
|
1
|
-
import { createError, defineEventHandler,
|
|
1
|
+
import { createError, defineEventHandler, getQuery } from "h3";
|
|
2
2
|
import { withoutBase } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import { extractOgImageOptions } from "../utils.mjs";
|
|
4
5
|
import { getRouteRules } from "#internal/nitro";
|
|
5
6
|
import { useRuntimeConfig } from "#imports";
|
|
6
7
|
export default defineEventHandler(async (e) => {
|
|
7
8
|
const query = getQuery(e);
|
|
8
9
|
const path = withoutBase(query.path || "/", useRuntimeConfig().app.baseURL);
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
+
}
|
|
17
19
|
const extractedPayload = extractOgImageOptions(html);
|
|
18
20
|
if (!extractedPayload) {
|
|
19
21
|
throw createError({
|
|
@@ -22,20 +24,19 @@ export default defineEventHandler(async (e) => {
|
|
|
22
24
|
});
|
|
23
25
|
}
|
|
24
26
|
e.node.req.url = path;
|
|
27
|
+
const oldRouteRules = e.context._nitro.routeRules;
|
|
25
28
|
e.context._nitro.routeRules = void 0;
|
|
26
29
|
const routeRules = getRouteRules(e)?.ogImage;
|
|
30
|
+
e.context._nitro.routeRules = oldRouteRules;
|
|
27
31
|
e.node.req.url = e.path;
|
|
28
32
|
if (routeRules === false)
|
|
29
33
|
return false;
|
|
30
34
|
const { defaults } = useRuntimeConfig()["nuxt-og-image"];
|
|
31
|
-
return
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
// use query data
|
|
39
|
-
...query
|
|
40
|
-
};
|
|
35
|
+
return defu(
|
|
36
|
+
extractedPayload,
|
|
37
|
+
routeRules,
|
|
38
|
+
// runtime options
|
|
39
|
+
{ path },
|
|
40
|
+
defaults
|
|
41
|
+
);
|
|
41
42
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
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
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export default defineEventHandler(async (e) => {
|
|
@@ -15,5 +15,5 @@ export default defineEventHandler(async (e) => {
|
|
|
15
15
|
statusMessage: `Provider ${options.provider} is missing.`
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
return provider.createSvg(
|
|
18
|
+
return provider.createSvg(options);
|
|
19
19
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
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
5
|
import { useRuntimeConfig } from "#imports";
|
|
6
6
|
export default defineEventHandler(async (e) => {
|
|
@@ -15,5 +15,5 @@ export default defineEventHandler(async (e) => {
|
|
|
15
15
|
statusMessage: `Provider ${options.provider} is missing.`
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
|
-
return provider.createVNode(
|
|
18
|
+
return provider.createVNode(options);
|
|
19
19
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export function decodeHtml(html) {
|
|
2
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(parseInt(int));
|
|
3
|
+
return String.fromCharCode(Number.parseInt(int));
|
|
4
4
|
});
|
|
5
5
|
}
|
|
6
6
|
function decodeObjectHtmlEntities(obj) {
|
|
@@ -34,6 +34,3 @@ export function extractOgImageOptions(html) {
|
|
|
34
34
|
}
|
|
35
35
|
return false;
|
|
36
36
|
}
|
|
37
|
-
export function stripOgImageOptions(html) {
|
|
38
|
-
return html.replace(/<script id="nuxt-og-image-options" type="application\/json">(.*?)<\/script>/, "");
|
|
39
|
-
}
|
|
@@ -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): string;
|
|
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,75 +1,81 @@
|
|
|
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
|
-
import
|
|
6
|
-
|
|
5
|
+
import { prefixStorage } from "unstorage";
|
|
6
|
+
import sizeOf from "image-size";
|
|
7
|
+
import { useNitroOrigin, useRuntimeConfig, useStorage } from "#imports";
|
|
8
|
+
export function wasmLoader(asyncModuleLoad, fallback) {
|
|
7
9
|
let promise;
|
|
8
|
-
let
|
|
10
|
+
let wasm;
|
|
9
11
|
return {
|
|
10
|
-
|
|
11
|
-
if (loaded)
|
|
12
|
-
return true;
|
|
12
|
+
async load(options) {
|
|
13
13
|
if (typeof promise !== "undefined")
|
|
14
14
|
return promise;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
async load() {
|
|
15
|
+
if (wasm)
|
|
16
|
+
return wasm;
|
|
18
17
|
promise = promise || new Promise(async (resolve) => {
|
|
19
|
-
let wasm;
|
|
20
18
|
try {
|
|
21
|
-
wasm = await
|
|
19
|
+
wasm = await asyncModuleLoad;
|
|
22
20
|
if (typeof wasm === "string")
|
|
23
21
|
wasm = void 0;
|
|
24
22
|
} catch (e) {
|
|
25
23
|
}
|
|
26
|
-
if (!wasm)
|
|
27
|
-
wasm = await readPublicAsset(fallback);
|
|
28
24
|
if (!wasm) {
|
|
29
|
-
|
|
30
|
-
|
|
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);
|
|
31
32
|
}
|
|
32
|
-
loaded = true;
|
|
33
33
|
resolve(wasm);
|
|
34
34
|
});
|
|
35
35
|
return promise;
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
|
-
export function fetchOptions(e, path) {
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
} :
|
|
43
|
-
|
|
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 = path.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
|
+
// cache for 1 minute or 5 seconds, avoids subsequent internal fetches
|
|
64
|
+
expiresAt: Date.now() + (options.cache ? 60 * 60 * 1e3 : 5 * 1e3)
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
...options,
|
|
70
|
+
// use query data
|
|
71
|
+
...getQuery(e),
|
|
72
|
+
requestOrigin: useNitroOrigin(e)
|
|
44
73
|
};
|
|
45
|
-
return globalThis.$fetch("/api/og-image-options", {
|
|
46
|
-
query: {
|
|
47
|
-
...getQuery(e),
|
|
48
|
-
path
|
|
49
|
-
},
|
|
50
|
-
...fetchOptions2
|
|
51
|
-
});
|
|
52
74
|
}
|
|
53
75
|
export function base64ToArrayBuffer(base64) {
|
|
54
76
|
const buffer = Buffer.from(base64, "base64");
|
|
55
77
|
return new Uint8Array(buffer).buffer;
|
|
56
78
|
}
|
|
57
|
-
export function renderIsland(payload) {
|
|
58
|
-
return globalThis.$fetch(`/__nuxt_island/${payload.component}`, {
|
|
59
|
-
query: { props: JSON.stringify(payload) }
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
export function useHostname(e) {
|
|
63
|
-
const config = useRuntimeConfig()["nuxt-og-image"];
|
|
64
|
-
const base = useRuntimeConfig().app.baseURL;
|
|
65
|
-
if (!process.dev && config.siteUrl)
|
|
66
|
-
return withBase(base, config.siteUrl);
|
|
67
|
-
const host = getRequestHeader(e, "host") || process.env.NITRO_HOST || process.env.HOST || "localhost";
|
|
68
|
-
const protocol = getRequestHeader(e, "x-forwarded-proto") || "http";
|
|
69
|
-
const useHttp = process.env.NODE_ENV === "development" || host.includes("127.0.0.1") || host.includes("localhost") || protocol === "http";
|
|
70
|
-
const port = host.includes(":") ? host.split(":").pop() : process.env.NITRO_PORT || process.env.PORT;
|
|
71
|
-
return withBase(base, `http${useHttp ? "" : "s"}://${host.includes(":") ? host.split(":")[0] : host}${port ? `:${port}` : ""}`);
|
|
72
|
-
}
|
|
73
79
|
function r(base, key) {
|
|
74
80
|
return join(base, key.replace(/:/g, "/"));
|
|
75
81
|
}
|
|
@@ -84,13 +90,21 @@ export async function readPublicAsset(file, encoding) {
|
|
|
84
90
|
export async function readPublicAssetBase64(file) {
|
|
85
91
|
const base64 = await readPublicAsset(file, "base64");
|
|
86
92
|
if (base64) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
type = "image/png";
|
|
93
|
-
return `data:${type};base64,${base64}`;
|
|
93
|
+
const dimensions = await sizeOf(Buffer.from(base64, "base64"));
|
|
94
|
+
return {
|
|
95
|
+
src: toBase64Image(file, base64),
|
|
96
|
+
...dimensions
|
|
97
|
+
};
|
|
94
98
|
}
|
|
95
99
|
}
|
|
100
|
+
export function toBase64Image(fileName, data) {
|
|
101
|
+
const base64 = typeof data === "string" ? data : Buffer.from(data).toString("base64");
|
|
102
|
+
let type = "image/jpeg";
|
|
103
|
+
const ext = fileName.split(".").pop();
|
|
104
|
+
if (ext === "svg")
|
|
105
|
+
type = "image/svg+xml";
|
|
106
|
+
else if (ext === "png")
|
|
107
|
+
type = "image/png";
|
|
108
|
+
return `data:${type};base64,${base64}`;
|
|
109
|
+
}
|
|
96
110
|
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,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nuxt-og-image",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "2.0.
|
|
5
|
-
"packageManager": "pnpm@8.
|
|
4
|
+
"version": "2.0.1",
|
|
5
|
+
"packageManager": "pnpm@8.6.5",
|
|
6
|
+
"description": "Enlightened OG Image generation for Nuxt.",
|
|
6
7
|
"license": "MIT",
|
|
7
8
|
"funding": "https://github.com/sponsors/harlan-zw",
|
|
8
9
|
"homepage": "https://github.com/harlan-zw/nuxt-og-image#readme",
|
|
@@ -26,46 +27,56 @@
|
|
|
26
27
|
"dist"
|
|
27
28
|
],
|
|
28
29
|
"dependencies": {
|
|
29
|
-
"@nuxt/kit": "3.
|
|
30
|
+
"@nuxt/kit": "^3.6.1",
|
|
31
|
+
"@resvg/resvg-js": "^2.4.1",
|
|
32
|
+
"@resvg/resvg-wasm": "^2.4.1",
|
|
30
33
|
"@types/fs-extra": "^11.0.1",
|
|
31
|
-
"birpc": "^0.2.
|
|
32
|
-
"chalk": "^5.
|
|
33
|
-
"chrome-launcher": "^0.15.
|
|
34
|
+
"birpc": "^0.2.12",
|
|
35
|
+
"chalk": "^5.3.0",
|
|
36
|
+
"chrome-launcher": "^0.15.2",
|
|
34
37
|
"defu": "^6.1.2",
|
|
35
38
|
"execa": "^7.1.1",
|
|
36
|
-
"fast-glob": "^3.
|
|
39
|
+
"fast-glob": "^3.3.0",
|
|
37
40
|
"flatted": "^3.2.7",
|
|
38
41
|
"fs-extra": "^11.1.1",
|
|
42
|
+
"globby": "^13.2.1",
|
|
43
|
+
"image-size": "^1.0.2",
|
|
44
|
+
"inline-css": "^4.0.2",
|
|
39
45
|
"launch-editor": "^2.6.0",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"
|
|
43
|
-
"
|
|
46
|
+
"nuxt-site-config": "^0.8.1",
|
|
47
|
+
"nuxt-site-config-kit": "^0.8.1",
|
|
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",
|
|
44
53
|
"radix3": "^1.0.1",
|
|
45
|
-
"satori": "0.
|
|
54
|
+
"satori": "0.10.1",
|
|
46
55
|
"satori-html": "^0.3.2",
|
|
47
|
-
"sirv": "^2.0.
|
|
48
|
-
"std-env": "^3.3.
|
|
49
|
-
"svg2png-wasm": "^1.
|
|
56
|
+
"sirv": "^2.0.3",
|
|
57
|
+
"std-env": "^3.3.3",
|
|
58
|
+
"svg2png-wasm": "^1.4.0",
|
|
50
59
|
"tinyws": "^0.1.0",
|
|
51
60
|
"twemoji": "^14.0.2",
|
|
52
|
-
"ufo": "^1.1.
|
|
61
|
+
"ufo": "^1.1.2",
|
|
53
62
|
"ws": "^8.13.0",
|
|
54
63
|
"yoga-wasm-web": "^0.3.3"
|
|
55
64
|
},
|
|
56
65
|
"devDependencies": {
|
|
57
|
-
"@antfu/eslint-config": "^0.
|
|
58
|
-
"@nuxt/devtools-edge": "0.
|
|
59
|
-
"@nuxt/module-builder": "^0.
|
|
60
|
-
"@nuxt/test-utils": "3.
|
|
66
|
+
"@antfu/eslint-config": "^0.39.6",
|
|
67
|
+
"@nuxt/devtools-edge": "0.6.6-28139075.95f3dd8",
|
|
68
|
+
"@nuxt/module-builder": "^0.4.0",
|
|
69
|
+
"@nuxt/test-utils": "3.6.1",
|
|
61
70
|
"@nuxtjs/eslint-config-typescript": "^12.0.0",
|
|
62
|
-
"@types/ws": "^8.5.
|
|
63
|
-
"bumpp": "^9.1.
|
|
64
|
-
"eslint": "8.
|
|
71
|
+
"@types/ws": "^8.5.5",
|
|
72
|
+
"bumpp": "^9.1.1",
|
|
73
|
+
"eslint": "8.44.0",
|
|
65
74
|
"jest-image-snapshot": "^6.1.0",
|
|
66
|
-
"nuxt": "^3.
|
|
67
|
-
"
|
|
68
|
-
"
|
|
75
|
+
"nuxt": "^3.6.1",
|
|
76
|
+
"nuxt-icon": "^0.4.2",
|
|
77
|
+
"playwright": "^1.35.1",
|
|
78
|
+
"sass": "^1.63.6",
|
|
79
|
+
"vitest": "^0.32.4"
|
|
69
80
|
},
|
|
70
81
|
"scripts": {
|
|
71
82
|
"build": "pnpm dev:prepare && pnpm build:module && pnpm build:client",
|
|
@@ -76,6 +87,6 @@
|
|
|
76
87
|
"dev:build": "nuxi build .playground",
|
|
77
88
|
"dev:prepare": "nuxt-module-build --stub && nuxi prepare .playground",
|
|
78
89
|
"release": "bumpp package.json --commit --push --tag",
|
|
79
|
-
"test": "
|
|
90
|
+
"test": "vitest"
|
|
80
91
|
}
|
|
81
92
|
}
|
|
@@ -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.fc9150b0.js";const x=p({__name:"IconCSS",props:{name:{type:String,required:!0},size:{type:String,default:""}},setup(c){const s=c;u(e=>({"09a3f8ca":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-c836ce7b"]]);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.fc9150b0.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 _};
|