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
package/dist/module.mjs
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
2
|
-
import { defineNuxtModule,
|
|
2
|
+
import { useNuxt, addTemplate, defineNuxtModule, useLogger, createResolver, addServerHandler, addImports, addComponent, hasNuxtModule, addServerPlugin } from '@nuxt/kit';
|
|
3
3
|
import { execa } from 'execa';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
5
|
import defu from 'defu';
|
|
6
6
|
import { toRouteMatcher, createRouter } from 'radix3';
|
|
7
7
|
import { withBase, joinURL } from 'ufo';
|
|
8
|
-
import { resolve, relative } from 'pathe';
|
|
8
|
+
import { resolve, relative, dirname } from 'pathe';
|
|
9
9
|
import { tinyws } from 'tinyws';
|
|
10
10
|
import sirv from 'sirv';
|
|
11
11
|
import { pathExists, copy, mkdirp } from 'fs-extra';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
12
|
+
import { globby } from 'globby';
|
|
13
|
+
import { installNuxtSiteConfig, updateSiteConfig, requireSiteConfig } from 'nuxt-site-config-kit';
|
|
14
14
|
import playwrightCore from 'playwright-core';
|
|
15
15
|
import { existsSync } from 'node:fs';
|
|
16
16
|
import { createBirpcGroup } from 'birpc';
|
|
17
17
|
import { stringify, parse } from 'flatted';
|
|
18
|
+
import { addDependency } from 'nypm';
|
|
19
|
+
import { provider } from 'std-env';
|
|
18
20
|
|
|
19
21
|
async function createBrowser() {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
if (process.dev || process.env.prerender) {
|
|
23
|
+
try {
|
|
24
|
+
const { Launcher } = await import(String("chrome-launcher"));
|
|
25
|
+
const chromePath = Launcher.getFirstInstallation();
|
|
26
|
+
return await playwrightCore.chromium.launch({
|
|
27
|
+
headless: true,
|
|
28
|
+
executablePath: chromePath
|
|
29
|
+
});
|
|
30
|
+
} catch (e) {
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
try {
|
|
30
34
|
return await playwrightCore.chromium.launch({
|
|
@@ -55,9 +59,9 @@ async function screenshot(browser, options) {
|
|
|
55
59
|
width: options.width || 1200,
|
|
56
60
|
height: options.height || 630
|
|
57
61
|
});
|
|
58
|
-
const isHtml = options.path
|
|
62
|
+
const isHtml = options.html || options.path?.startsWith("html:");
|
|
59
63
|
if (isHtml) {
|
|
60
|
-
const html = options.html || options.path
|
|
64
|
+
const html = options.html || options.path?.substring(5);
|
|
61
65
|
await page.evaluate((html2) => {
|
|
62
66
|
document.open("text/html");
|
|
63
67
|
document.write(html2);
|
|
@@ -66,12 +70,12 @@ async function screenshot(browser, options) {
|
|
|
66
70
|
await page.waitForLoadState("networkidle");
|
|
67
71
|
} else {
|
|
68
72
|
await page.goto(`${options.host}${options.path}`, {
|
|
69
|
-
timeout: 1e4,
|
|
73
|
+
timeout: process.env.prerender || process.dev ? 1e4 : 3500,
|
|
70
74
|
waitUntil: "networkidle"
|
|
71
75
|
});
|
|
72
76
|
}
|
|
73
77
|
const screenshotOptions = {
|
|
74
|
-
timeout: 1e4
|
|
78
|
+
timeout: process.env.prerender || process.dev ? 1e4 : 3500
|
|
75
79
|
};
|
|
76
80
|
if (options.delay)
|
|
77
81
|
await page.waitForTimeout(options.delay);
|
|
@@ -83,7 +87,9 @@ async function screenshot(browser, options) {
|
|
|
83
87
|
}
|
|
84
88
|
if (options.selector)
|
|
85
89
|
return await page.locator(options.selector).screenshot(screenshotOptions);
|
|
86
|
-
|
|
90
|
+
const screenshot2 = await page.screenshot(screenshotOptions);
|
|
91
|
+
await page.close();
|
|
92
|
+
return screenshot2;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
function setupPlaygroundRPC(nuxt, config) {
|
|
@@ -170,7 +176,7 @@ function getBodyJson(req) {
|
|
|
170
176
|
|
|
171
177
|
function decodeHtml(html) {
|
|
172
178
|
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) => {
|
|
173
|
-
return String.fromCharCode(parseInt(int));
|
|
179
|
+
return String.fromCharCode(Number.parseInt(int));
|
|
174
180
|
});
|
|
175
181
|
}
|
|
176
182
|
function decodeObjectHtmlEntities(obj) {
|
|
@@ -204,50 +210,204 @@ function extractOgImageOptions(html) {
|
|
|
204
210
|
}
|
|
205
211
|
return false;
|
|
206
212
|
}
|
|
207
|
-
|
|
208
|
-
|
|
213
|
+
|
|
214
|
+
const SVG2PNGWasmPlaceholder = '"/* NUXT_OG_IMAGE_SVG2PNG_WASM */"';
|
|
215
|
+
const YogaWasmPlaceholder = '"/* NUXT_OG_IMAGE_YOGA_WASM */"';
|
|
216
|
+
const ReSVGWasmPlaceholder = '"/* NUXT_OG_IMAGE_RESVG_WASM */"';
|
|
217
|
+
const Wasms = [
|
|
218
|
+
{
|
|
219
|
+
placeholder: SVG2PNGWasmPlaceholder,
|
|
220
|
+
path: "svg2png/svg2png.wasm",
|
|
221
|
+
file: "svg2png.wasm"
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
placeholder: ReSVGWasmPlaceholder,
|
|
225
|
+
path: "resvg/resvg.wasm",
|
|
226
|
+
file: "resvg.wasm"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
placeholder: YogaWasmPlaceholder,
|
|
230
|
+
path: "yoga/yoga.wasm",
|
|
231
|
+
file: "yoga.wasm"
|
|
232
|
+
}
|
|
233
|
+
];
|
|
234
|
+
const DefaultRuntimeCompatibility = {
|
|
235
|
+
// node-server runtime
|
|
236
|
+
browser: "playwright",
|
|
237
|
+
satori: "default",
|
|
238
|
+
wasm: "fetch",
|
|
239
|
+
png: "resvg-node"
|
|
240
|
+
};
|
|
241
|
+
const RuntimeCompatibility = {
|
|
242
|
+
"nitro-dev": {
|
|
243
|
+
wasm: "fetch",
|
|
244
|
+
browser: "universal"
|
|
245
|
+
},
|
|
246
|
+
"stackblitz": {
|
|
247
|
+
browser: false,
|
|
248
|
+
satori: "yoga-wasm",
|
|
249
|
+
wasm: "inline",
|
|
250
|
+
png: "resvg-wasm"
|
|
251
|
+
},
|
|
252
|
+
"netlify": {
|
|
253
|
+
browser: "lambda",
|
|
254
|
+
wasm: "inline"
|
|
255
|
+
},
|
|
256
|
+
"netlify-edge": {
|
|
257
|
+
wasm: "inline",
|
|
258
|
+
png: "resvg-wasm"
|
|
259
|
+
},
|
|
260
|
+
"vercel": {
|
|
261
|
+
// exceeds 50mb limit
|
|
262
|
+
browser: false
|
|
263
|
+
},
|
|
264
|
+
"vercel-edge": {
|
|
265
|
+
browser: false,
|
|
266
|
+
wasm: "import",
|
|
267
|
+
wasmImportQuery: "?module",
|
|
268
|
+
png: "resvg-wasm"
|
|
269
|
+
},
|
|
270
|
+
"cloudflare-pages": {
|
|
271
|
+
browser: false,
|
|
272
|
+
wasm: "import",
|
|
273
|
+
png: "resvg-wasm"
|
|
274
|
+
},
|
|
275
|
+
"cloudflare": {
|
|
276
|
+
browser: false,
|
|
277
|
+
wasm: "import"
|
|
278
|
+
}
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
const autodetectableProviders = {
|
|
282
|
+
azure_static: "azure",
|
|
283
|
+
cloudflare_pages: "cloudflare-pages",
|
|
284
|
+
netlify: "netlify",
|
|
285
|
+
stormkit: "stormkit",
|
|
286
|
+
vercel: "vercel",
|
|
287
|
+
cleavr: "cleavr",
|
|
288
|
+
stackblitz: "stackblitz"
|
|
289
|
+
};
|
|
290
|
+
const autodetectableStaticProviders = {
|
|
291
|
+
netlify: "netlify-static",
|
|
292
|
+
vercel: "vercel-static"
|
|
293
|
+
};
|
|
294
|
+
function detectTarget(options = {}) {
|
|
295
|
+
return options?.static ? autodetectableStaticProviders[provider] : autodetectableProviders[provider];
|
|
296
|
+
}
|
|
297
|
+
function getNitroPreset(nuxt) {
|
|
298
|
+
return process.env.NITRO_PRESET || nuxt.options.nitro.preset || detectTarget() || "node-server";
|
|
299
|
+
}
|
|
300
|
+
function getNitroProviderCompatibility(nuxt) {
|
|
301
|
+
if (provider === "stackblitz")
|
|
302
|
+
return defu(RuntimeCompatibility.stackblitz, DefaultRuntimeCompatibility);
|
|
303
|
+
if (nuxt.options.dev || nuxt.options._prepare || nuxt.options._generate) {
|
|
304
|
+
return defu({
|
|
305
|
+
wasm: "fetch",
|
|
306
|
+
browser: "universal"
|
|
307
|
+
}, DefaultRuntimeCompatibility);
|
|
308
|
+
}
|
|
309
|
+
const target = getNitroPreset(nuxt);
|
|
310
|
+
const compatibility = RuntimeCompatibility[target];
|
|
311
|
+
if (compatibility === false)
|
|
312
|
+
return false;
|
|
313
|
+
return defu(compatibility || {}, DefaultRuntimeCompatibility);
|
|
314
|
+
}
|
|
315
|
+
function ensureDependencies(nuxt, dep) {
|
|
316
|
+
return Promise.all(dep.map((d) => {
|
|
317
|
+
return addDependency(d, { cwd: nuxt.options.rootDir });
|
|
318
|
+
}));
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function extendTypes(module, template) {
|
|
322
|
+
const nuxt = useNuxt();
|
|
323
|
+
addTemplate({
|
|
324
|
+
filename: `${module}.d.ts`,
|
|
325
|
+
getContents: () => {
|
|
326
|
+
const s = template();
|
|
327
|
+
return `// Generated by ${module}
|
|
328
|
+
${s}
|
|
329
|
+
export {}
|
|
330
|
+
`;
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
nuxt.hooks.hook("prepare:types", ({ references }) => {
|
|
334
|
+
references.push({ path: resolve(nuxt.options.buildDir, `${module}.d.ts`) });
|
|
335
|
+
});
|
|
209
336
|
}
|
|
210
337
|
|
|
211
338
|
const PATH = "/__nuxt_og_image__";
|
|
212
339
|
const PATH_ENTRY = `${PATH}/entry`;
|
|
213
340
|
const PATH_PLAYGROUND = `${PATH}/client`;
|
|
214
|
-
const edgeProvidersSupported = [
|
|
215
|
-
"cloudflare",
|
|
216
|
-
"vercel-edge",
|
|
217
|
-
"netlify-edge"
|
|
218
|
-
];
|
|
219
341
|
const module = defineNuxtModule({
|
|
220
342
|
meta: {
|
|
221
343
|
name: "nuxt-og-image",
|
|
222
344
|
compatibility: {
|
|
223
|
-
nuxt: "^3.
|
|
345
|
+
nuxt: "^3.6.1",
|
|
224
346
|
bridge: false
|
|
225
347
|
},
|
|
226
348
|
configKey: "ogImage"
|
|
227
349
|
},
|
|
228
350
|
defaults(nuxt) {
|
|
229
|
-
const siteUrl = process.env.NUXT_PUBLIC_SITE_URL || process.env.NUXT_SITE_URL || nuxt.options.runtimeConfig.public?.siteUrl || nuxt.options.runtimeConfig.siteUrl;
|
|
230
351
|
return {
|
|
231
|
-
|
|
232
|
-
forcePrerender: !nuxt.options.dev && nuxt.options._generate,
|
|
233
|
-
siteUrl,
|
|
352
|
+
enabled: true,
|
|
234
353
|
defaults: {
|
|
235
|
-
component: "
|
|
354
|
+
component: "OgImageTemplateFallback",
|
|
236
355
|
width: 1200,
|
|
237
|
-
height: 630
|
|
356
|
+
height: 630,
|
|
357
|
+
// default is to cache the image for 24 hours
|
|
358
|
+
cache: true,
|
|
359
|
+
cacheTtl: 24 * 60 * 60 * 1e3
|
|
238
360
|
},
|
|
239
|
-
|
|
240
|
-
|
|
361
|
+
componentDirs: ["OgImage", "OgImageTemplate"],
|
|
362
|
+
runtimeSatori: true,
|
|
363
|
+
runtimeBrowser: nuxt.options.dev,
|
|
241
364
|
fonts: [],
|
|
365
|
+
runtimeCacheStorage: true,
|
|
242
366
|
satoriOptions: {},
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
playground: process.env.NODE_ENV === "development" || nuxt.options.dev
|
|
367
|
+
playground: process.env.NODE_ENV === "development" || nuxt.options.dev,
|
|
368
|
+
debug: false
|
|
246
369
|
};
|
|
247
370
|
},
|
|
248
371
|
async setup(config, nuxt) {
|
|
372
|
+
const logger = useLogger("nuxt-og-image");
|
|
373
|
+
logger.level = config.debug || nuxt.options.debug ? 4 : 3;
|
|
374
|
+
if (config.enabled === false) {
|
|
375
|
+
logger.debug("The module is disabled, skipping setup.");
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
249
378
|
const { resolve } = createResolver(import.meta.url);
|
|
250
|
-
|
|
379
|
+
logger.debug("Using Nitro preset", getNitroPreset(nuxt));
|
|
380
|
+
const nitroCompatibility = getNitroProviderCompatibility(nuxt);
|
|
381
|
+
logger.debug("Nitro compatibility", nitroCompatibility);
|
|
382
|
+
const nitroTarget = process.env.NITRO_PRESET || nuxt.options.nitro.preset;
|
|
383
|
+
if (!nitroCompatibility) {
|
|
384
|
+
logger.warn(`\`nuxt-og-image\` does not support the nitro target \`${nitroTarget}\`. Please make an issue. `);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
if (!nitroCompatibility.browser && config.runtimeBrowser) {
|
|
388
|
+
config.runtimeBrowser = false;
|
|
389
|
+
logger.warn(`\`nuxt-og-image\` does not support the nitro target \`${nitroTarget}\` with the runtime browser. Set runtimeBrowser: false to stop seeing this.`);
|
|
390
|
+
}
|
|
391
|
+
if (config.runtimeBrowser && nitroCompatibility.browser === "lambda") {
|
|
392
|
+
logger.info(`\`nuxt-og-image\` is deploying to nitro target \`${nitroTarget}\` that installs extra dependencies.`);
|
|
393
|
+
await ensureDependencies(nuxt, ["puppeteer-core@14.1.1", "@sparticuz/chrome-aws-lambda@14.1.1"]);
|
|
394
|
+
}
|
|
395
|
+
await installNuxtSiteConfig();
|
|
396
|
+
await updateSiteConfig({
|
|
397
|
+
_context: "nuxt-og-image:config",
|
|
398
|
+
url: config.siteUrl || config.host
|
|
399
|
+
});
|
|
400
|
+
requireSiteConfig("nuxt-og-image", {
|
|
401
|
+
url: "Required to generate absolute URLs for the og:image."
|
|
402
|
+
}, { prerender: true });
|
|
403
|
+
nuxt.options.nitro.storage = nuxt.options.nitro.storage || {};
|
|
404
|
+
if (nuxt.options._generate) {
|
|
405
|
+
nuxt.options.nitro.storage["og-image"] = {
|
|
406
|
+
driver: "memory"
|
|
407
|
+
};
|
|
408
|
+
} else if (config.runtimeCacheStorage && !nuxt.options.dev && typeof config.runtimeCacheStorage === "object") {
|
|
409
|
+
nuxt.options.nitro.storage["og-image"] = config.runtimeCacheStorage;
|
|
410
|
+
}
|
|
251
411
|
if (!config.fonts.length)
|
|
252
412
|
config.fonts = ["Inter:400", "Inter:700"];
|
|
253
413
|
const distResolve = (p) => {
|
|
@@ -257,34 +417,27 @@ const module = defineNuxtModule({
|
|
|
257
417
|
return resolve(`../dist/${p}`);
|
|
258
418
|
};
|
|
259
419
|
nuxt.options.experimental.componentIslands = true;
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
getContents: () => {
|
|
263
|
-
return `// Generated by nuxt-og-image
|
|
264
|
-
interface NuxtOgImageNitroRules {
|
|
420
|
+
extendTypes("nuxt-og-image", () => {
|
|
421
|
+
return `interface NuxtOgImageNitroRules {
|
|
265
422
|
ogImage?: false | Record<string, any>
|
|
266
423
|
}
|
|
267
424
|
declare module 'nitropack' {
|
|
268
425
|
interface NitroRouteRules extends NuxtOgImageNitroRules {}
|
|
269
426
|
interface NitroRouteConfig extends NuxtOgImageNitroRules {}
|
|
270
|
-
}
|
|
271
|
-
export {}
|
|
272
|
-
`;
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
nuxt.hooks.hook("prepare:types", ({ references }) => {
|
|
276
|
-
references.push({ path: resolve(nuxt.options.buildDir, "nuxt-og-image.d.ts") });
|
|
427
|
+
}`;
|
|
277
428
|
});
|
|
278
429
|
addServerHandler({
|
|
279
430
|
lazy: true,
|
|
280
431
|
handler: resolve("./runtime/nitro/middleware/og.png")
|
|
281
432
|
});
|
|
282
|
-
["html", "options", "svg", "vnode", "font"].forEach((type) => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
433
|
+
["html", "options", "svg", "vnode", "font", "debug"].forEach((type) => {
|
|
434
|
+
if (type !== "debug" || config.debug) {
|
|
435
|
+
addServerHandler({
|
|
436
|
+
lazy: true,
|
|
437
|
+
route: `/api/og-image-${type}`,
|
|
438
|
+
handler: resolve(`./runtime/nitro/routes/${type}`)
|
|
439
|
+
});
|
|
440
|
+
}
|
|
288
441
|
});
|
|
289
442
|
nuxt.hook("devtools:customTabs", (iframeTabs) => {
|
|
290
443
|
iframeTabs.push({
|
|
@@ -313,7 +466,17 @@ export {}
|
|
|
313
466
|
});
|
|
314
467
|
}
|
|
315
468
|
nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"] = [];
|
|
316
|
-
[
|
|
469
|
+
[
|
|
470
|
+
// deprecated
|
|
471
|
+
"Dynamic",
|
|
472
|
+
"Static",
|
|
473
|
+
// new
|
|
474
|
+
"index",
|
|
475
|
+
"Cached",
|
|
476
|
+
"WithoutCache",
|
|
477
|
+
"Screenshot"
|
|
478
|
+
].forEach((name) => {
|
|
479
|
+
name = name === "index" ? "defineOgImage" : `defineOgImage${name}`;
|
|
317
480
|
addImports({
|
|
318
481
|
name,
|
|
319
482
|
from: resolve("./runtime/composables/defineOgImage")
|
|
@@ -321,104 +484,198 @@ export {}
|
|
|
321
484
|
nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
|
|
322
485
|
});
|
|
323
486
|
await addComponent({
|
|
324
|
-
name: "
|
|
325
|
-
filePath: resolve("./runtime/components/
|
|
487
|
+
name: "OgImageTemplateFallback",
|
|
488
|
+
filePath: resolve("./runtime/components/OgImageTemplate/Fallback.vue"),
|
|
326
489
|
island: true
|
|
327
490
|
});
|
|
328
|
-
[
|
|
491
|
+
[
|
|
492
|
+
// deprecated
|
|
493
|
+
"Static",
|
|
494
|
+
"Dynamic",
|
|
495
|
+
// new
|
|
496
|
+
"index",
|
|
497
|
+
"Cached",
|
|
498
|
+
"WithoutCache",
|
|
499
|
+
"Screenshot"
|
|
500
|
+
].forEach((name) => {
|
|
329
501
|
addComponent({
|
|
330
|
-
|
|
331
|
-
|
|
502
|
+
global: hasNuxtModule("@nuxt/content"),
|
|
503
|
+
name: name === "index" ? "OgImage" : `OgImage${name}`,
|
|
504
|
+
filePath: resolve(`./runtime/components/OgImage/${name}`)
|
|
332
505
|
});
|
|
333
506
|
});
|
|
507
|
+
const ogImageComponents = [];
|
|
508
|
+
nuxt.hook("components:extend", (components) => {
|
|
509
|
+
components.forEach((component) => {
|
|
510
|
+
let valid = false;
|
|
511
|
+
config.componentDirs.forEach((dir) => {
|
|
512
|
+
if (component.pascalName.startsWith(dir) || component.kebabName.startsWith(dir))
|
|
513
|
+
valid = true;
|
|
514
|
+
});
|
|
515
|
+
if (valid) {
|
|
516
|
+
component.island = true;
|
|
517
|
+
component.mode = "server";
|
|
518
|
+
ogImageComponents.push({ pascalName: component.pascalName, kebabName: component.kebabName });
|
|
519
|
+
}
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
addTemplate({
|
|
523
|
+
filename: "og-image-component-names.mjs",
|
|
524
|
+
getContents() {
|
|
525
|
+
return `export const componentNames = ${JSON.stringify(ogImageComponents)}`;
|
|
526
|
+
},
|
|
527
|
+
options: { mode: "server" }
|
|
528
|
+
});
|
|
334
529
|
const runtimeDir = resolve("./runtime");
|
|
335
530
|
nuxt.options.build.transpile.push(runtimeDir);
|
|
336
|
-
|
|
337
|
-
const
|
|
338
|
-
|
|
339
|
-
|
|
531
|
+
addServerPlugin(resolve("./runtime/nitro/plugins/prerender"));
|
|
532
|
+
const customAssetDirs = [
|
|
533
|
+
// allows us to show custom error images
|
|
534
|
+
resolve("./runtime/public-assets")
|
|
340
535
|
];
|
|
536
|
+
if (config.runtimeSatori) {
|
|
537
|
+
if (config.fonts.includes("Inter:400"))
|
|
538
|
+
customAssetDirs.push(resolve("./runtime/public-assets-optional/inter-font"));
|
|
539
|
+
if (nitroCompatibility.png === "resvg-wasm" && nitroCompatibility.wasm === "fetch")
|
|
540
|
+
customAssetDirs.push(resolve("./runtime/public-assets-optional/resvg"));
|
|
541
|
+
else if (nitroCompatibility.png === "svg2png" && nitroCompatibility.wasm === "fetch")
|
|
542
|
+
customAssetDirs.push(resolve("./runtime/public-assets-optional/svg2png"));
|
|
543
|
+
if (nitroCompatibility.satori === "yoga-wasm")
|
|
544
|
+
customAssetDirs.push(resolve("./runtime/public-assets-optional/yoga"));
|
|
545
|
+
}
|
|
341
546
|
nuxt.hooks.hook("modules:done", async () => {
|
|
342
547
|
nuxt.hooks.callHook("og-image:config", config);
|
|
343
|
-
nuxt.options.runtimeConfig["nuxt-og-image"] = {
|
|
548
|
+
nuxt.options.runtimeConfig["nuxt-og-image"] = {
|
|
549
|
+
satoriOptions: config.satoriOptions,
|
|
550
|
+
runtimeSatori: config.runtimeSatori,
|
|
551
|
+
runtimeBrowser: config.runtimeBrowser,
|
|
552
|
+
// @ts-expect-error runtime type
|
|
553
|
+
defaults: config.defaults,
|
|
554
|
+
// avoid adding credentials
|
|
555
|
+
runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
|
|
556
|
+
// convert the fonts to uniform type to fix ts issue
|
|
557
|
+
fonts: config.fonts.map((f) => {
|
|
558
|
+
if (typeof f === "string") {
|
|
559
|
+
const [name, weight] = f.split(":");
|
|
560
|
+
return {
|
|
561
|
+
name,
|
|
562
|
+
weight
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
return f;
|
|
566
|
+
}),
|
|
567
|
+
assetDirs: [
|
|
568
|
+
resolve(nuxt.options.srcDir, nuxt.options.dir.public),
|
|
569
|
+
...customAssetDirs,
|
|
570
|
+
// always add runtime dirs for prerendering to work, these are just used as scan roots
|
|
571
|
+
resolve("./runtime/public-assets-optional/inter-font"),
|
|
572
|
+
resolve("./runtime/public-assets-optional/resvg"),
|
|
573
|
+
resolve("./runtime/public-assets-optional/yoga"),
|
|
574
|
+
resolve("./runtime/public-assets-optional/svg2png")
|
|
575
|
+
]
|
|
576
|
+
};
|
|
344
577
|
});
|
|
345
|
-
const useSatoriWasm = provider === "stackblitz";
|
|
346
578
|
nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
|
|
347
579
|
nitroConfig.externals = defu(nitroConfig.externals || {}, {
|
|
348
580
|
inline: [runtimeDir]
|
|
349
581
|
});
|
|
350
|
-
if (config.
|
|
582
|
+
if (config.runtimeBrowser) {
|
|
351
583
|
nitroConfig.alias = nitroConfig.alias || {};
|
|
352
584
|
nitroConfig.alias.electron = "unenv/runtime/mock/proxy-cjs";
|
|
353
585
|
nitroConfig.alias.bufferutil = "unenv/runtime/mock/proxy-cjs";
|
|
354
586
|
nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
|
|
355
587
|
}
|
|
356
588
|
nitroConfig.publicAssets = nitroConfig.publicAssets || [];
|
|
357
|
-
|
|
589
|
+
customAssetDirs.forEach((dir) => {
|
|
590
|
+
nitroConfig.publicAssets.push({ dir, maxAge: 31536e3 });
|
|
591
|
+
});
|
|
358
592
|
const providerPath = `${runtimeDir}/nitro/providers`;
|
|
359
|
-
if (config.
|
|
360
|
-
nitroConfig.virtual["#nuxt-og-image/browser"] =
|
|
361
|
-
|
|
362
|
-
|
|
593
|
+
if (config.runtimeBrowser) {
|
|
594
|
+
nitroConfig.virtual["#nuxt-og-image/browser"] = `
|
|
595
|
+
let browser
|
|
363
596
|
export default async function() {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
` : `export default async function() {
|
|
367
|
-
return () => {}
|
|
597
|
+
browser = browser || await import('${providerPath}/browser/${nitroCompatibility.browser}').then((m) => m.default || m)
|
|
598
|
+
return browser
|
|
368
599
|
}
|
|
369
600
|
`;
|
|
370
601
|
}
|
|
371
|
-
if (config.
|
|
372
|
-
nitroConfig.virtual["#nuxt-og-image/satori"] = `import satori from '${providerPath}/satori/${
|
|
373
|
-
export default
|
|
602
|
+
if (config.runtimeSatori) {
|
|
603
|
+
nitroConfig.virtual["#nuxt-og-image/satori"] = `import satori from '${providerPath}/satori/${nitroCompatibility.satori}'
|
|
604
|
+
export default function() {
|
|
374
605
|
return satori
|
|
375
606
|
}`;
|
|
376
|
-
nitroConfig.virtual["#nuxt-og-image/
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
607
|
+
nitroConfig.virtual["#nuxt-og-image/png"] = `import png from '${providerPath}/png/${nitroCompatibility.png}'
|
|
608
|
+
export default function() {
|
|
609
|
+
return png
|
|
610
|
+
}
|
|
611
|
+
`;
|
|
381
612
|
}
|
|
382
613
|
nitroConfig.virtual["#nuxt-og-image/provider"] = `
|
|
383
|
-
import satori from '${relative(nuxt.options.rootDir, resolve("./runtime/nitro/renderers/satori"))}'
|
|
384
|
-
import browser from '${relative(nuxt.options.rootDir, resolve("./runtime/nitro/renderers/browser"))}'
|
|
614
|
+
${config.runtimeSatori ? `import satori from '${relative(nuxt.options.rootDir, resolve("./runtime/nitro/renderers/satori"))}'` : ""}
|
|
615
|
+
${config.runtimeBrowser ? `import browser from '${relative(nuxt.options.rootDir, resolve("./runtime/nitro/renderers/browser"))}'` : ""}
|
|
385
616
|
|
|
386
617
|
export async function useProvider(provider) {
|
|
387
618
|
if (provider === 'satori')
|
|
388
|
-
return satori
|
|
619
|
+
return ${config.runtimeSatori ? "satori" : "null"}
|
|
389
620
|
if (provider === 'browser')
|
|
390
|
-
return browser
|
|
621
|
+
return ${config.runtimeBrowser ? "browser" : "null"}
|
|
622
|
+
return null
|
|
391
623
|
}
|
|
392
624
|
`;
|
|
393
625
|
});
|
|
394
626
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
395
627
|
let screenshotQueue = [];
|
|
396
628
|
nitro.hooks.hook("compiled", async (_nitro) => {
|
|
397
|
-
if (
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
629
|
+
if (!config.runtimeSatori || nuxt.options.dev)
|
|
630
|
+
return;
|
|
631
|
+
if (config.fonts.includes("Inter:400"))
|
|
632
|
+
await copy(resolve("./runtime/public-assets-optional/inter-font/inter-latin-ext-400-normal.woff"), resolve(_nitro.options.output.publicDir, "inter-latin-ext-400-normal.woff"));
|
|
633
|
+
if (config.fonts.includes("Inter:700"))
|
|
634
|
+
await copy(resolve("./runtime/public-assets-optional/inter-font/inter-latin-ext-700-normal.woff"), resolve(_nitro.options.output.publicDir, "inter-latin-ext-700-normal.woff"));
|
|
635
|
+
const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
|
|
636
|
+
const wasmProviderPath = resolve(_nitro.options.output.serverDir, typeof configuredEntry === "string" ? configuredEntry : "index.mjs");
|
|
637
|
+
const paths = [wasmProviderPath];
|
|
638
|
+
const chunks = await globby([`${_nitro.options.output.serverDir}/chunks/**/*.mjs`], { absolute: true });
|
|
639
|
+
paths.push(...chunks);
|
|
640
|
+
for (const path of paths) {
|
|
641
|
+
if (!await pathExists(path))
|
|
642
|
+
continue;
|
|
643
|
+
let contents = await readFile(path, "utf-8");
|
|
644
|
+
let updated = false;
|
|
645
|
+
if (_nitro.options.preset.includes("vercel") && path === wasmProviderPath) {
|
|
646
|
+
contents = contents.replace(".cwd(),", '?.cwd || "/",');
|
|
647
|
+
updated = true;
|
|
404
648
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
649
|
+
if (_nitro.options.preset.includes("netlify") && path.endsWith("netlify.mjs")) {
|
|
650
|
+
const match = "// TODO: handle event.isBase64Encoded\n });";
|
|
651
|
+
contents = contents.replace(match, `${match}
|
|
652
|
+
|
|
653
|
+
const headers = normalizeOutgoingHeaders(r.headers);
|
|
654
|
+
// image buffers must be base64 encoded
|
|
655
|
+
if (Buffer.isBuffer(r.body) && headers["content-type"].startsWith("image/")) {
|
|
656
|
+
return {
|
|
657
|
+
statusCode: r.status,
|
|
658
|
+
headers,
|
|
659
|
+
body: r.body.toString("base64"),
|
|
660
|
+
isBase64Encoded: true
|
|
661
|
+
};
|
|
662
|
+
}`);
|
|
663
|
+
updated = true;
|
|
664
|
+
}
|
|
665
|
+
for (const wasm of Wasms) {
|
|
666
|
+
if (contents.includes(wasm.placeholder)) {
|
|
667
|
+
if (nitroCompatibility.wasm === "import") {
|
|
668
|
+
contents = contents.replace(wasm.placeholder, `import("./${wasm.file}${nitroCompatibility.wasmImportQuery || ""}").then(m => m.default || m)`);
|
|
669
|
+
await copy(resolve(`./runtime/public-assets-optional/${wasm.path}`), resolve(dirname(path), wasm.file));
|
|
670
|
+
} else if (nitroCompatibility.wasm === "inline") {
|
|
671
|
+
const wasmBuffer = await readFile(resolve(`./runtime/public-assets-optional/${wasm.path}`));
|
|
672
|
+
contents = contents.replace(wasm.placeholder, `Buffer.from("${wasmBuffer}", "base64")`);
|
|
673
|
+
}
|
|
674
|
+
updated = true;
|
|
420
675
|
}
|
|
421
676
|
}
|
|
677
|
+
if (updated)
|
|
678
|
+
await writeFile(path, contents, { encoding: "utf-8" });
|
|
422
679
|
}
|
|
423
680
|
});
|
|
424
681
|
const _routeRulesMatcher = toRouteMatcher(
|
|
@@ -431,7 +688,6 @@ export async function useProvider(provider) {
|
|
|
431
688
|
if (!html)
|
|
432
689
|
return;
|
|
433
690
|
const extractedOptions = extractOgImageOptions(html);
|
|
434
|
-
ctx.contents = stripOgImageOptions(html);
|
|
435
691
|
const routeRules = defu({}, ..._routeRulesMatcher.matchAll(ctx.route).reverse());
|
|
436
692
|
if (!extractedOptions || routeRules.ogImage === false)
|
|
437
693
|
return;
|
|
@@ -441,7 +697,7 @@ export async function useProvider(provider) {
|
|
|
441
697
|
...extractedOptions,
|
|
442
698
|
...routeRules.ogImage || {}
|
|
443
699
|
};
|
|
444
|
-
if ((nuxt.options._generate || entry.
|
|
700
|
+
if ((nuxt.options._generate || entry.cache) && entry.provider === "browser")
|
|
445
701
|
screenshotQueue.push(entry);
|
|
446
702
|
});
|
|
447
703
|
if (nuxt.options.dev)
|
|
@@ -489,14 +745,14 @@ export async function useProvider(provider) {
|
|
|
489
745
|
});
|
|
490
746
|
}
|
|
491
747
|
if (entry.component)
|
|
492
|
-
entry.html = await
|
|
748
|
+
entry.html = await globalThis.$fetch(entry.path);
|
|
493
749
|
}
|
|
494
750
|
for (const k in screenshotQueue) {
|
|
495
751
|
const entry = screenshotQueue[k];
|
|
496
752
|
const start = Date.now();
|
|
497
753
|
let hasError = false;
|
|
498
|
-
const
|
|
499
|
-
const filename = joinURL(
|
|
754
|
+
const dirname2 = joinURL(nitro.options.output.publicDir, entry.route, "/__og_image__/");
|
|
755
|
+
const filename = joinURL(dirname2, "/og.png");
|
|
500
756
|
try {
|
|
501
757
|
const imgBuffer = await screenshot(browser, {
|
|
502
758
|
...config.defaults || {},
|
|
@@ -504,7 +760,7 @@ export async function useProvider(provider) {
|
|
|
504
760
|
host
|
|
505
761
|
});
|
|
506
762
|
try {
|
|
507
|
-
await mkdirp(
|
|
763
|
+
await mkdirp(dirname2);
|
|
508
764
|
} catch (e) {
|
|
509
765
|
}
|
|
510
766
|
await writeFile(filename, imgBuffer);
|