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

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 (128) 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.06e6c904.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/eb64321b-b694-4f04-b8be-8bfdecc73293.json +1 -0
  8. package/dist/client/_nuxt/entry.5625a982.js +137 -0
  9. package/dist/client/_nuxt/entry.f47d0628.css +1 -0
  10. package/dist/client/_nuxt/{error-404.b1c8e4c8.js → error-404.ab2243fa.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.6b97e3ab.js → error-500.9440311e.js} +1 -1
  12. package/dist/client/index.html +5 -5
  13. package/dist/module.d.mts +44 -26
  14. package/dist/module.d.ts +44 -26
  15. package/dist/module.json +2 -2
  16. package/dist/module.mjs +152 -98
  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/stackblitz.d.ts +40 -0
  39. package/dist/runtime/core/bindings/resvg/stackblitz.mjs +6 -0
  40. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -3
  41. package/dist/runtime/core/bindings/satori/stackblitz.mjs +13 -0
  42. package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
  43. package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
  44. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  45. package/dist/runtime/core/cache/emojis.mjs +5 -0
  46. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  47. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  48. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  49. package/dist/runtime/core/font/fetch.d.ts +2 -3
  50. package/dist/runtime/core/font/fetch.mjs +20 -8
  51. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  52. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  53. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  54. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  55. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  56. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  57. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  58. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  59. package/dist/runtime/core/options/fetch.d.ts +1 -1
  60. package/dist/runtime/core/options/fetch.mjs +10 -5
  61. package/dist/runtime/core/options/normalise.d.ts +2 -2
  62. package/dist/runtime/core/options/normalise.mjs +3 -2
  63. package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
  64. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  65. package/dist/runtime/core/renderers/chromium/screenshot.mjs +5 -4
  66. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  67. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  68. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  69. package/dist/runtime/core/renderers/satori/index.mjs +25 -22
  70. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  71. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  72. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  73. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +8 -4
  74. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  75. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +38 -0
  76. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  77. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  78. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  79. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  80. package/dist/runtime/core/utils/resolveRendererContext.mjs +46 -23
  81. package/dist/runtime/core/utils/wasm.d.ts +3 -0
  82. package/dist/runtime/core/utils/wasm.mjs +16 -0
  83. package/dist/runtime/nitro/plugins/nuxt-content.mjs +3 -4
  84. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  85. package/dist/runtime/nitro/plugins/prerender.mjs +13 -5
  86. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +31 -0
  87. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -50
  88. package/dist/runtime/nuxt/utils.d.ts +2 -0
  89. package/dist/runtime/nuxt/utils.mjs +53 -0
  90. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +1 -3
  91. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +4 -8
  92. package/dist/runtime/server/routes/__og-image__/image.mjs +87 -0
  93. package/dist/runtime/types.d.ts +74 -25
  94. package/dist/runtime/utils.d.ts +4 -0
  95. package/dist/runtime/utils.mjs +11 -0
  96. package/dist/runtime/utils.pure.d.ts +5 -0
  97. package/dist/runtime/utils.pure.mjs +43 -0
  98. package/package.json +27 -29
  99. package/virtual.d.ts +49 -0
  100. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  101. package/dist/client/_nuxt/builds/meta/af7b6f15-8224-4a19-bb3a-f685b2b145c3.json +0 -1
  102. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  103. package/dist/client/_nuxt/entry.8ea61ef1.js +0 -137
  104. package/dist/client/grid.png +0 -0
  105. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  106. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  107. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  108. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  109. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  110. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  111. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  112. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  113. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  114. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  115. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  116. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  117. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  118. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  119. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  120. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  121. package/dist/runtime/core/html/fetch.d.ts +0 -3
  122. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  123. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  124. package/dist/runtime/utilts.d.ts +0 -2
  125. package/dist/runtime/utilts.mjs +0 -8
  126. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → stackblitz.d.ts} +0 -0
  127. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  128. /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.31";
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,43 @@ const RuntimeCompatibility = {
62
64
  "stackblitz": {
63
65
  bindings: {
64
66
  "chromium": false,
65
- "css-inline": "node",
66
- "resvg": "wasm",
67
- "satori": "node",
68
- "sharp": "node"
69
- },
70
- wasmStrategy: "inline"
67
+ "css-inline": false,
68
+ "resvg": "stackblitz",
69
+ "satori": "stackblitz",
70
+ "sharp": false
71
+ }
71
72
  },
72
73
  "aws-lambda": awsLambda,
73
74
  "netlify": awsLambda,
74
75
  "netlify-edge": {
75
76
  bindings: {
76
77
  "chromium": false,
77
- "css-inline": "node",
78
+ "css-inline": false,
78
79
  "resvg": "wasm",
79
80
  "satori": "node",
80
- "sharp": "node"
81
+ "sharp": false
81
82
  },
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"
83
+ wasm: {
84
+ rollup: {
85
+ targetEnv: "auto-inline",
86
+ sync: ["@resvg/resvg-wasm/index_bg.wasm"]
87
+ }
88
+ }
93
89
  },
90
+ "firebase": awsLambda,
91
+ "vercel": awsLambda,
94
92
  "vercel-edge": {
95
93
  bindings: {
96
94
  "chromium": false,
97
- "css-inline": "node",
95
+ "css-inline": false,
98
96
  "resvg": "wasm",
99
97
  "satori": "node",
100
- "sharp": "node"
98
+ "sharp": false
101
99
  },
102
- wasmStrategy: "inline",
103
- wasmImportQuery: "?module"
100
+ wasm: {
101
+ // lowers workers kb size
102
+ esmImport: true
103
+ }
104
104
  },
105
105
  "cloudflare-pages": cloudflare,
106
106
  "cloudflare": cloudflare
@@ -141,15 +141,37 @@ function applyNitroPresetCompatibility(nitroConfig, options) {
141
141
  applyBinding("satori"),
142
142
  applyBinding("resvg"),
143
143
  applyBinding("sharp"),
144
+ applyBinding("css-inline"),
144
145
  nitroConfig.alias || {}
145
146
  );
146
- if (target.includes("cloudflare")) {
147
- nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
148
- nitroConfig.rollupConfig.output.inlineDynamicImports = true;
147
+ if (Object.values(compatibility.bindings).includes("wasm")) {
148
+ nitroConfig.experimental = nitroConfig.experimental || {};
149
+ nitroConfig.experimental.wasm = true;
149
150
  }
151
+ nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
152
+ nitroConfig.wasm = defu(compatibility.wasm, nitroConfig.wasm);
150
153
  return compatibility;
151
154
  }
152
155
 
156
+ async function getNuxtModuleOptions(module, nuxt = useNuxt()) {
157
+ const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
158
+ const { nuxtModule } = await loadNuxtModuleInstance(module, nuxt);
159
+ let moduleEntry;
160
+ for (const m of nuxt.options.modules) {
161
+ if (Array.isArray(m) && m.length >= 2) {
162
+ const _module = m[0];
163
+ const _moduleEntryName = typeof _module === "string" ? _module : (await _module.getMeta?.())?.name || "";
164
+ if (_moduleEntryName === moduleMeta.name)
165
+ moduleEntry = m;
166
+ }
167
+ }
168
+ let inlineOptions = {};
169
+ if (moduleEntry)
170
+ inlineOptions = moduleEntry[1];
171
+ if (nuxtModule.getOptions)
172
+ return nuxtModule.getOptions(inlineOptions, nuxt);
173
+ return inlineOptions;
174
+ }
153
175
  function extendTypes(module, template) {
154
176
  const nuxt = useNuxt();
155
177
  const { resolve } = createResolver(import.meta.url);
@@ -201,9 +223,15 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
201
223
  rpc.broadcast.refreshRouteData(path).catch(() => {
202
224
  });
203
225
  }
204
- if (options.componentDirs.some((dir) => path.includes(dir)))
205
- rpc.broadcast.refreshGlobalData().catch(() => {
206
- });
226
+ if (options.componentDirs.some((dir) => path.includes(dir))) {
227
+ if (e === "change") {
228
+ rpc.broadcast.refresh().catch(() => {
229
+ });
230
+ } else {
231
+ rpc.broadcast.refreshGlobalData().catch(() => {
232
+ });
233
+ }
234
+ }
207
235
  });
208
236
  });
209
237
  nuxt.hook("devtools:customTabs", (tabs) => {
@@ -226,8 +254,8 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
226
254
  function setupDevHandler(options, resolve, nuxt = useNuxt()) {
227
255
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
228
256
  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 });
257
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = options.runtimeChromium ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
258
+ applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: options.runtimeCompatibility });
231
259
  });
232
260
  }
233
261
 
@@ -251,12 +279,13 @@ function setupGenerateHandler(options, resolve, nuxt = useNuxt()) {
251
279
  }
252
280
 
253
281
  function setupPrerenderHandler(options, resolve, nuxt = useNuxt()) {
254
- addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
255
282
  nuxt.hooks.hook("nitro:init", async (nitro) => {
256
283
  nitro.hooks.hook("prerender:config", async (nitroConfig) => {
257
284
  nitroConfig.alias["#nuxt-og-image/renderers/satori"] = resolve("./runtime/core/renderers/satori");
258
285
  nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = resolve("./runtime/core/renderers/chromium");
259
286
  applyNitroPresetCompatibility(nitroConfig, { resolve });
287
+ nitroConfig.wasm = nitroConfig.wasm || {};
288
+ nitroConfig.wasm.esmImport = false;
260
289
  });
261
290
  });
262
291
  }
@@ -267,20 +296,41 @@ async function setupBuildHandler(config, resolve, nuxt = useNuxt()) {
267
296
  nuxt.options.nitro.storage["og-image"] = config.runtimeCacheStorage;
268
297
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
269
298
  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";
299
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = config.runtimeChromium ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
271
300
  applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: config.runtimeCompatibility });
272
301
  nitroConfig.alias.electron = "unenv/runtime/mock/proxy-cjs";
273
302
  nitroConfig.alias.bufferutil = "unenv/runtime/mock/proxy-cjs";
274
303
  nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
275
304
  nitroConfig.alias.queue = "unenv/runtime/mock/proxy-cjs";
276
305
  });
306
+ nuxt.hooks.hook("nitro:init", async (nitro) => {
307
+ nitro.hooks.hook("compiled", async (_nitro) => {
308
+ const target = resolveNitroPreset(_nitro.options);
309
+ const compatibility = getPresetNitroPresetCompatibility(target);
310
+ if (compatibility.wasm?.esmImport !== true)
311
+ return;
312
+ const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
313
+ let serverEntry = resolve(_nitro.options.output.serverDir, typeof configuredEntry === "string" ? configuredEntry : "index.mjs");
314
+ if (target === "cloudflare-pages")
315
+ serverEntry = resolve(dirname(serverEntry), "./chunks/wasm.mjs");
316
+ const contents = await readFile(serverEntry, "utf-8");
317
+ const resvgHash = sha1(await readFile(await resolvePath("@resvg/resvg-wasm/index_bg.wasm")));
318
+ const yogaHash = sha1(await readFile(await resolvePath("yoga-wasm-web/dist/yoga.wasm")));
319
+ const postfix = target === "vercel-edge" ? "?module" : "";
320
+ const path = target === "cloudflare-pages" ? `../wasm/` : `./wasm/`;
321
+ 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" });
322
+ });
323
+ });
324
+ }
325
+ function sha1(source) {
326
+ return createHash("sha1").update(source).digest("hex").slice(0, 16);
277
327
  }
278
328
 
279
329
  const module = defineNuxtModule({
280
330
  meta: {
281
331
  name: "nuxt-og-image",
282
332
  compatibility: {
283
- nuxt: "^3.7.0",
333
+ nuxt: "^3.8.2",
284
334
  bridge: false
285
335
  },
286
336
  configKey: "ogImage"
@@ -289,21 +339,20 @@ const module = defineNuxtModule({
289
339
  return {
290
340
  enabled: true,
291
341
  defaults: {
342
+ emojis: "noto",
292
343
  renderer: "satori",
293
- component: "Fallback",
344
+ component: "NuxtSeo",
294
345
  width: 1200,
295
346
  height: 600,
296
- cache: true,
297
347
  // default is to cache the image for 1 day (24 hours)
298
- cacheTtl: 24 * 60 * 60 * 1e3
348
+ cacheMaxAgeSeconds: 60 * 60 * 24 * 3
299
349
  },
300
350
  componentDirs: ["OgImage", "OgImageTemplate"],
301
- runtimeSatori: true,
302
- runtimeBrowser: nuxt.options.dev,
303
351
  fonts: [],
304
352
  runtimeCacheStorage: true,
305
- playground: env.NODE_ENV === "development" || nuxt.options.dev,
306
- debug: false
353
+ runtimeSatori: true,
354
+ runtimeChromium: nuxt.options.dev,
355
+ debug: isDevelopment
307
356
  };
308
357
  },
309
358
  async setup(config, nuxt) {
@@ -320,14 +369,20 @@ const module = defineNuxtModule({
320
369
  const { resolve } = createResolver(import.meta.url);
321
370
  const preset = resolveNitroPreset(nuxt.options.nitro);
322
371
  const compatibility = getPresetNitroPresetCompatibility(preset);
323
- config.defaults.extension = "jpg";
324
- if (!compatibility.bindings.sharp)
372
+ const userConfiguredExtension = config.defaults.extension;
373
+ config.defaults.extension = userConfiguredExtension || "jpg";
374
+ if (!compatibility.bindings.sharp && config.defaults.renderer !== "chromium") {
375
+ if (userConfiguredExtension && ["jpeg", "jpg"].includes(userConfiguredExtension))
376
+ logger.warn("The sharp runtime is not available for this target, disabling sharp and using png instead.");
325
377
  config.defaults.extension = "png";
378
+ }
379
+ if (config.runtimeChromium && !compatibility.bindings.chromium) {
380
+ logger.warn("The Chromium runtime is not available for this target, disabling runtimeChromium.");
381
+ config.runtimeChromium = false;
382
+ }
326
383
  await installNuxtSiteConfig();
327
- if (hasNuxtModule("@nuxt/content")) {
384
+ if (hasNuxtModule("@nuxt/content"))
328
385
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
329
- addPlugin(resolve("./runtime/nuxt/plugins/nuxt-content-canonical-urls"));
330
- }
331
386
  if (!config.fonts.length)
332
387
  config.fonts = ["Inter:400", "Inter:700"];
333
388
  nuxt.options.experimental.componentIslands = true;
@@ -346,52 +401,34 @@ const module = defineNuxtModule({
346
401
  addServerHandler({
347
402
  lazy: true,
348
403
  route: "/__og-image__/image/**",
349
- handler: resolve("./runtime/server/routes/__og-image__/image-[path]-og.[extension]")
404
+ handler: resolve("./runtime/server/routes/__og-image__/image")
350
405
  });
351
406
  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}`;
407
+ ["defineOgImage", "defineOgImageComponent", "defineOgImageScreenshot"].forEach((name) => {
364
408
  addImports({
365
409
  name,
366
- from: resolve("./runtime/composables/defineOgImage")
410
+ from: resolve(`./runtime/composables/${name}`)
367
411
  });
368
412
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
369
413
  });
370
414
  await addComponentsDir({
371
415
  path: resolve("./runtime/components/Templates/Community"),
372
- island: true
373
- });
374
- await addComponentsDir({
375
- path: resolve("./runtime/components/Templates/Official"),
376
- island: true
416
+ island: true,
417
+ watch: true
377
418
  });
378
419
  [
379
- // deprecated
380
- "Static",
381
- "Dynamic",
382
420
  // new
383
- "index",
384
- "Cached",
385
- "WithoutCache",
386
- "Screenshot"
421
+ "OgImage",
422
+ "OgImageScreenshot"
387
423
  ].forEach((name) => {
388
424
  addComponent({
389
- global: hasNuxtModule("@nuxt/content"),
390
- name: name === "index" ? "OgImage" : `OgImage${name}`,
425
+ name,
426
+ global: true,
391
427
  filePath: resolve(`./runtime/components/OgImage/${name}`)
392
428
  });
393
429
  });
394
- addPlugin(resolve("./runtime/nuxt/plugins/route-rule-og-image.server"));
430
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/route-rule-og-image.server") });
431
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/og-image-canonical-urls.server") });
395
432
  const ogImageComponentCtx = { components: [] };
396
433
  nuxt.hook("components:extend", (components) => {
397
434
  ogImageComponentCtx.components = [];
@@ -409,8 +446,6 @@ const module = defineNuxtModule({
409
446
  let category = "app";
410
447
  if (component.filePath.includes(resolve("./runtime/components/Templates/Community")))
411
448
  category = "community";
412
- else if (component.filePath.includes(resolve("./runtime/components/Templates/Official")))
413
- category = "official";
414
449
  const componentFile = fs.readFileSync(component.filePath, "utf-8");
415
450
  const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
416
451
  ogImageComponentCtx.components.push({
@@ -437,6 +472,16 @@ const module = defineNuxtModule({
437
472
  nuxt.options.nitro.virtual["#nuxt-og-image/component-names.mjs"] = () => {
438
473
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
439
474
  };
475
+ let unoCssConfig = { theme: {} };
476
+ nuxt.hook("tailwindcss:config", (tailwindConfig) => {
477
+ unoCssConfig = defu(tailwindConfig.theme.extend, { ...tailwindConfig.theme || {}, extend: void 0 });
478
+ });
479
+ nuxt.hook("unocss:config", (_unoCssConfig) => {
480
+ unoCssConfig = { ..._unoCssConfig.theme };
481
+ });
482
+ nuxt.options.nitro.virtual["#nuxt-og-image/unocss-config.mjs"] = () => {
483
+ return `export const theme = ${JSON.stringify(unoCssConfig)}`;
484
+ };
440
485
  extendTypes("nuxt-og-image", ({ typesPath }) => {
441
486
  const componentImports = ogImageComponentCtx.components.map((component) => {
442
487
  const relativeComponentPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), component.path);
@@ -445,12 +490,13 @@ const module = defineNuxtModule({
445
490
  return `
446
491
  declare module 'nitropack' {
447
492
  interface NitroRouteRules {
448
- ogImage?: false | import('${typesPath}').OgImageOptions
493
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
449
494
  }
450
495
  interface NitroRouteConfig {
451
- ogImage?: false | import('${typesPath}').OgImageOptions
496
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
452
497
  }
453
498
  }
499
+
454
500
  declare module '#nuxt-og-image/components' {
455
501
  export interface OgImageComponents {
456
502
  ${componentImports}
@@ -458,6 +504,11 @@ ${componentImports}
458
504
  }
459
505
  `;
460
506
  });
507
+ const cacheEnabled = typeof config.runtimeCacheStorage !== "undefined" && config.runtimeCacheStorage !== false;
508
+ const runtimeCacheStorage = typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver;
509
+ let baseCacheKey = runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${version}` : `/nuxt-og-image@${version}`;
510
+ if (!cacheEnabled)
511
+ baseCacheKey = false;
461
512
  nuxt.hooks.hook("modules:done", async () => {
462
513
  nuxt.hooks.callHook("og-image:config", config);
463
514
  const normalisedFonts = config.fonts.map((f) => {
@@ -478,6 +529,9 @@ ${componentImports}
478
529
  nuxt.options.nitro.prerender.routes.push(`/__og-image__/font/${name}/${weight}.ttf`);
479
530
  });
480
531
  }
532
+ let colorPreference = hasNuxtModule("@nuxtjs/color-mode") ? (await getNuxtModuleOptions("@nuxtjs/color-mode")).preference : "light";
533
+ if (!colorPreference || !["dark", "light"].includes(colorPreference))
534
+ colorPreference = "light";
481
535
  nuxt.options.runtimeConfig["nuxt-og-image"] = {
482
536
  version,
483
537
  // binding options
@@ -485,18 +539,17 @@ ${componentImports}
485
539
  resvgOptions: config.resvgOptions || {},
486
540
  sharpOptions: config.sharpOptions || {},
487
541
  runtimeSatori: config.runtimeSatori,
488
- runtimeBrowser: config.runtimeBrowser,
489
- // @ts-expect-error runtime type
542
+ runtimeChromium: config.runtimeChromium,
490
543
  defaults: config.defaults,
544
+ debug: config.debug,
491
545
  // avoid adding credentials
492
- runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
546
+ baseCacheKey,
493
547
  // convert the fonts to uniform type to fix ts issue
494
548
  fonts: normalisedFonts,
495
- hasNuxtIcon: hasNuxtModule("nuxt-icon")
549
+ hasNuxtIcon: hasNuxtModule("nuxt-icon"),
550
+ colorPreference
496
551
  };
497
552
  });
498
- nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
499
- nuxt.options.nitro.experimental.wasm = true;
500
553
  if (nuxt.options.dev) {
501
554
  setupDevHandler(config, resolve);
502
555
  setupDevToolsUI(config, resolve);
@@ -505,8 +558,9 @@ ${componentImports}
505
558
  } else if (nuxt.options.build) {
506
559
  await setupBuildHandler(config, resolve);
507
560
  }
508
- if (nuxt.options.nitro.prerender?.routes || nuxt.options._generate)
509
- setupPrerenderHandler(config, resolve);
561
+ if (nuxt.options.nitro.prerender?.routes?.length || nuxt.options.nitro.prerender?.crawlLinks || nuxt.options._generate)
562
+ addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
563
+ setupPrerenderHandler(config, resolve);
510
564
  }
511
565
  });
512
566
 
@@ -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">