nuxt-og-image 1.3.2 → 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.
Files changed (145) hide show
  1. package/README.md +3 -2
  2. package/dist/client/200.html +2 -2
  3. package/dist/client/404.html +2 -2
  4. package/dist/client/_nuxt/{index.7072fbd5.css → IFrameLoader.7072fbd5.css} +0 -0
  5. package/dist/client/_nuxt/IFrameLoader.d5909035.js +1 -0
  6. package/dist/client/_nuxt/Icon.403b6716.css +1 -0
  7. package/dist/client/_nuxt/Icon.60a95afe.js +1 -0
  8. package/dist/client/_nuxt/Icon.vue.a2ec08e3.js +1 -0
  9. package/dist/client/_nuxt/ImageLoader.a4ce18ac.js +1 -0
  10. package/dist/client/_nuxt/NButton.694cef96.js +1 -0
  11. package/dist/client/_nuxt/NButton.vue.ab05bc78.js +1 -0
  12. package/dist/client/_nuxt/NCard.73524dd1.js +1 -0
  13. package/dist/client/_nuxt/NCheckbox.d5ba4120.js +1 -0
  14. package/dist/client/_nuxt/NDarkToggle.687abd18.js +1 -0
  15. package/dist/client/_nuxt/NDarkToggle.vue.f7f2dd0a.js +1 -0
  16. package/dist/client/_nuxt/NDialog.44534c12.js +7 -0
  17. package/dist/client/_nuxt/NDropdown.29d0f6c4.js +1 -0
  18. package/dist/client/_nuxt/NIcon.af04832c.js +1 -0
  19. package/dist/client/_nuxt/NIcon.vue.4a86e248.js +1 -0
  20. package/dist/client/_nuxt/NLink.7b890d54.js +1 -0
  21. package/dist/client/_nuxt/NLink.vue.1c7b39cf.js +1 -0
  22. package/dist/client/_nuxt/NRadio.1079a996.js +1 -0
  23. package/dist/client/_nuxt/NSwitch.28e8e7c4.js +1 -0
  24. package/dist/client/_nuxt/NTextInput.dd5d77f0.js +1 -0
  25. package/dist/client/_nuxt/NTextInput.vue.9b6f61da.js +1 -0
  26. package/dist/client/_nuxt/NTip.a2522c9e.js +1 -0
  27. package/dist/client/_nuxt/NuxtContentLogo.b33b5adb.js +1 -0
  28. package/dist/client/_nuxt/NuxtExampleLayout.5726c1e7.js +1 -0
  29. package/dist/client/_nuxt/NuxtLogo.c4101b4a.js +1 -0
  30. package/dist/client/_nuxt/UnoIcon.3704f042.js +1 -0
  31. package/dist/client/_nuxt/_plugin-vue_export-helper.c27b6911.js +1 -0
  32. package/dist/client/_nuxt/app.config.d5ed556c.js +1 -0
  33. package/dist/client/_nuxt/client-only.a160727e.js +4 -0
  34. package/dist/client/_nuxt/component.vue3.3c33ad5e.js +1 -0
  35. package/dist/client/_nuxt/components.client.a14db737.js +1 -0
  36. package/dist/client/_nuxt/components.def83447.js +1 -0
  37. package/dist/client/_nuxt/composables.b3b1407e.js +1 -0
  38. package/dist/client/_nuxt/dev-only.3974795b.js +1 -0
  39. package/dist/client/_nuxt/entry.3a708ff1.css +1 -0
  40. package/dist/client/_nuxt/entry.87ffbf0a.js +1 -0
  41. package/dist/client/_nuxt/error-404.1469f10f.css +1 -0
  42. package/dist/client/_nuxt/error-404.6ae4da09.js +1 -0
  43. package/dist/client/_nuxt/error-500.0e359581.js +1 -0
  44. package/dist/client/_nuxt/error-500.92b94fae.css +1 -0
  45. package/dist/client/_nuxt/error-component.e464704a.js +3 -0
  46. package/dist/client/_nuxt/index.0662c04b.js +1 -0
  47. package/dist/client/_nuxt/index.8da3b00c.js +1 -0
  48. package/dist/client/_nuxt/index.f6e5e2e7.js +1 -0
  49. package/dist/client/_nuxt/layout.ac370415.js +1 -0
  50. package/dist/client/_nuxt/logic.439aa142.js +1 -0
  51. package/dist/client/_nuxt/nuxt-error-boundary.550746e3.js +1 -0
  52. package/dist/client/_nuxt/nuxt-link.3b9becb1.js +1 -0
  53. package/dist/client/_nuxt/nuxt-loading-indicator.de8802c9.js +1 -0
  54. package/dist/client/_nuxt/options.582fe505.js +1 -0
  55. package/dist/client/_nuxt/page.b8634cae.js +1 -0
  56. package/dist/client/_nuxt/png.24020c5d.js +1 -0
  57. package/dist/client/_nuxt/runtime-core.esm-bundler.d2479180.js +1 -0
  58. package/dist/client/_nuxt/runtime-dom.esm-bundler.f4f35d78.js +1 -0
  59. package/dist/client/_nuxt/server-placeholder.8ed08e3a.js +1 -0
  60. package/dist/client/_nuxt/{shiki.69102a86.js → shiki.13470033.js} +5 -5
  61. package/dist/client/_nuxt/state.4540d876.js +1 -0
  62. package/dist/client/_nuxt/svg.e70dde70.js +1 -0
  63. package/dist/client/_nuxt/utils.b6c92ff8.js +5 -0
  64. package/dist/client/_nuxt/vnodes.25b95d99.js +1 -0
  65. package/dist/client/_nuxt/welcome.db724adb.css +1 -0
  66. package/dist/client/_nuxt/welcome.dd0c800c.js +1 -0
  67. package/dist/client/index.html +2 -2
  68. package/dist/client/options/index.html +2 -2
  69. package/dist/client/png/index.html +2 -2
  70. package/dist/client/svg/index.html +2 -2
  71. package/dist/client/vnodes/index.html +2 -2
  72. package/dist/module.d.ts +3 -2
  73. package/dist/module.json +1 -1
  74. package/dist/module.mjs +66 -43
  75. package/dist/runtime/components/OgImageBasic.island.vue +1 -1
  76. package/dist/runtime/composables/defineOgImage.mjs +7 -6
  77. package/dist/runtime/nitro/{routes/__og_image__ → middleware}/og.png.d.ts +0 -0
  78. package/dist/runtime/nitro/{routes/__og_image__ → middleware}/og.png.mjs +4 -4
  79. package/dist/runtime/nitro/{routes/__og_image__/index.d.ts → middleware/playground.d.ts} +0 -0
  80. package/dist/runtime/nitro/{routes/__og_image__/index.mjs → middleware/playground.mjs} +4 -4
  81. package/dist/runtime/nitro/providers/browser/lambda.d.ts +1 -0
  82. package/dist/runtime/nitro/{browsers → providers/browser}/lambda.mjs +1 -1
  83. package/dist/runtime/nitro/providers/browser/node.d.ts +1 -0
  84. package/dist/runtime/nitro/{browsers/default.mjs → providers/browser/node.mjs} +1 -1
  85. package/dist/runtime/nitro/providers/satori/node.d.ts +2 -0
  86. package/dist/runtime/nitro/providers/satori/node.mjs +4 -0
  87. package/dist/runtime/nitro/providers/satori/webworker.d.ts +4 -0
  88. package/dist/runtime/nitro/providers/satori/webworker.mjs +11 -0
  89. package/dist/runtime/nitro/providers/svg2png/universal.d.ts +4 -0
  90. package/dist/runtime/nitro/providers/svg2png/universal.mjs +9 -0
  91. package/dist/runtime/nitro/renderers/browser.d.ts +3 -0
  92. package/dist/runtime/nitro/{providers → renderers}/browser.mjs +5 -2
  93. package/dist/runtime/nitro/renderers/satori/index.d.ts +3 -0
  94. package/dist/runtime/nitro/{providers → renderers}/satori/index.mjs +14 -8
  95. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/emojis.d.ts +0 -0
  96. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/emojis.mjs +0 -0
  97. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/flex.d.ts +0 -0
  98. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/flex.mjs +0 -0
  99. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/imageSrc.d.ts +0 -0
  100. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/imageSrc.mjs +2 -1
  101. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/twClasses.d.ts +0 -0
  102. package/dist/runtime/nitro/{providers → renderers}/satori/plugins/twClasses.mjs +0 -0
  103. package/dist/runtime/nitro/{providers → renderers}/satori/utils.d.ts +1 -4
  104. package/dist/runtime/nitro/renderers/satori/utils.mjs +45 -0
  105. package/dist/runtime/nitro/routes/{__og_image__/font.d.ts → font.d.ts} +0 -0
  106. package/dist/runtime/nitro/routes/{__og_image__/font.mjs → font.mjs} +1 -1
  107. package/dist/runtime/nitro/routes/{__og_image__/html.d.ts → html.d.ts} +0 -0
  108. package/dist/runtime/nitro/routes/{__og_image__/html.mjs → html.mjs} +9 -8
  109. package/dist/runtime/nitro/routes/{__og_image__/options.d.ts → options.d.ts} +2 -2
  110. package/dist/runtime/nitro/routes/{__og_image__/options.mjs → options.mjs} +6 -9
  111. package/dist/runtime/nitro/routes/{__og_image__/svg.d.ts → svg.d.ts} +0 -0
  112. package/dist/runtime/nitro/routes/svg.mjs +11 -0
  113. package/dist/runtime/nitro/routes/{__og_image__/vnode.d.ts → vnode.d.ts} +0 -0
  114. package/dist/runtime/nitro/routes/vnode.mjs +11 -0
  115. package/dist/runtime/nitro/utils.d.ts +9 -1
  116. package/dist/runtime/nitro/utils.mjs +75 -10
  117. package/dist/runtime/{public → public-assets}/inter-latin-ext-400-normal.woff +0 -0
  118. package/dist/runtime/{public → public-assets}/inter-latin-ext-700-normal.woff +0 -0
  119. package/dist/runtime/public-assets/svg2png.wasm +0 -0
  120. package/dist/runtime/public-assets/yoga.wasm +0 -0
  121. package/package.json +10 -8
  122. package/dist/client/_nuxt/ImageLoader.be226b50.js +0 -1
  123. package/dist/client/_nuxt/entry.3dc1b14c.js +0 -5
  124. package/dist/client/_nuxt/entry.9f5c391a.css +0 -1
  125. package/dist/client/_nuxt/error-404.68aa58b4.css +0 -1
  126. package/dist/client/_nuxt/error-404.9a311ab2.js +0 -1
  127. package/dist/client/_nuxt/error-500.dc5710d1.css +0 -1
  128. package/dist/client/_nuxt/error-500.f8d3032e.js +0 -1
  129. package/dist/client/_nuxt/error-component.a4dd1ebc.js +0 -3
  130. package/dist/client/_nuxt/index.dea39ba2.js +0 -1
  131. package/dist/client/_nuxt/options.53a4a6ca.js +0 -1
  132. package/dist/client/_nuxt/png.6a754041.js +0 -1
  133. package/dist/client/_nuxt/svg.afcae77d.js +0 -1
  134. package/dist/client/_nuxt/vnodes.dd40690d.js +0 -1
  135. package/dist/runtime/nitro/browsers/default.d.ts +0 -1
  136. package/dist/runtime/nitro/browsers/lambda.d.ts +0 -1
  137. package/dist/runtime/nitro/providers/browser.d.ts +0 -3
  138. package/dist/runtime/nitro/providers/satori/index.d.ts +0 -3
  139. package/dist/runtime/nitro/providers/satori/utils.mjs +0 -69
  140. package/dist/runtime/nitro/resvg/node.d.ts +0 -3
  141. package/dist/runtime/nitro/resvg/node.mjs +0 -6
  142. package/dist/runtime/nitro/resvg/wasm.d.ts +0 -2
  143. package/dist/runtime/nitro/resvg/wasm.mjs +0 -32
  144. package/dist/runtime/nitro/routes/__og_image__/svg.mjs +0 -16
  145. package/dist/runtime/nitro/routes/__og_image__/vnode.mjs +0 -16
package/dist/module.mjs CHANGED
@@ -1,5 +1,4 @@
1
- import { mkdir, writeFile } from 'node:fs/promises';
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
- ["html", "options", "svg", "vnode", "og.png"].forEach((type) => {
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
- handler: resolve(`./runtime/nitro/routes/__og_image__/${type}`)
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 (existsSync(playgroundDir))
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/routes/__og_image__/index")
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 fontDir = resolve(nuxt.options.buildDir, "nuxt-og-image");
301
- const publicDirs = [`${nuxt.options.rootDir}/public`, fontDir];
302
- exposeModuleConfig("nuxt-og-image", { ...config, publicDirs });
303
- nuxt.hooks.hook("build:before", async () => {
304
- await copy(resolve("./runtime/public"), resolve(nuxt.options.buildDir, "nuxt-og-image"));
305
- });
306
- nuxt.hooks.hook("nitro:config", (nitroConfig) => {
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: fontDir, maxAge: 31536e3 });
312
- if (isEdge && config.experimentalNitroBrowser)
313
- nitroConfig.virtual["#nuxt-og-image/browser"] = `export { createBrowser } from '${runtimeDir}/nitro/browsers/${isEdge ? "lambda" : "default"}'`;
314
- else
315
- nitroConfig.virtual["#nuxt-og-image/browser"] = `export { createBrowser } from '${runtimeDir}/nitro/browsers/default'`;
316
- nitroConfig.virtual["#nuxt-og-image/resvg"] = `import resvg from '${runtimeDir}/nitro/resvg/${isEdge ? "wasm" : "node"}'; export { resvg }`;
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
- import satori from '${runtimeDir}/nitro/providers/satori'
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.prerender) && options.provider === "browser")
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 mkdir(dirname, { recursive: true });
416
+ await mkdirp(dirname);
394
417
  } catch (e) {
395
418
  }
396
419
  await writeFile(filename, imgBuffer);
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- const props = defineProps({
2
+ defineProps({
3
3
  path: String,
4
4
  title: String,
5
5
  description: String,
@@ -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
- prerender: true,
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
- prerender: true,
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.prerender) && options.provider === "satori")
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
  {
@@ -1,6 +1,6 @@
1
1
  import { defineEventHandler, setHeader } from "h3";
2
- import { joinURL, parseURL, withBase, withoutTrailingSlash } from "ufo";
3
- import { fetchOptions, useHostname } from "../../utils.mjs";
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(joinURL(basePath, "/__og_image__/html"), useHostname(e)), options);
18
+ return provider.createPng(withBase(basePath, useHostname(e)), options);
19
19
  });
@@ -1,12 +1,12 @@
1
1
  import { defineEventHandler } from "h3";
2
2
  import { parseURL, withoutTrailingSlash } from "ufo";
3
- import { fetchOptions } from "../../utils.mjs";
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 = withoutTrailingSlash(path.replace("__og_image__", ""));
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>;
@@ -1,4 +1,4 @@
1
- export async function createBrowser() {
1
+ export default async function createBrowser() {
2
2
  try {
3
3
  const playwrightCore = await import(String("playwright-core"));
4
4
  const { Launcher } = await import(String("chrome-launcher"));
@@ -0,0 +1,2 @@
1
+ import type { SatoriOptions } from 'satori';
2
+ export default function (nodes: any, options: SatoriOptions): Promise<string>;
@@ -0,0 +1,4 @@
1
+ import satori from "satori";
2
+ export default function(nodes, options) {
3
+ return satori(nodes, options);
4
+ }
@@ -0,0 +1,4 @@
1
+ import type { SatoriOptions } from 'satori';
2
+ export default function (nodes: string, options: SatoriOptions & {
3
+ baseUrl: string;
4
+ }): 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,4 @@
1
+ import type { ConvertOptions } from 'svg2png-wasm';
2
+ export default function (svg: string, options: ConvertOptions & {
3
+ baseUrl: string;
4
+ }): Promise<Uint8Array>;
@@ -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
+ }
@@ -0,0 +1,3 @@
1
+ import type { Renderer } from '../../../types';
2
+ declare const _default: Renderer;
3
+ export default _default;
@@ -1,5 +1,5 @@
1
1
  import { screenshot } from "../../browserUtil.mjs";
2
- import { createBrowser } from "#nuxt-og-image/browser";
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
- return screenshot(browser, basePath, options);
14
+ if (browser)
15
+ return screenshot(browser, basePath, options);
16
+ return null;
14
17
  }
15
18
  };
@@ -0,0 +1,3 @@
1
+ import type { Renderer } from '../../../../types';
2
+ declare const _default: Renderer;
3
+ export default _default;
@@ -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 { resvg } from "#nuxt-og-image/resvg";
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
- return resvg(svg, options);
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 $fetch(url.pathname);
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
- const satoriFonts = [];
40
- for (const font of fonts)
41
- satoriFonts.push(await loadFont(url, font));
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,
@@ -1,5 +1,6 @@
1
1
  import { withBase } from "ufo";
2
- import { defineSatoriTransformer, readPublicAssetBase64 } from "../utils.mjs";
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",
@@ -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 readPublicAsset(file: string, encoding?: BufferEncoding): Promise<string | Buffer | undefined>;
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
+ }
@@ -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 $fetch(`https://fonts.googleapis.com/css2?family=${name}:wght@${weight}`, {
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"
@@ -1,18 +1,19 @@
1
- import { parseURL, withBase, withoutTrailingSlash } from "ufo";
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 "../../utils.mjs";
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 = parseURL(e.path).pathname;
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
- const options = await fetchOptions(basePath);
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(basePath, useHostname(e)));
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 '../../../../types';
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 | undefined>;
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 path = parseURL(e.path).pathname;
25
- if (!path.endsWith("__og_image__/options"))
26
- return;
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 = basePath;
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: basePath,
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
- ...getQuery(e)
45
+ ...query
49
46
  };
50
47
  });
@@ -0,0 +1,11 @@
1
+ import { defineEventHandler, getQuery, setHeader } from "h3";
2
+ import { withBase } from "ufo";
3
+ import { fetchOptions, useHostname } from "../utils.mjs";
4
+ import { useProvider } from "#nuxt-og-image/provider";
5
+ export default defineEventHandler(async (e) => {
6
+ const path = getQuery(e).path || "/";
7
+ const options = await fetchOptions(e, path);
8
+ setHeader(e, "Content-Type", "image/svg+xml");
9
+ const provider = await useProvider(options.provider);
10
+ return provider.createSvg(withBase(path, useHostname(e)), options);
11
+ });