nuxt-og-image 1.3.1 → 1.4.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 +5 -1
- package/dist/client/200.html +2 -2
- package/dist/client/404.html +2 -2
- package/dist/client/_nuxt/{index.7072fbd5.css → IFrameLoader.7072fbd5.css} +0 -0
- package/dist/client/_nuxt/IFrameLoader.d5909035.js +1 -0
- package/dist/client/_nuxt/Icon.403b6716.css +1 -0
- package/dist/client/_nuxt/Icon.60a95afe.js +1 -0
- package/dist/client/_nuxt/Icon.vue.a2ec08e3.js +1 -0
- package/dist/client/_nuxt/ImageLoader.a4ce18ac.js +1 -0
- package/dist/client/_nuxt/NButton.694cef96.js +1 -0
- package/dist/client/_nuxt/NButton.vue.ab05bc78.js +1 -0
- package/dist/client/_nuxt/NCard.73524dd1.js +1 -0
- package/dist/client/_nuxt/NCheckbox.d5ba4120.js +1 -0
- package/dist/client/_nuxt/NDarkToggle.687abd18.js +1 -0
- package/dist/client/_nuxt/NDarkToggle.vue.f7f2dd0a.js +1 -0
- package/dist/client/_nuxt/NDialog.44534c12.js +7 -0
- package/dist/client/_nuxt/NDropdown.29d0f6c4.js +1 -0
- package/dist/client/_nuxt/NIcon.af04832c.js +1 -0
- package/dist/client/_nuxt/NIcon.vue.4a86e248.js +1 -0
- package/dist/client/_nuxt/NLink.7b890d54.js +1 -0
- package/dist/client/_nuxt/NLink.vue.1c7b39cf.js +1 -0
- package/dist/client/_nuxt/NRadio.1079a996.js +1 -0
- package/dist/client/_nuxt/NSwitch.28e8e7c4.js +1 -0
- package/dist/client/_nuxt/NTextInput.dd5d77f0.js +1 -0
- package/dist/client/_nuxt/NTextInput.vue.9b6f61da.js +1 -0
- package/dist/client/_nuxt/NTip.a2522c9e.js +1 -0
- package/dist/client/_nuxt/NuxtContentLogo.b33b5adb.js +1 -0
- package/dist/client/_nuxt/NuxtExampleLayout.5726c1e7.js +1 -0
- package/dist/client/_nuxt/NuxtLogo.c4101b4a.js +1 -0
- package/dist/client/_nuxt/UnoIcon.3704f042.js +1 -0
- package/dist/client/_nuxt/_plugin-vue_export-helper.c27b6911.js +1 -0
- package/dist/client/_nuxt/app.config.d5ed556c.js +1 -0
- package/dist/client/_nuxt/client-only.a160727e.js +4 -0
- package/dist/client/_nuxt/component.vue3.3c33ad5e.js +1 -0
- package/dist/client/_nuxt/components.client.a14db737.js +1 -0
- package/dist/client/_nuxt/components.def83447.js +1 -0
- package/dist/client/_nuxt/composables.b3b1407e.js +1 -0
- package/dist/client/_nuxt/dev-only.3974795b.js +1 -0
- package/dist/client/_nuxt/entry.3a708ff1.css +1 -0
- package/dist/client/_nuxt/entry.87ffbf0a.js +1 -0
- package/dist/client/_nuxt/error-404.1469f10f.css +1 -0
- package/dist/client/_nuxt/error-404.6ae4da09.js +1 -0
- package/dist/client/_nuxt/error-500.0e359581.js +1 -0
- package/dist/client/_nuxt/error-500.92b94fae.css +1 -0
- package/dist/client/_nuxt/error-component.e464704a.js +3 -0
- package/dist/client/_nuxt/index.0662c04b.js +1 -0
- package/dist/client/_nuxt/index.8da3b00c.js +1 -0
- package/dist/client/_nuxt/index.f6e5e2e7.js +1 -0
- package/dist/client/_nuxt/layout.ac370415.js +1 -0
- package/dist/client/_nuxt/logic.439aa142.js +1 -0
- package/dist/client/_nuxt/nuxt-error-boundary.550746e3.js +1 -0
- package/dist/client/_nuxt/nuxt-link.3b9becb1.js +1 -0
- package/dist/client/_nuxt/nuxt-loading-indicator.de8802c9.js +1 -0
- package/dist/client/_nuxt/options.582fe505.js +1 -0
- package/dist/client/_nuxt/page.b8634cae.js +1 -0
- package/dist/client/_nuxt/png.24020c5d.js +1 -0
- package/dist/client/_nuxt/runtime-core.esm-bundler.d2479180.js +1 -0
- package/dist/client/_nuxt/runtime-dom.esm-bundler.f4f35d78.js +1 -0
- package/dist/client/_nuxt/server-placeholder.8ed08e3a.js +1 -0
- package/dist/client/_nuxt/{shiki.69102a86.js → shiki.13470033.js} +5 -5
- package/dist/client/_nuxt/state.4540d876.js +1 -0
- package/dist/client/_nuxt/svg.e70dde70.js +1 -0
- package/dist/client/_nuxt/utils.b6c92ff8.js +5 -0
- package/dist/client/_nuxt/vnodes.25b95d99.js +1 -0
- package/dist/client/_nuxt/welcome.db724adb.css +1 -0
- package/dist/client/_nuxt/welcome.dd0c800c.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 +3 -2
- package/dist/module.json +1 -1
- package/dist/module.mjs +66 -43
- package/dist/runtime/components/OgImageBasic.island.vue +1 -1
- package/dist/runtime/composables/defineOgImage.mjs +8 -7
- package/dist/runtime/nitro/{routes/__og_image__ → middleware}/og.png.d.ts +0 -0
- package/dist/runtime/nitro/{routes/__og_image__ → middleware}/og.png.mjs +4 -4
- package/dist/runtime/nitro/{routes/__og_image__/index.d.ts → middleware/playground.d.ts} +0 -0
- package/dist/runtime/nitro/{routes/__og_image__/index.mjs → middleware/playground.mjs} +4 -4
- package/dist/runtime/nitro/providers/browser/lambda.d.ts +1 -0
- package/dist/runtime/nitro/{browsers → providers/browser}/lambda.mjs +1 -1
- package/dist/runtime/nitro/providers/browser/node.d.ts +1 -0
- package/dist/runtime/nitro/{browsers/default.mjs → providers/browser/node.mjs} +1 -1
- package/dist/runtime/nitro/providers/satori/node.d.ts +2 -0
- package/dist/runtime/nitro/providers/satori/node.mjs +4 -0
- package/dist/runtime/nitro/providers/satori/webworker.d.ts +4 -0
- package/dist/runtime/nitro/providers/satori/webworker.mjs +11 -0
- package/dist/runtime/nitro/providers/svg2png/universal.d.ts +4 -0
- package/dist/runtime/nitro/providers/svg2png/universal.mjs +9 -0
- package/dist/runtime/nitro/renderers/browser.d.ts +3 -0
- package/dist/runtime/nitro/{providers → renderers}/browser.mjs +5 -2
- package/dist/runtime/nitro/renderers/satori/index.d.ts +3 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/index.mjs +14 -8
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/emojis.d.ts +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/emojis.mjs +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/flex.d.ts +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/flex.mjs +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/imageSrc.d.ts +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/imageSrc.mjs +2 -1
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/twClasses.d.ts +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/plugins/twClasses.mjs +0 -0
- package/dist/runtime/nitro/{providers → renderers}/satori/utils.d.ts +1 -4
- package/dist/runtime/nitro/renderers/satori/utils.mjs +45 -0
- package/dist/runtime/nitro/routes/{__og_image__/font.d.ts → font.d.ts} +0 -0
- package/dist/runtime/nitro/routes/{__og_image__/font.mjs → font.mjs} +1 -1
- package/dist/runtime/nitro/routes/{__og_image__/html.d.ts → html.d.ts} +0 -0
- package/dist/runtime/nitro/routes/{__og_image__/html.mjs → html.mjs} +9 -8
- package/dist/runtime/nitro/routes/{__og_image__/options.d.ts → options.d.ts} +2 -2
- package/dist/runtime/nitro/routes/{__og_image__/options.mjs → options.mjs} +6 -9
- package/dist/runtime/nitro/routes/{__og_image__/svg.d.ts → svg.d.ts} +0 -0
- package/dist/runtime/nitro/routes/svg.mjs +11 -0
- package/dist/runtime/nitro/routes/{__og_image__/vnode.d.ts → vnode.d.ts} +0 -0
- package/dist/runtime/nitro/routes/vnode.mjs +11 -0
- package/dist/runtime/nitro/utils.d.ts +9 -1
- package/dist/runtime/nitro/utils.mjs +75 -10
- package/dist/runtime/{public → public-assets}/inter-latin-ext-400-normal.woff +0 -0
- package/dist/runtime/{public → public-assets}/inter-latin-ext-700-normal.woff +0 -0
- package/dist/runtime/public-assets/svg2png.wasm +0 -0
- package/dist/runtime/public-assets/yoga.wasm +0 -0
- package/package.json +10 -8
- package/dist/client/_nuxt/ImageLoader.be226b50.js +0 -1
- package/dist/client/_nuxt/entry.3dc1b14c.js +0 -5
- package/dist/client/_nuxt/entry.9f5c391a.css +0 -1
- package/dist/client/_nuxt/error-404.68aa58b4.css +0 -1
- package/dist/client/_nuxt/error-404.9a311ab2.js +0 -1
- package/dist/client/_nuxt/error-500.dc5710d1.css +0 -1
- package/dist/client/_nuxt/error-500.f8d3032e.js +0 -1
- package/dist/client/_nuxt/error-component.a4dd1ebc.js +0 -3
- package/dist/client/_nuxt/index.dea39ba2.js +0 -1
- package/dist/client/_nuxt/options.53a4a6ca.js +0 -1
- package/dist/client/_nuxt/png.6a754041.js +0 -1
- package/dist/client/_nuxt/svg.afcae77d.js +0 -1
- package/dist/client/_nuxt/vnodes.dd40690d.js +0 -1
- package/dist/runtime/nitro/browsers/default.d.ts +0 -1
- package/dist/runtime/nitro/browsers/lambda.d.ts +0 -1
- package/dist/runtime/nitro/providers/browser.d.ts +0 -3
- package/dist/runtime/nitro/providers/satori/index.d.ts +0 -3
- package/dist/runtime/nitro/providers/satori/utils.mjs +0 -69
- package/dist/runtime/nitro/resvg/node.d.ts +0 -3
- package/dist/runtime/nitro/resvg/node.mjs +0 -6
- package/dist/runtime/nitro/resvg/wasm.d.ts +0 -2
- package/dist/runtime/nitro/resvg/wasm.mjs +0 -32
- package/dist/runtime/nitro/routes/__og_image__/svg.mjs +0 -16
- package/dist/runtime/nitro/routes/__og_image__/vnode.mjs +0 -16
package/dist/module.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { existsSync } from 'fs';
|
|
1
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
3
2
|
import { useNuxt, addTemplate, defineNuxtModule, createResolver, addServerHandler, addImports, addComponent } from '@nuxt/kit';
|
|
4
3
|
import { execa } from 'execa';
|
|
5
4
|
import chalk from 'chalk';
|
|
@@ -9,8 +8,9 @@ import { joinURL } from 'ufo';
|
|
|
9
8
|
import { resolve, relative } from 'pathe';
|
|
10
9
|
import { tinyws } from 'tinyws';
|
|
11
10
|
import sirv from 'sirv';
|
|
12
|
-
import { copy } from 'fs-extra';
|
|
11
|
+
import { pathExists, copy, mkdirp } from 'fs-extra';
|
|
13
12
|
import { provider } from 'std-env';
|
|
13
|
+
import { existsSync } from 'fs';
|
|
14
14
|
import { createBirpcGroup } from 'birpc';
|
|
15
15
|
import { stringify, parse } from 'flatted';
|
|
16
16
|
|
|
@@ -197,7 +197,6 @@ const module = defineNuxtModule({
|
|
|
197
197
|
},
|
|
198
198
|
defaults(nuxt) {
|
|
199
199
|
return {
|
|
200
|
-
experimentalNitroBrowser: false,
|
|
201
200
|
// when we run `nuxi generate` we need to force prerendering
|
|
202
201
|
forcePrerender: !nuxt.options.dev && nuxt.options._generate,
|
|
203
202
|
host: nuxt.options.runtimeConfig.public?.siteUrl,
|
|
@@ -206,6 +205,8 @@ const module = defineNuxtModule({
|
|
|
206
205
|
width: 1200,
|
|
207
206
|
height: 630
|
|
208
207
|
},
|
|
208
|
+
satoriProvider: true,
|
|
209
|
+
browserProvider: true,
|
|
209
210
|
fonts: [],
|
|
210
211
|
satoriOptions: {}
|
|
211
212
|
};
|
|
@@ -221,7 +222,6 @@ const module = defineNuxtModule({
|
|
|
221
222
|
return resolve(`../dist/${p}`);
|
|
222
223
|
};
|
|
223
224
|
nuxt.options.experimental.componentIslands = true;
|
|
224
|
-
const isEdge = provider === "stackblitz" || (process.env.NITRO_PRESET || "").includes("edge");
|
|
225
225
|
addTemplate({
|
|
226
226
|
filename: "nuxt-og-image.d.ts",
|
|
227
227
|
getContents: () => {
|
|
@@ -240,16 +240,17 @@ export {}
|
|
|
240
240
|
nuxt.hooks.hook("prepare:types", ({ references }) => {
|
|
241
241
|
references.push({ path: resolve(nuxt.options.buildDir, "nuxt-og-image.d.ts") });
|
|
242
242
|
});
|
|
243
|
-
|
|
243
|
+
addServerHandler({
|
|
244
|
+
lazy: true,
|
|
245
|
+
handler: resolve("./runtime/nitro/middleware/og.png")
|
|
246
|
+
});
|
|
247
|
+
["html", "options", "svg", "vnode", "font"].forEach((type) => {
|
|
244
248
|
addServerHandler({
|
|
245
249
|
lazy: true,
|
|
246
|
-
|
|
250
|
+
route: `/api/og-image-${type}`,
|
|
251
|
+
handler: resolve(`./runtime/nitro/routes/${type}`)
|
|
247
252
|
});
|
|
248
253
|
});
|
|
249
|
-
addServerHandler({
|
|
250
|
-
route: "/api/og-image-font",
|
|
251
|
-
handler: resolve("./runtime/nitro/routes/__og_image__/font")
|
|
252
|
-
});
|
|
253
254
|
nuxt.hook("devtools:customTabs", (iframeTabs) => {
|
|
254
255
|
iframeTabs.push({
|
|
255
256
|
name: "ogimage",
|
|
@@ -266,14 +267,14 @@ export {}
|
|
|
266
267
|
const {
|
|
267
268
|
middleware: rpcMiddleware
|
|
268
269
|
} = setupPlaygroundRPC(nuxt, config);
|
|
269
|
-
nuxt.hook("vite:serverCreated", (server) => {
|
|
270
|
+
nuxt.hook("vite:serverCreated", async (server) => {
|
|
270
271
|
server.middlewares.use(PATH_ENTRY, tinyws());
|
|
271
272
|
server.middlewares.use(PATH_ENTRY, rpcMiddleware);
|
|
272
|
-
if (
|
|
273
|
+
if (await pathExists(playgroundDir))
|
|
273
274
|
server.middlewares.use(PATH_PLAYGROUND, sirv(playgroundDir, { single: true, dev: true }));
|
|
274
275
|
});
|
|
275
276
|
addServerHandler({
|
|
276
|
-
handler: resolve("./runtime/nitro/
|
|
277
|
+
handler: resolve("./runtime/nitro/middleware/playground")
|
|
277
278
|
});
|
|
278
279
|
}
|
|
279
280
|
["defineOgImageDynamic", "defineOgImageStatic", "defineOgImageScreenshot"].forEach((name) => {
|
|
@@ -297,45 +298,67 @@ export {}
|
|
|
297
298
|
});
|
|
298
299
|
const runtimeDir = resolve("./runtime");
|
|
299
300
|
nuxt.options.build.transpile.push(runtimeDir);
|
|
300
|
-
const
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
});
|
|
306
|
-
nuxt.
|
|
301
|
+
const moduleAssetDir = resolve("./runtime/public-assets");
|
|
302
|
+
const assetDirs = [
|
|
303
|
+
resolve(nuxt.options.rootDir, nuxt.options.dir.public),
|
|
304
|
+
moduleAssetDir
|
|
305
|
+
];
|
|
306
|
+
exposeModuleConfig("nuxt-og-image", { ...config, assetDirs });
|
|
307
|
+
const nitroPreset = process.env.NITRO_PRESET || nuxt.options.nitro.preset;
|
|
308
|
+
const isWebWorkerEnv = process.env.NODE_ENV !== "development" && (provider === "stackblitz" || ["cloudflare", "vercel-edge", "netlify-edge", "lambda"].includes(nitroPreset));
|
|
309
|
+
nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
|
|
307
310
|
nitroConfig.externals = defu(nitroConfig.externals || {}, {
|
|
308
311
|
inline: [runtimeDir]
|
|
309
312
|
});
|
|
310
313
|
nitroConfig.publicAssets = nitroConfig.publicAssets || [];
|
|
311
|
-
nitroConfig.publicAssets.push({ dir:
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
314
|
+
nitroConfig.publicAssets.push({ dir: moduleAssetDir, maxAge: 31536e3 });
|
|
315
|
+
const providerPath = `${runtimeDir}/nitro/providers`;
|
|
316
|
+
if (config.browserProvider) {
|
|
317
|
+
nitroConfig.virtual["#nuxt-og-image/browser"] = `
|
|
318
|
+
export default async function() {
|
|
319
|
+
return (process.env.prerender || process.env.dev === 'true') ? await import('${providerPath}/browser/node').then(m => m.default) : () => {}
|
|
320
|
+
}
|
|
321
|
+
`;
|
|
322
|
+
}
|
|
323
|
+
if (config.satoriProvider) {
|
|
324
|
+
nitroConfig.virtual["#nuxt-og-image/satori"] = isWebWorkerEnv ? `export default async function() {
|
|
325
|
+
return (process.env.prerender || process.env.dev === 'true') ? await import('${providerPath}/satori/webworker').then(m => m.default) : await import('${providerPath}/satori/webworker').then(m => m.default)
|
|
326
|
+
}` : `import node from '${providerPath}/satori/node';
|
|
327
|
+
export default function() {
|
|
328
|
+
return node
|
|
329
|
+
}
|
|
330
|
+
`;
|
|
331
|
+
nitroConfig.virtual["#nuxt-og-image/svg2png"] = `export default async function() {
|
|
332
|
+
return await import('${providerPath}/svg2png/universal').then(m => m.default)
|
|
333
|
+
}`;
|
|
334
|
+
}
|
|
317
335
|
nitroConfig.virtual["#nuxt-og-image/provider"] = `
|
|
318
|
-
|
|
319
|
-
import browser from '${runtimeDir}/nitro/providers/browser'
|
|
320
|
-
|
|
321
|
-
export function useProvider(provider) {
|
|
336
|
+
export async function useProvider(provider) {
|
|
322
337
|
if (provider === 'satori')
|
|
323
|
-
return satori
|
|
338
|
+
return ${config.satoriProvider ? `await import('${relative(nuxt.options.rootDir, resolve("./runtime/nitro/renderers/satori"))}').then(m => m.default)` : null}
|
|
324
339
|
if (provider === 'browser')
|
|
325
|
-
return browser
|
|
340
|
+
return (process.env.prerender || process.env.dev) ? ${config.browserProvider ? `await import('${relative(nuxt.options.rootDir, resolve("./runtime/nitro/renderers/browser"))}').then(m => m.default)` : null} : null
|
|
326
341
|
}
|
|
327
342
|
`;
|
|
328
|
-
if (config.experimentalNitroBrowser) {
|
|
329
|
-
nitroConfig.virtual["#nuxt-og-image/providers/browser"] = `export * from '${runtimeDir}/nitro/providers/browser'`;
|
|
330
|
-
if (isEdge) {
|
|
331
|
-
["puppeteer", "bufferutil", "utf-8-validate"].forEach((name) => {
|
|
332
|
-
nitroConfig.alias[name] = "unenv/runtime/mock/proxy";
|
|
333
|
-
});
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
343
|
});
|
|
337
344
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
338
345
|
let screenshotQueue = [];
|
|
346
|
+
nitro.hooks.hook("compiled", async (_nitro) => {
|
|
347
|
+
if (_nitro.options.preset === "cloudflare" || _nitro.options.preset === "vercel-edge") {
|
|
348
|
+
await copy(resolve("./runtime/public-assets/inter-latin-ext-400-normal.woff"), resolve(_nitro.options.output.publicDir, "inter-latin-ext-400-normal.woff"));
|
|
349
|
+
await copy(resolve("./runtime/public-assets/inter-latin-ext-700-normal.woff"), resolve(_nitro.options.output.publicDir, "inter-latin-ext-700-normal.woff"));
|
|
350
|
+
await copy(resolve("./runtime/public-assets/svg2png.wasm"), resolve(_nitro.options.output.serverDir, "svg2png.wasm"));
|
|
351
|
+
await copy(resolve("./runtime/public-assets/yoga.wasm"), resolve(_nitro.options.output.serverDir, "yoga.wasm"));
|
|
352
|
+
const indexFile = resolve(_nitro.options.output.serverDir, "index.mjs");
|
|
353
|
+
if (await pathExists(indexFile)) {
|
|
354
|
+
const indexContents = await readFile(indexFile, "utf-8");
|
|
355
|
+
await writeFile(
|
|
356
|
+
indexFile,
|
|
357
|
+
indexContents.replace('"/* NUXT_OG_IMAGE_SVG2PNG_WASM */"', 'import("./svg2png.wasm").then(m => m.default || m)').replace('"/* NUXT_OG_IMAGE_YOGA_WASM */"', 'import("./yoga.wasm").then(m => m.default || m)').replace(".cwd(),", '?.cwd || "/",')
|
|
358
|
+
);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
});
|
|
339
362
|
const _routeRulesMatcher = toRouteMatcher(
|
|
340
363
|
createRouter({ routes: nitro.options.routeRules })
|
|
341
364
|
);
|
|
@@ -356,7 +379,7 @@ export {}
|
|
|
356
379
|
...routeRules.ogImage || {},
|
|
357
380
|
ctx
|
|
358
381
|
};
|
|
359
|
-
if ((nuxt.options._generate || options.
|
|
382
|
+
if ((nuxt.options._generate || options.static) && options.provider === "browser")
|
|
360
383
|
screenshotQueue.push(options);
|
|
361
384
|
});
|
|
362
385
|
if (nuxt.options.dev)
|
|
@@ -390,7 +413,7 @@ export {}
|
|
|
390
413
|
...entry || {}
|
|
391
414
|
});
|
|
392
415
|
try {
|
|
393
|
-
await
|
|
416
|
+
await mkdirp(dirname);
|
|
394
417
|
} catch (e) {
|
|
395
418
|
}
|
|
396
419
|
await writeFile(filename, imgBuffer);
|
|
@@ -2,27 +2,28 @@ import { useServerHead } from "@vueuse/head";
|
|
|
2
2
|
import { withBase } from "ufo";
|
|
3
3
|
import { useRequestEvent } from "#app";
|
|
4
4
|
import { useRouter } from "#imports";
|
|
5
|
-
import { defaults, forcePrerender, host } from "#nuxt-og-image/config";
|
|
5
|
+
import { defaults, forcePrerender, host, satoriProvider } from "#nuxt-og-image/config";
|
|
6
6
|
export function defineOgImageScreenshot(options = {}) {
|
|
7
7
|
const router = useRouter();
|
|
8
8
|
const route = router?.currentRoute?.value?.path || "";
|
|
9
9
|
defineOgImage({
|
|
10
10
|
alt: `Web page screenshot${route ? ` of ${route}` : ""}.`,
|
|
11
11
|
provider: "browser",
|
|
12
|
-
|
|
12
|
+
static: true,
|
|
13
13
|
...options
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
export function defineOgImageDynamic(options = {}) {
|
|
17
17
|
defineOgImage({
|
|
18
|
-
provider: "satori",
|
|
18
|
+
provider: satoriProvider ? "satori" : "browser",
|
|
19
|
+
static: !!forcePrerender,
|
|
19
20
|
...options
|
|
20
21
|
});
|
|
21
22
|
}
|
|
22
23
|
export function defineOgImageStatic(options = {}) {
|
|
23
24
|
defineOgImage({
|
|
24
|
-
provider: "satori",
|
|
25
|
-
|
|
25
|
+
provider: satoriProvider ? "satori" : "browser",
|
|
26
|
+
static: true,
|
|
26
27
|
...options
|
|
27
28
|
});
|
|
28
29
|
}
|
|
@@ -31,7 +32,7 @@ export function defineOgImage(options = {}) {
|
|
|
31
32
|
const router = useRouter();
|
|
32
33
|
const route = router?.currentRoute?.value?.path || "";
|
|
33
34
|
const e = useRequestEvent();
|
|
34
|
-
if ((forcePrerender || options.
|
|
35
|
+
if ((forcePrerender || options.static) && options.provider === "satori")
|
|
35
36
|
e.res.setHeader("x-nitro-prerender", `${route === "/" ? "" : route}/__og_image__/og.png`);
|
|
36
37
|
const meta = [
|
|
37
38
|
{
|
|
@@ -40,7 +41,7 @@ export function defineOgImage(options = {}) {
|
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
43
|
property: "og:image",
|
|
43
|
-
content: () => withBase(`${route}/__og_image__/og.png`, host)
|
|
44
|
+
content: () => withBase(`${route === "/" ? "" : route}/__og_image__/og.png`, host)
|
|
44
45
|
},
|
|
45
46
|
{
|
|
46
47
|
property: "og:image:width",
|
|
File without changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler, setHeader } from "h3";
|
|
2
|
-
import {
|
|
3
|
-
import { fetchOptions, useHostname } from "
|
|
2
|
+
import { parseURL, withBase, withoutTrailingSlash } from "ufo";
|
|
3
|
+
import { fetchOptions, useHostname } from "../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
5
|
export default defineEventHandler(async (e) => {
|
|
6
6
|
const path = parseURL(e.path).pathname;
|
|
@@ -9,11 +9,11 @@ export default defineEventHandler(async (e) => {
|
|
|
9
9
|
const basePath = withoutTrailingSlash(
|
|
10
10
|
path.replace("__og_image__/og.png", "")
|
|
11
11
|
);
|
|
12
|
-
const options = await fetchOptions(basePath);
|
|
13
12
|
setHeader(e, "Content-Type", "image/png");
|
|
14
13
|
setHeader(e, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
15
14
|
setHeader(e, "Pragma", "no-cache");
|
|
16
15
|
setHeader(e, "Expires", "0");
|
|
16
|
+
const options = await fetchOptions(e, basePath);
|
|
17
17
|
const provider = await useProvider(options.provider);
|
|
18
|
-
return provider.createPng(withBase(
|
|
18
|
+
return provider.createPng(withBase(basePath, useHostname(e)), options);
|
|
19
19
|
});
|
|
File without changes
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { defineEventHandler } from "h3";
|
|
2
2
|
import { parseURL, withoutTrailingSlash } from "ufo";
|
|
3
|
-
import { fetchOptions } from "
|
|
3
|
+
import { fetchOptions } from "../utils.mjs";
|
|
4
4
|
export default defineEventHandler(async (e) => {
|
|
5
|
-
const path = parseURL(e.path).pathname;
|
|
5
|
+
const path = withoutTrailingSlash(parseURL(e.path).pathname);
|
|
6
6
|
if (!path.endsWith("/__og_image__"))
|
|
7
7
|
return;
|
|
8
|
-
const basePath =
|
|
9
|
-
const options = await fetchOptions(basePath);
|
|
8
|
+
const basePath = path.replace("/__og_image__", "");
|
|
9
|
+
const options = await fetchOptions(e, basePath === "" ? "/" : basePath);
|
|
10
10
|
if (!options)
|
|
11
11
|
return `The route ${basePath} has not been set up for og:image generation.`;
|
|
12
12
|
return `
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function createBrowser(): Promise<import("puppeteer-core").Browser>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import edgeChromium from "chrome-aws-lambda";
|
|
2
2
|
import puppeteer from "puppeteer-core";
|
|
3
|
-
export async function createBrowser() {
|
|
3
|
+
export default async function createBrowser() {
|
|
4
4
|
return puppeteer.launch({
|
|
5
5
|
args: edgeChromium.args,
|
|
6
6
|
executablePath: await edgeChromium.executablePath,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function createBrowser(): Promise<any>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import satori, { init } from "satori/wasm";
|
|
2
|
+
import initYoga from "yoga-wasm-web";
|
|
3
|
+
import { wasmLoader } from "../../utils.mjs";
|
|
4
|
+
export default async function(nodes, options) {
|
|
5
|
+
const loader = wasmLoader("/* NUXT_OG_IMAGE_YOGA_WASM */", "/yoga.wasm", options.baseUrl);
|
|
6
|
+
if (!await loader.loaded()) {
|
|
7
|
+
const yoga = await initYoga(await loader.load());
|
|
8
|
+
init(yoga);
|
|
9
|
+
}
|
|
10
|
+
return await satori(nodes, options);
|
|
11
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { initialize, svg2png } from "svg2png-wasm";
|
|
2
|
+
import { wasmLoader } from "../../utils.mjs";
|
|
3
|
+
export default async function(svg, options) {
|
|
4
|
+
const loader = wasmLoader("/* NUXT_OG_IMAGE_SVG2PNG_WASM */", "/svg2png.wasm", options.baseUrl);
|
|
5
|
+
if (!await loader.loaded())
|
|
6
|
+
await initialize(await loader.load()).catch(() => {
|
|
7
|
+
});
|
|
8
|
+
return await svg2png(svg, options);
|
|
9
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { screenshot } from "../../browserUtil.mjs";
|
|
2
|
-
import
|
|
2
|
+
import loadBrowser from "#nuxt-og-image/browser";
|
|
3
3
|
export default {
|
|
4
4
|
name: "browser",
|
|
5
5
|
createSvg: async function createSvg() {
|
|
@@ -9,7 +9,10 @@ export default {
|
|
|
9
9
|
throw new Error("Browser provider can't create VNodes.");
|
|
10
10
|
},
|
|
11
11
|
createPng: async function createPng(basePath, options) {
|
|
12
|
+
const createBrowser = await loadBrowser();
|
|
12
13
|
const browser = await createBrowser();
|
|
13
|
-
|
|
14
|
+
if (browser)
|
|
15
|
+
return screenshot(browser, basePath, options);
|
|
16
|
+
return null;
|
|
14
17
|
}
|
|
15
18
|
};
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { html as convertHtmlToSatori } from "satori-html";
|
|
2
|
-
import satori from "satori";
|
|
3
2
|
import { parseURL } from "ufo";
|
|
4
3
|
import twemoji from "twemoji";
|
|
5
4
|
import { loadFont, walkSatoriTree } from "./utils.mjs";
|
|
@@ -8,16 +7,21 @@ import twClasses from "./plugins/twClasses.mjs";
|
|
|
8
7
|
import flex from "./plugins/flex.mjs";
|
|
9
8
|
import emojis from "./plugins/emojis.mjs";
|
|
10
9
|
import { fonts, satoriOptions } from "#nuxt-og-image/config";
|
|
11
|
-
import
|
|
10
|
+
import loadSvg2png from "#nuxt-og-image/svg2png";
|
|
11
|
+
import loadSatori from "#nuxt-og-image/satori";
|
|
12
|
+
const satoriFonts = [];
|
|
12
13
|
export default {
|
|
13
14
|
name: "satori",
|
|
14
15
|
createPng: async function createPng(baseUrl, options) {
|
|
15
16
|
const svg = await this.createSvg(baseUrl, options);
|
|
16
|
-
|
|
17
|
+
const svg2png = await loadSvg2png();
|
|
18
|
+
return svg2png(svg, { baseUrl, ...options });
|
|
17
19
|
},
|
|
18
20
|
createVNode: async function createVNode(baseUrl, options) {
|
|
19
21
|
const url = parseURL(baseUrl);
|
|
20
|
-
const html = await
|
|
22
|
+
const html = await globalThis.$fetch("/api/og-image-html", {
|
|
23
|
+
query: { path: url.pathname, options: JSON.stringify(options) }
|
|
24
|
+
});
|
|
21
25
|
const body = html.match(/<body[^>]*>([\s\S]*)<\/body>/)?.[1];
|
|
22
26
|
const emojiedFont = twemoji.parse(body, {
|
|
23
27
|
folder: "svg",
|
|
@@ -34,13 +38,15 @@ export default {
|
|
|
34
38
|
return satoriTree;
|
|
35
39
|
},
|
|
36
40
|
createSvg: async function createSvg(baseUrl, options) {
|
|
37
|
-
const url = parseURL(baseUrl);
|
|
38
41
|
const vnodes = await this.createVNode(baseUrl, options);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
if (!satoriFonts.length) {
|
|
43
|
+
for (const font of fonts)
|
|
44
|
+
satoriFonts.push(await loadFont(new URL(baseUrl), font));
|
|
45
|
+
}
|
|
46
|
+
const satori = await loadSatori();
|
|
42
47
|
return await satori(vnodes, {
|
|
43
48
|
...satoriOptions,
|
|
49
|
+
baseUrl,
|
|
44
50
|
fonts: satoriFonts,
|
|
45
51
|
embedFont: true,
|
|
46
52
|
width: options.width,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { withBase } from "ufo";
|
|
2
|
-
import { defineSatoriTransformer
|
|
2
|
+
import { defineSatoriTransformer } from "../utils.mjs";
|
|
3
|
+
import { readPublicAssetBase64 } from "../../../utils.mjs";
|
|
3
4
|
export default defineSatoriTransformer((url) => {
|
|
4
5
|
return {
|
|
5
6
|
filter: (node) => node.type === "img",
|
|
File without changes
|
|
File without changes
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import type { ParsedURL } from 'ufo';
|
|
3
2
|
import type { SatoriTransformer, VNode } from '../../../../types';
|
|
4
|
-
export declare function
|
|
5
|
-
export declare function readPublicAssetBase64(file: string): Promise<string | undefined>;
|
|
6
|
-
export declare function loadFont(url: ParsedURL, font: string): Promise<any>;
|
|
3
|
+
export declare function loadFont(url: URL, font: string): Promise<any>;
|
|
7
4
|
export declare function walkSatoriTree(url: ParsedURL, node: VNode, plugins: SatoriTransformer[]): Promise<void>;
|
|
8
5
|
export declare function defineSatoriTransformer(transformer: (url: ParsedURL) => SatoriTransformer): (url: ParsedURL) => SatoriTransformer;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { base64ToArrayBuffer, readPublicAsset } from "../../utils.mjs";
|
|
2
|
+
import { useStorage } from "#internal/nitro";
|
|
3
|
+
const cachedFonts = {};
|
|
4
|
+
export async function loadFont(url, font) {
|
|
5
|
+
if (cachedFonts[font])
|
|
6
|
+
return cachedFonts[font];
|
|
7
|
+
let data;
|
|
8
|
+
const storageKey = `assets:nuxt-og-imagee:font:${font}`;
|
|
9
|
+
if (await useStorage().hasItem(storageKey)) {
|
|
10
|
+
data = base64ToArrayBuffer(await useStorage().getItem(storageKey));
|
|
11
|
+
return cachedFonts[font] = { name: font, data, style: "normal" };
|
|
12
|
+
}
|
|
13
|
+
const [name, weight] = font.split(":");
|
|
14
|
+
if (name === "Inter" && ["400", "700"].includes(weight)) {
|
|
15
|
+
const data2 = await readPublicAsset(`/inter-latin-ext-${weight}-normal.woff`);
|
|
16
|
+
if (data2)
|
|
17
|
+
return cachedFonts[font] = { name: font, data: data2, style: "normal" };
|
|
18
|
+
}
|
|
19
|
+
if (!data) {
|
|
20
|
+
const fontUrl = await globalThis.$fetch("/api/og-image-font", {
|
|
21
|
+
query: { name, weight }
|
|
22
|
+
});
|
|
23
|
+
data = await globalThis.$fetch(fontUrl, {
|
|
24
|
+
responseType: "arrayBuffer"
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
await useStorage().setItem(storageKey, Buffer.from(data).toString("base64"));
|
|
28
|
+
return cachedFonts[font] = { name, weight, data, style: "normal" };
|
|
29
|
+
}
|
|
30
|
+
export async function walkSatoriTree(url, node, plugins) {
|
|
31
|
+
if (!node.props?.children)
|
|
32
|
+
return;
|
|
33
|
+
for (const child of node.props.children || []) {
|
|
34
|
+
if (child) {
|
|
35
|
+
for (const plugin of plugins) {
|
|
36
|
+
if (plugin.filter(child))
|
|
37
|
+
await plugin.transform(child);
|
|
38
|
+
}
|
|
39
|
+
await walkSatoriTree(url, child, plugins);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
export function defineSatoriTransformer(transformer) {
|
|
44
|
+
return transformer;
|
|
45
|
+
}
|
|
File without changes
|
|
@@ -4,7 +4,7 @@ export default defineCachedEventHandler(async (e) => {
|
|
|
4
4
|
const { name, weight } = getQuery(e);
|
|
5
5
|
if (!name || !weight)
|
|
6
6
|
return "Provide a font name and weight";
|
|
7
|
-
const css = await await
|
|
7
|
+
const css = await await globalThis.$fetch(`https://fonts.googleapis.com/css2?family=${name}:wght@${weight}`, {
|
|
8
8
|
headers: {
|
|
9
9
|
// Make sure it returns TTF.
|
|
10
10
|
"User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
|
|
File without changes
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { withBase } from "ufo";
|
|
2
2
|
import { renderSSRHead } from "@unhead/ssr";
|
|
3
3
|
import { createHeadCore } from "@unhead/vue";
|
|
4
4
|
import { defineEventHandler, getQuery, sendRedirect } from "h3";
|
|
5
|
-
import { fetchOptions, renderIsland, useHostname } from "
|
|
5
|
+
import { fetchOptions, renderIsland, useHostname } from "../utils.mjs";
|
|
6
6
|
import { defaults, fonts } from "#nuxt-og-image/config";
|
|
7
7
|
export default defineEventHandler(async (e) => {
|
|
8
|
-
const path =
|
|
9
|
-
if (!path.endsWith("__og_image__/html"))
|
|
10
|
-
return;
|
|
11
|
-
const basePath = withoutTrailingSlash(path.replace("__og_image__/html", ""));
|
|
8
|
+
const path = getQuery(e).path || "/";
|
|
12
9
|
const scale = getQuery(e).scale;
|
|
13
|
-
|
|
10
|
+
let options;
|
|
11
|
+
if (getQuery(e).options)
|
|
12
|
+
options = JSON.parse(getQuery(e).options);
|
|
13
|
+
if (!options)
|
|
14
|
+
options = await fetchOptions(e, path);
|
|
14
15
|
if (options.provider === "browser")
|
|
15
|
-
return sendRedirect(e, withBase(
|
|
16
|
+
return sendRedirect(e, withBase(path, useHostname(e)));
|
|
16
17
|
const island = await renderIsland(options);
|
|
17
18
|
const head = createHeadCore();
|
|
18
19
|
head.push(island.head);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { OgImageOptions } from '
|
|
1
|
+
import type { OgImageOptions } from '../../../types';
|
|
2
2
|
export declare function extractOgImageOptions(html: string): any;
|
|
3
3
|
export declare const inferOgImageOptions: (html: string) => OgImageOptions;
|
|
4
|
-
declare const _default: import("h3").EventHandler<false | OgImageOptions
|
|
4
|
+
declare const _default: import("h3").EventHandler<false | OgImageOptions>;
|
|
5
5
|
export default _default;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { parseURL, withoutTrailingSlash } from "ufo";
|
|
2
1
|
import { defineEventHandler, getQuery } from "h3";
|
|
3
2
|
import { getRouteRules } from "#internal/nitro";
|
|
4
3
|
import { defaults } from "#nuxt-og-image/config";
|
|
@@ -21,22 +20,20 @@ export const inferOgImageOptions = (html) => {
|
|
|
21
20
|
return options;
|
|
22
21
|
};
|
|
23
22
|
export default defineEventHandler(async (e) => {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const basePath = withoutTrailingSlash(path.replace("__og_image__/options", ""));
|
|
28
|
-
const html = await $fetch(basePath);
|
|
23
|
+
const query = getQuery(e);
|
|
24
|
+
const path = query.path;
|
|
25
|
+
const html = await globalThis.$fetch(path);
|
|
29
26
|
const extractedPayload = extractOgImageOptions(html);
|
|
30
27
|
if (!extractedPayload)
|
|
31
28
|
return false;
|
|
32
|
-
e.node.req.url =
|
|
29
|
+
e.node.req.url = path;
|
|
33
30
|
e.context._nitro.routeRules = void 0;
|
|
34
31
|
const routeRules = getRouteRules(e)?.ogImage;
|
|
35
32
|
e.node.req.url = e.path;
|
|
36
33
|
if (routeRules === false)
|
|
37
34
|
return false;
|
|
38
35
|
return {
|
|
39
|
-
path
|
|
36
|
+
path,
|
|
40
37
|
...defaults,
|
|
41
38
|
// use inferred data
|
|
42
39
|
...inferOgImageOptions(html),
|
|
@@ -45,6 +42,6 @@ export default defineEventHandler(async (e) => {
|
|
|
45
42
|
// use provided data
|
|
46
43
|
...extractedPayload,
|
|
47
44
|
// use query data
|
|
48
|
-
...
|
|
45
|
+
...query
|
|
49
46
|
};
|
|
50
47
|
});
|
|
File without changes
|