nuxt-og-image 3.0.0-beta.3 → 3.0.0-beta.30

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 (124) hide show
  1. package/README.md +3 -3
  2. package/dist/client/200.html +5 -5
  3. package/dist/client/404.html +5 -5
  4. package/dist/client/_nuxt/{IconCSS.e8427024.js → IconCSS.157c2ef5.js} +1 -1
  5. package/dist/client/_nuxt/IconCSS.7e8f1f7b.css +1 -0
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/2f3b82b2-c809-4818-a70e-0a9fa0dde8cb.json +1 -0
  8. package/dist/client/_nuxt/entry.74866e06.js +137 -0
  9. package/dist/client/_nuxt/entry.f47d0628.css +1 -0
  10. package/dist/client/_nuxt/{error-404.b1c8e4c8.js → error-404.d663cd65.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.6b97e3ab.js → error-500.8c184504.js} +1 -1
  12. package/dist/client/index.html +5 -5
  13. package/dist/module.d.mts +43 -25
  14. package/dist/module.d.ts +43 -25
  15. package/dist/module.json +2 -2
  16. package/dist/module.mjs +146 -93
  17. package/dist/runtime/cache.d.ts +7 -10
  18. package/dist/runtime/cache.mjs +40 -27
  19. package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
  20. package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
  21. package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
  22. package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
  23. package/dist/runtime/components/Templates/{Official → Community}/BrandedLogo.vue +3 -2
  24. package/dist/runtime/components/Templates/Community/Nuxt.vue +6 -5
  25. package/dist/runtime/components/Templates/Community/NuxtSeo.vue +137 -0
  26. package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
  27. package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
  28. package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
  29. package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
  30. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  31. package/dist/runtime/composables/defineOgImage.mjs +33 -116
  32. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  33. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  34. package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
  35. package/dist/runtime/composables/defineOgImageScreenshot.mjs +14 -0
  36. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  37. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  38. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -3
  39. package/dist/runtime/core/bindings/satori/wasm.mjs +7 -0
  40. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  41. package/dist/runtime/core/cache/emojis.mjs +5 -0
  42. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  43. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  44. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  45. package/dist/runtime/core/font/fetch.d.ts +2 -3
  46. package/dist/runtime/core/font/fetch.mjs +20 -8
  47. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  48. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  49. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  50. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  51. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  52. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  53. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  54. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  55. package/dist/runtime/core/options/fetch.d.ts +1 -1
  56. package/dist/runtime/core/options/fetch.mjs +10 -5
  57. package/dist/runtime/core/options/normalise.d.ts +2 -2
  58. package/dist/runtime/core/options/normalise.mjs +3 -2
  59. package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
  60. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  61. package/dist/runtime/core/renderers/chromium/screenshot.mjs +5 -4
  62. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  63. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  64. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  65. package/dist/runtime/core/renderers/satori/index.mjs +25 -22
  66. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  67. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  68. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  69. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +8 -4
  70. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  71. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +38 -0
  72. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  73. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  74. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  75. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  76. package/dist/runtime/core/utils/resolveRendererContext.mjs +46 -23
  77. package/dist/runtime/core/utils/wasm.d.ts +1 -0
  78. package/dist/runtime/core/utils/wasm.mjs +10 -0
  79. package/dist/runtime/nitro/plugins/nuxt-content.mjs +3 -4
  80. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  81. package/dist/runtime/nitro/plugins/prerender.mjs +13 -5
  82. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +31 -0
  83. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -50
  84. package/dist/runtime/nuxt/utils.d.ts +2 -0
  85. package/dist/runtime/nuxt/utils.mjs +53 -0
  86. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +1 -3
  87. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +4 -8
  88. package/dist/runtime/server/routes/__og-image__/image.mjs +87 -0
  89. package/dist/runtime/types.d.ts +74 -25
  90. package/dist/runtime/utils.d.ts +4 -0
  91. package/dist/runtime/utils.mjs +11 -0
  92. package/dist/runtime/utils.pure.d.ts +5 -0
  93. package/dist/runtime/utils.pure.mjs +43 -0
  94. package/package.json +27 -29
  95. package/virtual.d.ts +49 -0
  96. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  97. package/dist/client/_nuxt/builds/meta/af7b6f15-8224-4a19-bb3a-f685b2b145c3.json +0 -1
  98. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  99. package/dist/client/_nuxt/entry.8ea61ef1.js +0 -137
  100. package/dist/client/grid.png +0 -0
  101. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  102. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  103. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  104. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  105. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  106. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  107. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  108. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  109. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  110. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  111. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  112. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  113. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  114. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  115. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  116. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  117. package/dist/runtime/core/html/fetch.d.ts +0 -3
  118. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  119. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  120. package/dist/runtime/utilts.d.ts +0 -2
  121. package/dist/runtime/utilts.mjs +0 -8
  122. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → wasm.d.ts} +0 -0
  123. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  124. /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
package/dist/module.mjs CHANGED
@@ -1,15 +1,17 @@
1
1
  import * as fs from 'node:fs';
2
2
  import { existsSync } from 'node:fs';
3
- import { useNuxt, createResolver, addTemplate, addServerPlugin, defineNuxtModule, useLogger, hasNuxtModule, addPlugin, addServerHandler, addImports, addComponentsDir, addComponent } from '@nuxt/kit';
3
+ import { loadNuxtModuleInstance, useNuxt, createResolver, addTemplate, resolvePath, defineNuxtModule, useLogger, hasNuxtModule, addServerPlugin, addServerHandler, addImports, addComponentsDir, addComponent, addPlugin } from '@nuxt/kit';
4
4
  import { installNuxtSiteConfig } from 'nuxt-site-config-kit';
5
- import { provider, env } from 'std-env';
5
+ import { provider, env, isDevelopment } from 'std-env';
6
6
  import { hash } from 'ohash';
7
- import { relative } from 'pathe';
8
- import 'nypm';
7
+ import { relative, dirname } from 'pathe';
9
8
  import { defu } from 'defu';
9
+ import 'nypm';
10
10
  import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
11
+ import { readFile, writeFile } from 'node:fs/promises';
12
+ import { createHash } from 'node:crypto';
11
13
 
12
- const version = "3.0.0-beta.3";
14
+ const version = "3.0.0-beta.30";
13
15
 
14
16
  const autodetectableProviders = {
15
17
  azure_static: "azure",
@@ -32,18 +34,19 @@ const NodeRuntime = {
32
34
  "resvg": "node",
33
35
  "satori": "node",
34
36
  "sharp": "node"
35
- },
36
- wasmStrategy: "import"
37
+ }
37
38
  };
38
39
  const cloudflare = {
39
40
  bindings: {
40
41
  "chromium": false,
41
- "css-inline": "node",
42
+ "css-inline": false,
42
43
  "resvg": "wasm",
43
44
  "satori": "node",
44
45
  "sharp": false
45
46
  },
46
- wasmStrategy: "import"
47
+ wasm: {
48
+ esmImport: true
49
+ }
47
50
  };
48
51
  const awsLambda = {
49
52
  bindings: {
@@ -52,8 +55,7 @@ const awsLambda = {
52
55
  "resvg": "node",
53
56
  "satori": "node",
54
57
  "sharp": "node"
55
- },
56
- wasmStrategy: "inline"
58
+ }
57
59
  };
58
60
  const RuntimeCompatibility = {
59
61
  "nitro-dev": NodeRuntime,
@@ -62,45 +64,48 @@ const RuntimeCompatibility = {
62
64
  "stackblitz": {
63
65
  bindings: {
64
66
  "chromium": false,
65
- "css-inline": "node",
67
+ "css-inline": false,
66
68
  "resvg": "wasm",
67
- "satori": "node",
68
- "sharp": "node"
69
+ "satori": "wasm",
70
+ "sharp": false
69
71
  },
70
- wasmStrategy: "inline"
72
+ wasm: {
73
+ rollup: {
74
+ targetEnv: "auto-inline",
75
+ sync: ["@resvg/resvg-wasm/index_bg.wasm"]
76
+ }
77
+ }
71
78
  },
72
79
  "aws-lambda": awsLambda,
73
80
  "netlify": awsLambda,
74
81
  "netlify-edge": {
75
82
  bindings: {
76
83
  "chromium": false,
77
- "css-inline": "node",
84
+ "css-inline": false,
78
85
  "resvg": "wasm",
79
86
  "satori": "node",
80
- "sharp": "node"
87
+ "sharp": false
81
88
  },
82
- wasmStrategy: "inline"
83
- },
84
- "vercel": {
85
- bindings: {
86
- "chromium": false,
87
- "css-inline": "node",
88
- "resvg": "wasm",
89
- "satori": "node",
90
- "sharp": "node"
91
- },
92
- wasmStrategy: "inline"
89
+ wasm: {
90
+ rollup: {
91
+ targetEnv: "auto-inline",
92
+ sync: ["@resvg/resvg-wasm/index_bg.wasm"]
93
+ }
94
+ }
93
95
  },
96
+ "vercel": awsLambda,
94
97
  "vercel-edge": {
95
98
  bindings: {
96
99
  "chromium": false,
97
- "css-inline": "node",
100
+ "css-inline": false,
98
101
  "resvg": "wasm",
99
102
  "satori": "node",
100
- "sharp": "node"
103
+ "sharp": false
101
104
  },
102
- wasmStrategy: "inline",
103
- wasmImportQuery: "?module"
105
+ wasm: {
106
+ // lowers workers kb size
107
+ esmImport: true
108
+ }
104
109
  },
105
110
  "cloudflare-pages": cloudflare,
106
111
  "cloudflare": cloudflare
@@ -141,15 +146,37 @@ function applyNitroPresetCompatibility(nitroConfig, options) {
141
146
  applyBinding("satori"),
142
147
  applyBinding("resvg"),
143
148
  applyBinding("sharp"),
149
+ applyBinding("css-inline"),
144
150
  nitroConfig.alias || {}
145
151
  );
146
- if (target.includes("cloudflare")) {
147
- nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
148
- nitroConfig.rollupConfig.output.inlineDynamicImports = true;
152
+ if (Object.values(compatibility.bindings).includes("wasm")) {
153
+ nitroConfig.experimental = nitroConfig.experimental || {};
154
+ nitroConfig.experimental.wasm = true;
149
155
  }
156
+ nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
157
+ nitroConfig.wasm = defu(compatibility.wasm, nitroConfig.wasm);
150
158
  return compatibility;
151
159
  }
152
160
 
161
+ async function getNuxtModuleOptions(module, nuxt = useNuxt()) {
162
+ const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
163
+ const { nuxtModule } = await loadNuxtModuleInstance(module, nuxt);
164
+ let moduleEntry;
165
+ for (const m of nuxt.options.modules) {
166
+ if (Array.isArray(m) && m.length >= 2) {
167
+ const _module = m[0];
168
+ const _moduleEntryName = typeof _module === "string" ? _module : (await _module.getMeta?.())?.name || "";
169
+ if (_moduleEntryName === moduleMeta.name)
170
+ moduleEntry = m;
171
+ }
172
+ }
173
+ let inlineOptions = {};
174
+ if (moduleEntry)
175
+ inlineOptions = moduleEntry[1];
176
+ if (nuxtModule.getOptions)
177
+ return nuxtModule.getOptions(inlineOptions, nuxt);
178
+ return inlineOptions;
179
+ }
153
180
  function extendTypes(module, template) {
154
181
  const nuxt = useNuxt();
155
182
  const { resolve } = createResolver(import.meta.url);
@@ -226,8 +253,8 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
226
253
  function setupDevHandler(options, resolve, nuxt = useNuxt()) {
227
254
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
228
255
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = options.runtimeSatori ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
229
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = options.runtimeBrowser ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
230
- applyNitroPresetCompatibility(nitroConfig, { resolve });
256
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = options.runtimeChromium ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
257
+ applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: options.runtimeCompatibility });
231
258
  });
232
259
  }
233
260
 
@@ -251,12 +278,13 @@ function setupGenerateHandler(options, resolve, nuxt = useNuxt()) {
251
278
  }
252
279
 
253
280
  function setupPrerenderHandler(options, resolve, nuxt = useNuxt()) {
254
- addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
255
281
  nuxt.hooks.hook("nitro:init", async (nitro) => {
256
282
  nitro.hooks.hook("prerender:config", async (nitroConfig) => {
257
283
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = resolve("./runtime/core/renderers/satori");
258
284
  nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = resolve("./runtime/core/renderers/chromium");
259
285
  applyNitroPresetCompatibility(nitroConfig, { resolve });
286
+ nitroConfig.wasm = nitroConfig.wasm || {};
287
+ nitroConfig.wasm.esmImport = false;
260
288
  });
261
289
  });
262
290
  }
@@ -267,20 +295,41 @@ async function setupBuildHandler(config, resolve, nuxt = useNuxt()) {
267
295
  nuxt.options.nitro.storage["og-image"] = config.runtimeCacheStorage;
268
296
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
269
297
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = config.runtimeSatori ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
270
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = config.runtimeBrowser ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
298
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = config.runtimeChromium ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
271
299
  applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: config.runtimeCompatibility });
272
300
  nitroConfig.alias.electron = "unenv/runtime/mock/proxy-cjs";
273
301
  nitroConfig.alias.bufferutil = "unenv/runtime/mock/proxy-cjs";
274
302
  nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
275
303
  nitroConfig.alias.queue = "unenv/runtime/mock/proxy-cjs";
276
304
  });
305
+ nuxt.hooks.hook("nitro:init", async (nitro) => {
306
+ nitro.hooks.hook("compiled", async (_nitro) => {
307
+ const target = resolveNitroPreset(_nitro.options);
308
+ const compatibility = getPresetNitroPresetCompatibility(target);
309
+ if (compatibility.wasm?.esmImport !== true)
310
+ return;
311
+ const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
312
+ let serverEntry = resolve(_nitro.options.output.serverDir, typeof configuredEntry === "string" ? configuredEntry : "index.mjs");
313
+ if (target === "cloudflare-pages")
314
+ serverEntry = resolve(dirname(serverEntry), "./chunks/wasm.mjs");
315
+ const contents = await readFile(serverEntry, "utf-8");
316
+ const resvgHash = sha1(await readFile(await resolvePath("@resvg/resvg-wasm/index_bg.wasm")));
317
+ const yogaHash = sha1(await readFile(await resolvePath("yoga-wasm-web/dist/yoga.wasm")));
318
+ const postfix = target === "vercel-edge" ? "?module" : "";
319
+ const path = target === "cloudflare-pages" ? `../wasm/` : `./wasm/`;
320
+ await writeFile(serverEntry, contents.replaceAll('"@resvg/resvg-wasm/index_bg.wasm"', `"${path}index_bg-${resvgHash}.wasm${postfix}"`).replaceAll('"yoga-wasm-web/dist/yoga.wasm"', `"${path}yoga-${yogaHash}.wasm${postfix}"`), { encoding: "utf-8" });
321
+ });
322
+ });
323
+ }
324
+ function sha1(source) {
325
+ return createHash("sha1").update(source).digest("hex").slice(0, 16);
277
326
  }
278
327
 
279
328
  const module = defineNuxtModule({
280
329
  meta: {
281
330
  name: "nuxt-og-image",
282
331
  compatibility: {
283
- nuxt: "^3.7.0",
332
+ nuxt: "^3.8.2",
284
333
  bridge: false
285
334
  },
286
335
  configKey: "ogImage"
@@ -289,21 +338,20 @@ const module = defineNuxtModule({
289
338
  return {
290
339
  enabled: true,
291
340
  defaults: {
341
+ emojis: "noto",
292
342
  renderer: "satori",
293
- component: "Fallback",
343
+ component: "NuxtSeo",
294
344
  width: 1200,
295
345
  height: 600,
296
- cache: true,
297
346
  // default is to cache the image for 1 day (24 hours)
298
- cacheTtl: 24 * 60 * 60 * 1e3
347
+ cacheMaxAgeSeconds: 60 * 60 * 24 * 3
299
348
  },
300
349
  componentDirs: ["OgImage", "OgImageTemplate"],
301
- runtimeSatori: true,
302
- runtimeBrowser: nuxt.options.dev,
303
350
  fonts: [],
304
351
  runtimeCacheStorage: true,
305
- playground: env.NODE_ENV === "development" || nuxt.options.dev,
306
- debug: false
352
+ runtimeSatori: true,
353
+ runtimeChromium: nuxt.options.dev,
354
+ debug: isDevelopment
307
355
  };
308
356
  },
309
357
  async setup(config, nuxt) {
@@ -320,14 +368,20 @@ const module = defineNuxtModule({
320
368
  const { resolve } = createResolver(import.meta.url);
321
369
  const preset = resolveNitroPreset(nuxt.options.nitro);
322
370
  const compatibility = getPresetNitroPresetCompatibility(preset);
323
- config.defaults.extension = "jpg";
324
- if (!compatibility.bindings.sharp)
371
+ const userConfiguredExtension = config.defaults.extension;
372
+ config.defaults.extension = userConfiguredExtension || "jpg";
373
+ if (!compatibility.bindings.sharp && config.defaults.renderer !== "chromium") {
374
+ if (userConfiguredExtension && ["jpeg", "jpg"].includes(userConfiguredExtension))
375
+ logger.warn("The sharp runtime is not available for this target, disabling sharp and using png instead.");
325
376
  config.defaults.extension = "png";
377
+ }
378
+ if (config.runtimeChromium && !compatibility.bindings.chromium) {
379
+ logger.warn("The Chromium runtime is not available for this target, disabling runtimeChromium.");
380
+ config.runtimeChromium = false;
381
+ }
326
382
  await installNuxtSiteConfig();
327
- if (hasNuxtModule("@nuxt/content")) {
383
+ if (hasNuxtModule("@nuxt/content"))
328
384
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
329
- addPlugin(resolve("./runtime/nuxt/plugins/nuxt-content-canonical-urls"));
330
- }
331
385
  if (!config.fonts.length)
332
386
  config.fonts = ["Inter:400", "Inter:700"];
333
387
  nuxt.options.experimental.componentIslands = true;
@@ -346,52 +400,34 @@ const module = defineNuxtModule({
346
400
  addServerHandler({
347
401
  lazy: true,
348
402
  route: "/__og-image__/image/**",
349
- handler: resolve("./runtime/server/routes/__og-image__/image-[path]-og.[extension]")
403
+ handler: resolve("./runtime/server/routes/__og-image__/image")
350
404
  });
351
405
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"] = [];
352
- [
353
- // deprecated
354
- "Dynamic",
355
- "Static",
356
- // new
357
- "index",
358
- "Cached",
359
- "Component",
360
- "WithoutCache",
361
- "Screenshot"
362
- ].forEach((name) => {
363
- name = name === "index" ? "defineOgImage" : `defineOgImage${name}`;
406
+ ["defineOgImage", "defineOgImageComponent", "defineOgImageScreenshot"].forEach((name) => {
364
407
  addImports({
365
408
  name,
366
- from: resolve("./runtime/composables/defineOgImage")
409
+ from: resolve(`./runtime/composables/${name}`)
367
410
  });
368
411
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
369
412
  });
370
413
  await addComponentsDir({
371
414
  path: resolve("./runtime/components/Templates/Community"),
372
- island: true
373
- });
374
- await addComponentsDir({
375
- path: resolve("./runtime/components/Templates/Official"),
376
- island: true
415
+ island: true,
416
+ watch: true
377
417
  });
378
418
  [
379
- // deprecated
380
- "Static",
381
- "Dynamic",
382
419
  // new
383
- "index",
384
- "Cached",
385
- "WithoutCache",
386
- "Screenshot"
420
+ "OgImage",
421
+ "OgImageScreenshot"
387
422
  ].forEach((name) => {
388
423
  addComponent({
389
- global: hasNuxtModule("@nuxt/content"),
390
- name: name === "index" ? "OgImage" : `OgImage${name}`,
424
+ name,
425
+ global: true,
391
426
  filePath: resolve(`./runtime/components/OgImage/${name}`)
392
427
  });
393
428
  });
394
- addPlugin(resolve("./runtime/nuxt/plugins/route-rule-og-image.server"));
429
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/route-rule-og-image.server") });
430
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/og-image-canonical-urls.server") });
395
431
  const ogImageComponentCtx = { components: [] };
396
432
  nuxt.hook("components:extend", (components) => {
397
433
  ogImageComponentCtx.components = [];
@@ -409,8 +445,6 @@ const module = defineNuxtModule({
409
445
  let category = "app";
410
446
  if (component.filePath.includes(resolve("./runtime/components/Templates/Community")))
411
447
  category = "community";
412
- else if (component.filePath.includes(resolve("./runtime/components/Templates/Official")))
413
- category = "official";
414
448
  const componentFile = fs.readFileSync(component.filePath, "utf-8");
415
449
  const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
416
450
  ogImageComponentCtx.components.push({
@@ -437,6 +471,16 @@ const module = defineNuxtModule({
437
471
  nuxt.options.nitro.virtual["#nuxt-og-image/component-names.mjs"] = () => {
438
472
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
439
473
  };
474
+ let unoCssConfig = { theme: {} };
475
+ nuxt.hook("tailwindcss:config", (tailwindConfig) => {
476
+ unoCssConfig = defu(tailwindConfig.theme.extend, { ...tailwindConfig.theme || {}, extend: void 0 });
477
+ });
478
+ nuxt.hook("unocss:config", (_unoCssConfig) => {
479
+ unoCssConfig = { ..._unoCssConfig.theme };
480
+ });
481
+ nuxt.options.nitro.virtual["#nuxt-og-image/unocss-config.mjs"] = () => {
482
+ return `export const theme = ${JSON.stringify(unoCssConfig)}`;
483
+ };
440
484
  extendTypes("nuxt-og-image", ({ typesPath }) => {
441
485
  const componentImports = ogImageComponentCtx.components.map((component) => {
442
486
  const relativeComponentPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), component.path);
@@ -445,12 +489,13 @@ const module = defineNuxtModule({
445
489
  return `
446
490
  declare module 'nitropack' {
447
491
  interface NitroRouteRules {
448
- ogImage?: false | import('${typesPath}').OgImageOptions
492
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
449
493
  }
450
494
  interface NitroRouteConfig {
451
- ogImage?: false | import('${typesPath}').OgImageOptions
495
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
452
496
  }
453
497
  }
498
+
454
499
  declare module '#nuxt-og-image/components' {
455
500
  export interface OgImageComponents {
456
501
  ${componentImports}
@@ -458,6 +503,11 @@ ${componentImports}
458
503
  }
459
504
  `;
460
505
  });
506
+ const cacheEnabled = typeof config.runtimeCacheStorage !== "undefined" && config.runtimeCacheStorage !== false;
507
+ const runtimeCacheStorage = typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver;
508
+ let baseCacheKey = runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${version}` : `/nuxt-og-image@${version}`;
509
+ if (!cacheEnabled)
510
+ baseCacheKey = false;
461
511
  nuxt.hooks.hook("modules:done", async () => {
462
512
  nuxt.hooks.callHook("og-image:config", config);
463
513
  const normalisedFonts = config.fonts.map((f) => {
@@ -478,6 +528,9 @@ ${componentImports}
478
528
  nuxt.options.nitro.prerender.routes.push(`/__og-image__/font/${name}/${weight}.ttf`);
479
529
  });
480
530
  }
531
+ let colorPreference = hasNuxtModule("@nuxtjs/color-mode") ? (await getNuxtModuleOptions("@nuxtjs/color-mode")).preference : "light";
532
+ if (!colorPreference || !["dark", "light"].includes(colorPreference))
533
+ colorPreference = "light";
481
534
  nuxt.options.runtimeConfig["nuxt-og-image"] = {
482
535
  version,
483
536
  // binding options
@@ -485,18 +538,17 @@ ${componentImports}
485
538
  resvgOptions: config.resvgOptions || {},
486
539
  sharpOptions: config.sharpOptions || {},
487
540
  runtimeSatori: config.runtimeSatori,
488
- runtimeBrowser: config.runtimeBrowser,
489
- // @ts-expect-error runtime type
541
+ runtimeChromium: config.runtimeChromium,
490
542
  defaults: config.defaults,
543
+ debug: config.debug,
491
544
  // avoid adding credentials
492
- runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
545
+ baseCacheKey,
493
546
  // convert the fonts to uniform type to fix ts issue
494
547
  fonts: normalisedFonts,
495
- hasNuxtIcon: hasNuxtModule("nuxt-icon")
548
+ hasNuxtIcon: hasNuxtModule("nuxt-icon"),
549
+ colorPreference
496
550
  };
497
551
  });
498
- nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
499
- nuxt.options.nitro.experimental.wasm = true;
500
552
  if (nuxt.options.dev) {
501
553
  setupDevHandler(config, resolve);
502
554
  setupDevToolsUI(config, resolve);
@@ -505,8 +557,9 @@ ${componentImports}
505
557
  } else if (nuxt.options.build) {
506
558
  await setupBuildHandler(config, resolve);
507
559
  }
508
- if (nuxt.options.nitro.prerender?.routes || nuxt.options._generate)
509
- setupPrerenderHandler(config, resolve);
560
+ if (nuxt.options.nitro.prerender?.routes?.length || nuxt.options.nitro.prerender?.crawlLinks || nuxt.options._generate)
561
+ addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
562
+ setupPrerenderHandler(config, resolve);
510
563
  }
511
564
  });
512
565
 
@@ -1,12 +1,9 @@
1
- import type { H3Event } from 'h3';
2
- export declare function useNitroCache<T>(e: H3Event, options: {
3
- key: string;
4
- cacheTtl: number;
5
- cache: boolean;
6
- headers: boolean;
7
- skipRestore?: boolean;
8
- }): Promise<{
9
- cachedItem: false | T;
1
+ import type { H3EventOgImageRender } from './types';
2
+ export declare function useOgImageBufferCache(ctx: H3EventOgImageRender, options: {
3
+ baseCacheKey: string | false;
4
+ cacheMaxAgeSeconds?: number;
5
+ }): Promise<void | {
6
+ cachedItem: false | BufferSource;
10
7
  enabled: boolean;
11
- update: (item: T) => Promise<void>;
8
+ update: (image: BufferSource) => Promise<void>;
12
9
  }>;
@@ -1,45 +1,58 @@
1
1
  import { prefixStorage } from "unstorage";
2
- import { getQuery, setHeader } from "h3";
3
- import { useRuntimeConfig, useStorage } from "#imports";
4
- export async function useNitroCache(e, options) {
5
- const module = "nuxt-og-image";
6
- const { runtimeCacheStorage, version } = useRuntimeConfig()[module];
7
- const enabled = options.cache && runtimeCacheStorage && options.cacheTtl && options.cacheTtl > 0;
8
- const baseCacheKey = runtimeCacheStorage === "default" ? `/cache/${module}@${version}` : `/${module}@${version}`;
9
- const cache = prefixStorage(useStorage(), `${baseCacheKey}/`);
10
- const key = options.key;
11
- let xCacheHeader = "DISABLED";
12
- let xCacheExpires = 0;
13
- const newExpires = Date.now() + (options.cacheTtl || 0);
14
- const purge = typeof getQuery(e).purge !== "undefined";
2
+ import { getQuery, handleCacheHeaders, setHeader, setHeaders } from "h3";
3
+ import { withTrailingSlash } from "ufo";
4
+ import { hash } from "ohash";
5
+ import { useStorage } from "#imports";
6
+ export async function useOgImageBufferCache(ctx, options) {
7
+ const maxAge = Number(options.cacheMaxAgeSeconds);
8
+ const enabled = !import.meta.dev && import.meta.env.MODE !== "test" && maxAge > 0;
9
+ const cache = prefixStorage(useStorage(), withTrailingSlash(options.baseCacheKey || "/"));
10
+ const key = ctx.key;
15
11
  let cachedItem = false;
16
- if (!options.skipRestore && enabled && await cache.hasItem(key).catch(() => false)) {
17
- const { value, expiresAt } = await cache.getItem(key).catch(() => ({ value: null, expiresAt: Date.now() }));
18
- if (purge) {
19
- xCacheHeader = "PURGE";
20
- xCacheExpires = newExpires;
12
+ if (enabled && await cache.hasItem(key).catch(() => false)) {
13
+ const { value, expiresAt, headers } = await cache.getItem(key).catch(() => ({ value: null, expiresAt: Date.now() }));
14
+ if (typeof getQuery(ctx.e).purge !== "undefined") {
21
15
  await cache.removeItem(key).catch(() => {
22
16
  });
23
17
  } else if (expiresAt > Date.now()) {
24
- xCacheHeader = "HIT";
25
- xCacheExpires = newExpires;
26
- cachedItem = value;
18
+ cachedItem = Buffer.from(value, "base64");
19
+ if (handleCacheHeaders(ctx.e, {
20
+ modifiedTime: new Date(headers["last-modified"]),
21
+ etag: headers.etag,
22
+ maxAge
23
+ }))
24
+ return;
25
+ setHeaders(ctx.e, headers);
27
26
  } else {
28
- xCacheHeader = "MISS";
29
- xCacheExpires = expiresAt;
30
27
  await cache.removeItem(key).catch(() => {
31
28
  });
32
29
  }
33
30
  }
34
- if (options.headers) {
35
- setHeader(e, `x-${module}-cache`, xCacheHeader);
36
- setHeader(e, `x-${module}-expires`, xCacheExpires.toString());
31
+ if (!enabled) {
32
+ setHeader(ctx.e, "Cache-Control", "no-cache, no-store, must-revalidate");
33
+ setHeader(ctx.e, "Pragma", "no-cache");
34
+ setHeader(ctx.e, "Expires", "0");
37
35
  }
38
36
  return {
39
37
  enabled,
40
38
  cachedItem,
41
39
  async update(item) {
42
- enabled && await cache.setItem(key, { value: item, expiresAt: Date.now() + (options.cacheTtl || 0) });
40
+ if (!enabled)
41
+ return;
42
+ const value = Buffer.from(item).toString("base64");
43
+ const headers = {
44
+ // avoid multi-tenancy cache issues
45
+ "Vary": "accept-encoding, host",
46
+ "etag": `W/"${hash(value)}"`,
47
+ "last-modified": (/* @__PURE__ */ new Date()).toUTCString(),
48
+ "cache-control": `public, s-maxage=${maxAge}, stale-while-revalidate`
49
+ };
50
+ setHeaders(ctx.e, headers);
51
+ await cache.setItem(key, {
52
+ value,
53
+ headers,
54
+ expiresAt: Date.now() + maxAge * 1e3
55
+ });
43
56
  }
44
57
  };
45
58
  }
@@ -0,0 +1,5 @@
1
+ import type { OgImageOptions } from '../../types';
2
+ declare const _default: import("vue").DefineComponent<OgImageOptions<"NuxtSeo">, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<OgImageOptions<"NuxtSeo">>, {
3
+ props?: any;
4
+ }, {}>;
5
+ export default _default;
@@ -4,7 +4,7 @@ export default defineComponent({
4
4
  name: "OgImage",
5
5
  async setup(_, { attrs }) {
6
6
  if (import.meta.server)
7
- await defineOgImage(attrs);
7
+ defineOgImage(attrs);
8
8
  return () => null;
9
9
  }
10
10
  });
@@ -0,0 +1,5 @@
1
+ import type { OgImagePageScreenshotOptions } from '../../types';
2
+ declare const _default: import("vue").DefineComponent<OgImagePageScreenshotOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<OgImagePageScreenshotOptions>, {
3
+ props?: any;
4
+ }, {}>;
5
+ export default _default;
@@ -4,7 +4,7 @@ export default defineComponent({
4
4
  name: "OgImageScreenshot",
5
5
  async setup(_, { attrs }) {
6
6
  if (import.meta.server)
7
- await defineOgImageScreenshot(attrs);
7
+ defineOgImageScreenshot(attrs);
8
8
  return () => null;
9
9
  }
10
10
  });
@@ -1,6 +1,7 @@
1
1
  <script setup lang="ts">
2
- // inherited attrs can mess up the satori parser
3
- defineOptions({ inheritAttrs: false })
2
+ /**
3
+ * @credits Full Stack Heroes <https://fullstackheroes.com/>
4
+ */
4
5
 
5
6
  withDefaults(defineProps<{
6
7
  title?: string
@@ -3,14 +3,15 @@
3
3
  * @credits NuxtLabs <https://nuxtlabs.com/>
4
4
  * @see https://github.com/nuxt/nuxt.com/blob/main/components/OgImage/OgImageDocs.vue
5
5
  */
6
+ import { computed } from 'vue'
6
7
 
7
- defineOptions({ inheritAttrs: false })
8
-
9
- withDefaults(defineProps<{ title?: string, description?: string, headline?: string }>(), {
8
+ const props = withDefaults(defineProps<{ title?: string, description?: string, headline?: string }>(), {
10
9
  title: 'title',
11
10
  description: 'description',
12
11
  headline: 'headline',
13
12
  })
13
+
14
+ const title = computed(() => props.title.slice(0, 60))
14
15
  </script>
15
16
 
16
17
  <template>
@@ -43,11 +44,11 @@ withDefaults(defineProps<{ title?: string, description?: string, headline?: stri
43
44
  </defs>
44
45
  </svg>
45
46
 
46
- <div class="w-[700px] pl-[100px]">
47
+ <div class="w-[600px] pl-[100px]">
47
48
  <p v-if="headline" class="uppercase text-[24px] text-[#00DC82] mb-4 font-semibold">
48
49
  {{ headline }}
49
50
  </p>
50
- <h1 class="m-0 text-[75px] font-semibold mb-4 text-white flex items-center">
51
+ <h1 class="w-[600px] m-0 text-[75px] font-semibold mb-4 text-white flex items-center">
51
52
  <span>{{ title }}</span>
52
53
  </h1>
53
54
  <p class="text-[32px] text-[#E4E4E7] leading-tight">