nuxt-og-image 3.0.0-beta.5 → 3.0.0-beta.51

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 (138) hide show
  1. package/README.md +4 -4
  2. package/dist/client/200.html +5 -5
  3. package/dist/client/404.html +5 -5
  4. package/dist/client/_nuxt/IconCSS.4bbe2613.css +1 -0
  5. package/dist/client/_nuxt/IconCSS.71f1059a.js +1 -0
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/6b86c847-1bce-41b5-9ab8-acabeed13f1f.json +1 -0
  8. package/dist/client/_nuxt/entry.33a59bbf.css +1 -0
  9. package/dist/client/_nuxt/entry.99da9ce9.js +138 -0
  10. package/dist/client/_nuxt/{error-404.b07f263f.js → error-404.eed1a665.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.ed41d8f2.js → error-500.05b9efb3.js} +1 -1
  12. package/dist/client/index.html +5 -5
  13. package/dist/module.d.mts +55 -46
  14. package/dist/module.d.ts +55 -46
  15. package/dist/module.json +2 -2
  16. package/dist/module.mjs +306 -162
  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/Community/Pergel.vue +104 -0
  27. package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
  28. package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
  29. package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
  30. package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
  31. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  32. package/dist/runtime/composables/defineOgImage.mjs +33 -117
  33. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  34. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  35. package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
  36. package/dist/runtime/composables/defineOgImageScreenshot.mjs +13 -0
  37. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  38. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  39. package/dist/runtime/core/bindings/resvg/wasm-fs.d.ts +40 -0
  40. package/dist/runtime/core/bindings/resvg/wasm-fs.mjs +6 -0
  41. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -2
  42. package/dist/runtime/core/bindings/satori/wasm-fs.mjs +13 -0
  43. package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
  44. package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
  45. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  46. package/dist/runtime/core/cache/emojis.mjs +5 -0
  47. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  48. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  49. package/dist/runtime/core/cache/prerender.d.ts +1 -5
  50. package/dist/runtime/core/cache/prerender.mjs +1 -2
  51. package/dist/runtime/core/env/assets.d.ts +0 -1
  52. package/dist/runtime/core/env/assets.mjs +0 -4
  53. package/dist/runtime/core/font/fetch.d.ts +2 -3
  54. package/dist/runtime/core/font/fetch.mjs +32 -15
  55. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  56. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  57. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  58. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  59. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  60. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  61. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  62. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  63. package/dist/runtime/core/options/fetch.d.ts +1 -1
  64. package/dist/runtime/core/options/fetch.mjs +10 -5
  65. package/dist/runtime/core/renderers/chromium/index.mjs +9 -13
  66. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  67. package/dist/runtime/core/renderers/chromium/screenshot.mjs +18 -13
  68. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  69. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  70. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  71. package/dist/runtime/core/renderers/satori/index.mjs +26 -22
  72. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  73. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  74. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  75. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +23 -10
  76. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  77. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +45 -0
  78. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  79. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  80. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  81. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  82. package/dist/runtime/core/utils/resolveRendererContext.mjs +47 -29
  83. package/dist/runtime/core/utils/wasm.d.ts +3 -0
  84. package/dist/runtime/core/utils/wasm.mjs +16 -0
  85. package/dist/runtime/nitro/plugins/nuxt-content.mjs +3 -4
  86. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  87. package/dist/runtime/nitro/plugins/prerender.mjs +20 -18
  88. package/dist/runtime/nitro/utils.d.ts +2 -0
  89. package/dist/runtime/nitro/utils.mjs +17 -0
  90. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +31 -0
  91. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -51
  92. package/dist/runtime/nuxt/utils.d.ts +3 -0
  93. package/dist/runtime/nuxt/utils.mjs +69 -0
  94. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +2 -3
  95. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +5 -7
  96. package/dist/runtime/server/routes/__og-image__/image.mjs +88 -0
  97. package/dist/runtime/types.d.ts +89 -25
  98. package/dist/runtime/utils.d.ts +4 -0
  99. package/dist/runtime/utils.mjs +11 -0
  100. package/dist/runtime/utils.pure.d.ts +5 -0
  101. package/dist/runtime/utils.pure.mjs +43 -0
  102. package/package.json +30 -31
  103. package/virtual.d.ts +49 -0
  104. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  105. package/dist/client/_nuxt/IconCSS.b16882c0.js +0 -1
  106. package/dist/client/_nuxt/builds/meta/df74ddc4-3ccb-4ada-8e61-014943e6befc.json +0 -1
  107. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  108. package/dist/client/_nuxt/entry.d4edd2a5.js +0 -137
  109. package/dist/client/grid.png +0 -0
  110. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  111. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  112. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  113. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  114. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  115. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  116. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  117. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  118. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  119. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  120. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  121. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  122. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  123. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  124. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  125. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  126. package/dist/runtime/core/html/fetch.d.ts +0 -3
  127. package/dist/runtime/core/options/normalise.d.ts +0 -2
  128. package/dist/runtime/core/options/normalise.mjs +0 -26
  129. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  130. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  131. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  132. package/dist/runtime/utilts.d.ts +0 -2
  133. package/dist/runtime/utilts.mjs +0 -8
  134. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → wasm-fs.d.ts} +0 -0
  135. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  136. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
  137. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
  138. /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,20 @@
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';
4
- import { installNuxtSiteConfig } from 'nuxt-site-config-kit';
5
- import { provider, env } from 'std-env';
3
+ import { useNuxt, addTemplate, loadNuxtModuleInstance, createResolver, resolvePath, defineNuxtModule, useLogger, tryResolveModule, hasNuxtModule, addServerPlugin, addServerHandler, addImports, addComponentsDir, addComponent, addPlugin } from '@nuxt/kit';
4
+ import { assertSiteConfig, installNuxtSiteConfig } from 'nuxt-site-config-kit';
5
+ import { provider, env, isDevelopment, isCI } 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 { Launcher } from 'chrome-launcher';
10
+ import { ensureDependencyInstalled } from 'nypm';
10
11
  import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
12
+ import { readFile, writeFile } from 'node:fs/promises';
13
+ import { createHash } from 'node:crypto';
14
+ import { execa } from 'execa';
15
+ import terminate from 'terminate';
11
16
 
12
- const version = "3.0.0-beta.5";
17
+ const version = "3.0.0-beta.51";
13
18
 
14
19
  const autodetectableProviders = {
15
20
  azure_static: "azure",
@@ -26,81 +31,69 @@ const autodetectableStaticProviders = {
26
31
  };
27
32
  const NodeRuntime = {
28
33
  // node-server runtime
29
- bindings: {
30
- "chromium": "node",
31
- "css-inline": "node",
32
- "resvg": "node",
33
- "satori": "node",
34
- "sharp": "node"
35
- },
36
- wasmStrategy: "import"
34
+ "chromium": "node",
35
+ "css-inline": "node",
36
+ "resvg": "node",
37
+ "satori": "node",
38
+ "sharp": "node"
39
+ // will be disabled if they're missing the dependency
37
40
  };
38
41
  const cloudflare = {
39
- bindings: {
40
- "chromium": false,
41
- "css-inline": "node",
42
- "resvg": "wasm",
43
- "satori": "node",
44
- "sharp": false
45
- },
46
- wasmStrategy: "import"
42
+ "chromium": false,
43
+ "css-inline": false,
44
+ "resvg": "wasm",
45
+ "satori": "node",
46
+ "sharp": false,
47
+ "wasm": {
48
+ esmImport: true
49
+ }
47
50
  };
48
51
  const awsLambda = {
49
- bindings: {
50
- "chromium": false,
51
- "css-inline": "node",
52
- "resvg": "node",
53
- "satori": "node",
54
- "sharp": "node"
55
- },
56
- wasmStrategy: "inline"
52
+ "chromium": false,
53
+ "css-inline": "node",
54
+ "resvg": "node",
55
+ "satori": "node",
56
+ "sharp": false
57
+ // 0.33.x has issues
57
58
  };
58
59
  const RuntimeCompatibility = {
59
60
  "nitro-dev": NodeRuntime,
60
61
  "nitro-prerender": NodeRuntime,
61
62
  "node-server": NodeRuntime,
62
63
  "stackblitz": {
63
- bindings: {
64
- "chromium": false,
65
- "css-inline": "node",
66
- "resvg": "wasm",
67
- "satori": "node",
68
- "sharp": "node"
69
- },
70
- wasmStrategy: "inline"
64
+ "chromium": false,
65
+ "css-inline": false,
66
+ "resvg": "wasm-fs",
67
+ "satori": "wasm-fs",
68
+ "sharp": false
71
69
  },
72
70
  "aws-lambda": awsLambda,
73
71
  "netlify": awsLambda,
74
72
  "netlify-edge": {
75
- bindings: {
76
- "chromium": false,
77
- "css-inline": "node",
78
- "resvg": "node",
79
- "satori": "node",
80
- "sharp": false
81
- },
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"
73
+ "chromium": false,
74
+ "css-inline": false,
75
+ "resvg": "wasm",
76
+ "satori": "node",
77
+ "sharp": false,
78
+ "wasm": {
79
+ rollup: {
80
+ targetEnv: "auto-inline",
81
+ sync: ["@resvg/resvg-wasm/index_bg.wasm"]
82
+ }
83
+ }
93
84
  },
85
+ "firebase": awsLambda,
86
+ "vercel": awsLambda,
94
87
  "vercel-edge": {
95
- bindings: {
96
- "chromium": false,
97
- "css-inline": "node",
98
- "resvg": "wasm",
99
- "satori": "node",
100
- "sharp": "node"
101
- },
102
- wasmStrategy: "inline",
103
- wasmImportQuery: "?module"
88
+ "chromium": false,
89
+ "css-inline": false,
90
+ "resvg": "wasm",
91
+ "satori": "node",
92
+ "sharp": false,
93
+ "wasm": {
94
+ // lowers workers kb size
95
+ esmImport: true
96
+ }
104
97
  },
105
98
  "cloudflare-pages": cloudflare,
106
99
  "cloudflare": cloudflare
@@ -125,31 +118,75 @@ function getPresetNitroPresetCompatibility(target) {
125
118
  return compatibility;
126
119
  }
127
120
  function applyNitroPresetCompatibility(nitroConfig, options) {
128
- let compatibility = options?.compatibility;
129
121
  const target = resolveNitroPreset(nitroConfig);
130
- if (!compatibility)
131
- compatibility = getPresetNitroPresetCompatibility(target);
132
- const resolve = options.resolve;
122
+ const compatibility = getPresetNitroPresetCompatibility(target);
123
+ const { resolve } = options;
124
+ const satoriEnabled = typeof options.compatibility?.satori !== "undefined" ? !!options.compatibility.satori : !!compatibility.satori;
125
+ const chromiumEnabled = typeof options.compatibility?.chromium !== "undefined" ? !!options.compatibility.chromium : !!compatibility.chromium;
126
+ nitroConfig.alias["#nuxt-og-image/renderers/satori"] = satoriEnabled ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
127
+ nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = chromiumEnabled ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
128
+ const resolvedCompatibility = {};
133
129
  function applyBinding(key) {
134
- const binding = compatibility.bindings[key];
135
- if (binding === false)
136
- return { [`#nuxt-og-image/bindings/${key}`]: "unenv/runtime/mock/empty" };
137
- return { [`#nuxt-og-image/bindings/${key}`]: resolve(`./runtime/core/bindings/${key}/${binding}`) };
130
+ let binding = options.compatibility?.[key];
131
+ if (typeof binding === "undefined")
132
+ binding = compatibility[key];
133
+ resolvedCompatibility[key] = binding;
134
+ return {
135
+ [`#nuxt-og-image/bindings/${key}`]: binding === false ? "unenv/runtime/mock/empty" : resolve(`./runtime/core/bindings/${key}/${binding}`)
136
+ };
138
137
  }
139
138
  nitroConfig.alias = defu(
140
139
  applyBinding("chromium"),
141
140
  applyBinding("satori"),
142
141
  applyBinding("resvg"),
143
142
  applyBinding("sharp"),
143
+ applyBinding("css-inline"),
144
144
  nitroConfig.alias || {}
145
145
  );
146
- if (target.includes("cloudflare")) {
147
- nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
148
- nitroConfig.rollupConfig.output.inlineDynamicImports = true;
146
+ if (Object.values(compatibility).includes("wasm")) {
147
+ nitroConfig.experimental = nitroConfig.experimental || {};
148
+ nitroConfig.experimental.wasm = true;
149
149
  }
150
- return compatibility;
150
+ nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
151
+ nitroConfig.wasm = defu(compatibility.wasm, nitroConfig.wasm);
152
+ nitroConfig.virtual["#nuxt-og-image/compatibility"] = () => `export default ${JSON.stringify(resolvedCompatibility)}`;
153
+ addTemplate({
154
+ filename: "nuxt-og-image/compatibility.mjs",
155
+ getContents() {
156
+ return `export default ${JSON.stringify(resolvedCompatibility)}`;
157
+ },
158
+ options: { mode: "server" }
159
+ });
160
+ return resolvedCompatibility;
161
+ }
162
+ function ensureDependencies(dep, nuxt = useNuxt()) {
163
+ return Promise.all(dep.map((d) => {
164
+ return ensureDependencyInstalled(d, {
165
+ cwd: nuxt.options.rootDir,
166
+ dev: true
167
+ });
168
+ }));
151
169
  }
152
170
 
171
+ async function getNuxtModuleOptions(module, nuxt = useNuxt()) {
172
+ const moduleMeta = (typeof module === "string" ? { name: module } : await module.getMeta?.()) || {};
173
+ const { nuxtModule } = await loadNuxtModuleInstance(module, nuxt);
174
+ let moduleEntry;
175
+ for (const m of nuxt.options.modules) {
176
+ if (Array.isArray(m) && m.length >= 2) {
177
+ const _module = m[0];
178
+ const _moduleEntryName = typeof _module === "string" ? _module : (await _module.getMeta?.())?.name || "";
179
+ if (_moduleEntryName === moduleMeta.name)
180
+ moduleEntry = m;
181
+ }
182
+ }
183
+ let inlineOptions = {};
184
+ if (moduleEntry)
185
+ inlineOptions = moduleEntry[1];
186
+ if (nuxtModule.getOptions)
187
+ return nuxtModule.getOptions(inlineOptions, nuxt);
188
+ return inlineOptions;
189
+ }
153
190
  function extendTypes(module, template) {
154
191
  const nuxt = useNuxt();
155
192
  const { resolve } = createResolver(import.meta.url);
@@ -201,9 +238,15 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
201
238
  rpc.broadcast.refreshRouteData(path).catch(() => {
202
239
  });
203
240
  }
204
- if (options.componentDirs.some((dir) => path.includes(dir)))
205
- rpc.broadcast.refreshGlobalData().catch(() => {
206
- });
241
+ if (options.componentDirs.some((dir) => path.includes(dir))) {
242
+ if (e === "change") {
243
+ rpc.broadcast.refresh().catch(() => {
244
+ });
245
+ } else {
246
+ rpc.broadcast.refreshGlobalData().catch(() => {
247
+ });
248
+ }
249
+ }
207
250
  });
208
251
  });
209
252
  nuxt.hook("devtools:customTabs", (tabs) => {
@@ -225,38 +268,42 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
225
268
 
226
269
  function setupDevHandler(options, resolve, nuxt = useNuxt()) {
227
270
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
228
- 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 });
271
+ applyNitroPresetCompatibility(nitroConfig, { compatibility: options.compatibility?.dev, resolve });
231
272
  });
232
273
  }
233
274
 
234
275
  function setupGenerateHandler(options, resolve, nuxt = useNuxt()) {
235
276
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
236
- nitroConfig.alias["#nuxt-og-image/renderers/satori"] = "unenv/runtime/mock/empty";
237
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = "unenv/runtime/mock/empty";
238
277
  applyNitroPresetCompatibility(nitroConfig, {
239
278
  compatibility: {
240
- bindings: {
241
- "css-inline": false,
242
- "chromium": false,
243
- "resvg": false,
244
- "satori": false,
245
- "sharp": false
246
- }
279
+ "chromium": false,
280
+ "satori": false,
281
+ "css-inline": false,
282
+ "resvg": false,
283
+ "sharp": false
247
284
  },
248
285
  resolve
249
286
  });
287
+ assertSiteConfig("nuxt-og-image", {
288
+ url: "OG Image tags are required to be absolute URLs."
289
+ }, {
290
+ throwError: true
291
+ });
250
292
  });
251
293
  }
252
294
 
253
295
  function setupPrerenderHandler(options, resolve, nuxt = useNuxt()) {
254
- addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
255
296
  nuxt.hooks.hook("nitro:init", async (nitro) => {
256
297
  nitro.hooks.hook("prerender:config", async (nitroConfig) => {
257
- nitroConfig.alias["#nuxt-og-image/renderers/satori"] = resolve("./runtime/core/renderers/satori");
258
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = resolve("./runtime/core/renderers/chromium");
259
- applyNitroPresetCompatibility(nitroConfig, { resolve });
298
+ applyNitroPresetCompatibility(nitroConfig, { compatibility: options.compatibility.prerender, resolve });
299
+ nitroConfig.wasm = nitroConfig.wasm || {};
300
+ nitroConfig.wasm.esmImport = false;
301
+ const prerenderingPages = (nuxt.options.nitro.prerender?.routes || []).some((r) => r && (!r.includes(".") || r.includes("*")));
302
+ prerenderingPages && assertSiteConfig("nuxt-og-image", {
303
+ url: "OG Image tags are required to be absolute URLs."
304
+ }, {
305
+ throwError: false
306
+ });
260
307
  });
261
308
  });
262
309
  }
@@ -266,44 +313,76 @@ async function setupBuildHandler(config, resolve, nuxt = useNuxt()) {
266
313
  if (typeof config.runtimeCacheStorage === "object")
267
314
  nuxt.options.nitro.storage["og-image"] = config.runtimeCacheStorage;
268
315
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
269
- 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";
271
- applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: config.runtimeCompatibility });
316
+ applyNitroPresetCompatibility(nitroConfig, { compatibility: config.compatibility?.runtime, resolve });
272
317
  nitroConfig.alias.electron = "unenv/runtime/mock/proxy-cjs";
273
318
  nitroConfig.alias.bufferutil = "unenv/runtime/mock/proxy-cjs";
274
319
  nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
275
320
  nitroConfig.alias.queue = "unenv/runtime/mock/proxy-cjs";
276
321
  });
322
+ nuxt.hooks.hook("nitro:init", async (nitro) => {
323
+ nitro.hooks.hook("compiled", async (_nitro) => {
324
+ const target = resolveNitroPreset(_nitro.options);
325
+ const compatibility = getPresetNitroPresetCompatibility(target);
326
+ if (compatibility.wasm?.esmImport !== true)
327
+ return;
328
+ const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
329
+ let serverEntry = resolve(_nitro.options.output.serverDir, typeof configuredEntry === "string" ? configuredEntry : "index.mjs");
330
+ if (target === "cloudflare-pages")
331
+ serverEntry = resolve(dirname(serverEntry), "./chunks/wasm.mjs");
332
+ const contents = await readFile(serverEntry, "utf-8");
333
+ const resvgHash = sha1(await readFile(await resolvePath("@resvg/resvg-wasm/index_bg.wasm")));
334
+ const yogaHash = sha1(await readFile(await resolvePath("yoga-wasm-web/dist/yoga.wasm")));
335
+ const postfix = target === "vercel-edge" ? "?module" : "";
336
+ const path = target === "cloudflare-pages" ? `../wasm/` : `./wasm/`;
337
+ 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" });
338
+ });
339
+ });
340
+ }
341
+ function sha1(source) {
342
+ return createHash("sha1").update(source).digest("hex").slice(0, 16);
343
+ }
344
+
345
+ async function ensureChromium(logger) {
346
+ logger.info("Ensuring Chromium install for og:image generation...");
347
+ const installChromeProcess = execa("npx", ["playwright", "install", "chromium"], {
348
+ stdio: "inherit"
349
+ });
350
+ installChromeProcess.stderr?.pipe(process.stderr);
351
+ await new Promise((resolve) => {
352
+ installChromeProcess.on("exit", (e) => {
353
+ if (e !== 0)
354
+ logger.error("Failed to install Playwright dependency for og:image generation. Trying anyway...");
355
+ resolve(true);
356
+ });
357
+ });
358
+ installChromeProcess.pid && terminate(installChromeProcess.pid);
277
359
  }
278
360
 
279
361
  const module = defineNuxtModule({
280
362
  meta: {
281
363
  name: "nuxt-og-image",
282
364
  compatibility: {
283
- nuxt: "^3.7.0",
365
+ nuxt: "^3.8.2",
284
366
  bridge: false
285
367
  },
286
368
  configKey: "ogImage"
287
369
  },
288
- defaults(nuxt) {
370
+ defaults() {
289
371
  return {
290
372
  enabled: true,
291
373
  defaults: {
374
+ emojis: "noto",
292
375
  renderer: "satori",
293
- component: "Fallback",
376
+ component: "NuxtSeo",
294
377
  width: 1200,
295
378
  height: 600,
296
- cache: true,
297
- // default is to cache the image for 1 day (24 hours)
298
- cacheTtl: 24 * 60 * 60 * 1e3
379
+ // default is to cache the image for 3 day (72 hours)
380
+ cacheMaxAgeSeconds: 60 * 60 * 24 * 3
299
381
  },
300
382
  componentDirs: ["OgImage", "OgImageTemplate"],
301
- runtimeSatori: true,
302
- runtimeBrowser: nuxt.options.dev,
303
383
  fonts: [],
304
384
  runtimeCacheStorage: true,
305
- playground: env.NODE_ENV === "development" || nuxt.options.dev,
306
- debug: false
385
+ debug: isDevelopment
307
386
  };
308
387
  },
309
388
  async setup(config, nuxt) {
@@ -319,17 +398,80 @@ const module = defineNuxtModule({
319
398
  }
320
399
  const { resolve } = createResolver(import.meta.url);
321
400
  const preset = resolveNitroPreset(nuxt.options.nitro);
322
- const compatibility = getPresetNitroPresetCompatibility(preset);
323
- config.defaults.extension = "jpg";
324
- if (!compatibility.bindings.sharp)
325
- config.defaults.extension = "png";
401
+ const targetCompatibility = getPresetNitroPresetCompatibility(preset);
402
+ const hasSharpDependency = !!await tryResolveModule("sharp");
403
+ const userConfiguredExtension = config.defaults.extension;
404
+ const hasConfiguredJpegs = userConfiguredExtension && ["jpeg", "jpg"].includes(userConfiguredExtension);
405
+ config.defaults.extension = userConfiguredExtension || (hasSharpDependency && targetCompatibility.sharp ? "jpg" : "png");
406
+ if (hasConfiguredJpegs && config.defaults.renderer !== "chromium") {
407
+ if (hasSharpDependency && !targetCompatibility.sharp) {
408
+ logger.warn(`Rendering JPEGs requires sharp which does not work with ${preset}. Images will be rendered as PNG at runtime.`);
409
+ config.compatibility = defu(config.compatibility, {
410
+ runtime: { sharp: false }
411
+ });
412
+ } else if (!hasSharpDependency) {
413
+ logger.warn("You have enabled `JPEG` images. These require the `sharp` dependency which is missing, installing it for you.");
414
+ await ensureDependencies(["sharp"]);
415
+ logger.warn("Support for `sharp` is limited so check the compatibility guide.");
416
+ }
417
+ } else if (!hasSharpDependency) {
418
+ config.compatibility = defu(config.compatibility, {
419
+ runtime: { sharp: false },
420
+ dev: { sharp: false },
421
+ prerender: { sharp: false }
422
+ });
423
+ }
424
+ const isUndefinedOrTruthy = (v) => typeof v === "undefined" || v !== false;
425
+ if (isUndefinedOrTruthy(config.compatibility?.prerender?.chromium) && isUndefinedOrTruthy(config.compatibility?.runtime?.chromium)) {
426
+ let hasChromeLocally = false;
427
+ try {
428
+ hasChromeLocally = !!Launcher.getFirstInstallation();
429
+ } catch {
430
+ }
431
+ if (isCI)
432
+ await ensureChromium(logger);
433
+ const hasPlaywrightDependency = !!await tryResolveModule("playwright");
434
+ if (hasChromeLocally) {
435
+ config.compatibility = defu(config.compatibility, {
436
+ runtime: { chromium: false },
437
+ dev: { chromium: "node" },
438
+ prerender: { chromium: "node" }
439
+ });
440
+ } else if (hasPlaywrightDependency && targetCompatibility.chromium) {
441
+ config.compatibility = defu(config.compatibility, {
442
+ runtime: { chromium: "node" },
443
+ dev: { chromium: "node" },
444
+ prerender: { chromium: "node" }
445
+ });
446
+ }
447
+ }
326
448
  await installNuxtSiteConfig();
327
- if (hasNuxtModule("@nuxt/content")) {
449
+ if (hasNuxtModule("@nuxt/content"))
328
450
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
329
- addPlugin(resolve("./runtime/nuxt/plugins/nuxt-content-canonical-urls"));
330
- }
331
451
  if (!config.fonts.length)
332
452
  config.fonts = ["Inter:400", "Inter:700"];
453
+ if (preset === "stackblitz") {
454
+ config.fonts = config.fonts.map((f) => {
455
+ if (typeof f === "string" && f.startsWith("Inter:")) {
456
+ const [_, weight] = f.split(":");
457
+ return {
458
+ name: "Inter",
459
+ weight,
460
+ // nuxt server assets
461
+ key: `nuxt-og-image:fonts:inter-latin-ext-${weight}-normal.woff`
462
+ };
463
+ }
464
+ if (typeof f === "string" || !f.path && !f.key) {
465
+ logger.warn(`The ${typeof f === "string" ? f : `${f.name}:${f.weight}`} font was skipped because remote fonts are not available in StackBlitz, please use a local font.`);
466
+ return false;
467
+ }
468
+ return f;
469
+ }).filter(Boolean);
470
+ nuxt.hooks.hook("nitro:config", (nitroConfig) => {
471
+ nitroConfig.serverAssets = nitroConfig.serverAssets || [];
472
+ nitroConfig.serverAssets.push({ baseName: "nuxt-og-image:fonts", dir: resolve("./runtime/server/assets") });
473
+ });
474
+ }
333
475
  nuxt.options.experimental.componentIslands = true;
334
476
  addServerHandler({
335
477
  lazy: true,
@@ -346,52 +488,34 @@ const module = defineNuxtModule({
346
488
  addServerHandler({
347
489
  lazy: true,
348
490
  route: "/__og-image__/image/**",
349
- handler: resolve("./runtime/server/routes/__og-image__/image-[path]-og.[extension]")
491
+ handler: resolve("./runtime/server/routes/__og-image__/image")
350
492
  });
351
493
  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}`;
494
+ ["defineOgImage", "defineOgImageComponent", "defineOgImageScreenshot"].forEach((name) => {
364
495
  addImports({
365
496
  name,
366
- from: resolve("./runtime/composables/defineOgImage")
497
+ from: resolve(`./runtime/composables/${name}`)
367
498
  });
368
499
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
369
500
  });
370
501
  await addComponentsDir({
371
502
  path: resolve("./runtime/components/Templates/Community"),
372
- island: true
373
- });
374
- await addComponentsDir({
375
- path: resolve("./runtime/components/Templates/Official"),
376
- island: true
503
+ island: true,
504
+ watch: true
377
505
  });
378
506
  [
379
- // deprecated
380
- "Static",
381
- "Dynamic",
382
507
  // new
383
- "index",
384
- "Cached",
385
- "WithoutCache",
386
- "Screenshot"
508
+ "OgImage",
509
+ "OgImageScreenshot"
387
510
  ].forEach((name) => {
388
511
  addComponent({
389
- global: hasNuxtModule("@nuxt/content"),
390
- name: name === "index" ? "OgImage" : `OgImage${name}`,
512
+ name,
513
+ global: true,
391
514
  filePath: resolve(`./runtime/components/OgImage/${name}`)
392
515
  });
393
516
  });
394
- addPlugin(resolve("./runtime/nuxt/plugins/route-rule-og-image.server"));
517
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/route-rule-og-image.server") });
518
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/og-image-canonical-urls.server") });
395
519
  const ogImageComponentCtx = { components: [] };
396
520
  nuxt.hook("components:extend", (components) => {
397
521
  ogImageComponentCtx.components = [];
@@ -409,8 +533,6 @@ const module = defineNuxtModule({
409
533
  let category = "app";
410
534
  if (component.filePath.includes(resolve("./runtime/components/Templates/Community")))
411
535
  category = "community";
412
- else if (component.filePath.includes(resolve("./runtime/components/Templates/Official")))
413
- category = "official";
414
536
  const componentFile = fs.readFileSync(component.filePath, "utf-8");
415
537
  const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
416
538
  ogImageComponentCtx.components.push({
@@ -427,7 +549,7 @@ const module = defineNuxtModule({
427
549
  nuxt.hooks.hook("nuxt-og-image:components", ogImageComponentCtx);
428
550
  });
429
551
  addTemplate({
430
- filename: "og-image-component-names.mjs",
552
+ filename: "nuxt-og-image/components.mjs",
431
553
  getContents() {
432
554
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
433
555
  },
@@ -437,6 +559,16 @@ const module = defineNuxtModule({
437
559
  nuxt.options.nitro.virtual["#nuxt-og-image/component-names.mjs"] = () => {
438
560
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
439
561
  };
562
+ let unoCssConfig = { theme: {} };
563
+ nuxt.hook("tailwindcss:config", (tailwindConfig) => {
564
+ unoCssConfig = defu(tailwindConfig.theme.extend, { ...tailwindConfig.theme || {}, extend: void 0 });
565
+ });
566
+ nuxt.hook("unocss:config", (_unoCssConfig) => {
567
+ unoCssConfig = { ..._unoCssConfig.theme };
568
+ });
569
+ nuxt.options.nitro.virtual["#nuxt-og-image/unocss-config.mjs"] = () => {
570
+ return `export const theme = ${JSON.stringify(unoCssConfig)}`;
571
+ };
440
572
  extendTypes("nuxt-og-image", ({ typesPath }) => {
441
573
  const componentImports = ogImageComponentCtx.components.map((component) => {
442
574
  const relativeComponentPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), component.path);
@@ -445,12 +577,17 @@ const module = defineNuxtModule({
445
577
  return `
446
578
  declare module 'nitropack' {
447
579
  interface NitroRouteRules {
448
- ogImage?: false | import('${typesPath}').OgImageOptions
580
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
449
581
  }
450
582
  interface NitroRouteConfig {
451
- ogImage?: false | import('${typesPath}').OgImageOptions
583
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
584
+ }
585
+ interface NitroRuntimeHooks {
586
+ 'nuxt-og-image:context': (ctx: import('${typesPath}').OgImageRenderEventContext) => void | Promise<void>
587
+ 'nuxt-og-image:satori:vnodes': (vnodes: import('${typesPath}').VNode) => void | Promise<void>
452
588
  }
453
589
  }
590
+
454
591
  declare module '#nuxt-og-image/components' {
455
592
  export interface OgImageComponents {
456
593
  ${componentImports}
@@ -458,8 +595,12 @@ ${componentImports}
458
595
  }
459
596
  `;
460
597
  });
598
+ const cacheEnabled = typeof config.runtimeCacheStorage !== "undefined" && config.runtimeCacheStorage !== false;
599
+ const runtimeCacheStorage = typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver;
600
+ let baseCacheKey = runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${version}` : `/nuxt-og-image@${version}`;
601
+ if (!cacheEnabled)
602
+ baseCacheKey = false;
461
603
  nuxt.hooks.hook("modules:done", async () => {
462
- nuxt.hooks.callHook("og-image:config", config);
463
604
  const normalisedFonts = config.fonts.map((f) => {
464
605
  if (typeof f === "string") {
465
606
  const [name, weight] = f.split(":");
@@ -474,29 +615,31 @@ ${componentImports}
474
615
  if (!nuxt.options._generate && nuxt.options.build) {
475
616
  nuxt.options.nitro.prerender = nuxt.options.nitro.prerender || {};
476
617
  nuxt.options.nitro.prerender.routes = nuxt.options.nitro.prerender.routes || [];
477
- normalisedFonts.filter((f) => !f.path).forEach(({ name, weight }) => {
618
+ normalisedFonts.filter((f) => !f.path && !f.key).forEach(({ name, weight }) => {
478
619
  nuxt.options.nitro.prerender.routes.push(`/__og-image__/font/${name}/${weight}.ttf`);
479
620
  });
480
621
  }
481
- nuxt.options.runtimeConfig["nuxt-og-image"] = {
622
+ let colorPreference = hasNuxtModule("@nuxtjs/color-mode") ? (await getNuxtModuleOptions("@nuxtjs/color-mode")).preference : "light";
623
+ if (!colorPreference || !["dark", "light"].includes(colorPreference))
624
+ colorPreference = "light";
625
+ const runtimeConfig = {
482
626
  version,
483
627
  // binding options
484
628
  satoriOptions: config.satoriOptions || {},
485
629
  resvgOptions: config.resvgOptions || {},
486
630
  sharpOptions: config.sharpOptions || {},
487
- runtimeSatori: config.runtimeSatori,
488
- runtimeBrowser: config.runtimeBrowser,
489
- // @ts-expect-error runtime type
490
631
  defaults: config.defaults,
632
+ debug: config.debug,
491
633
  // avoid adding credentials
492
- runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
634
+ baseCacheKey,
493
635
  // convert the fonts to uniform type to fix ts issue
494
636
  fonts: normalisedFonts,
495
- hasNuxtIcon: hasNuxtModule("nuxt-icon")
637
+ hasNuxtIcon: hasNuxtModule("nuxt-icon"),
638
+ colorPreference
496
639
  };
640
+ nuxt.hooks.callHook("nuxt-og-image:runtime-config", runtimeConfig);
641
+ nuxt.options.runtimeConfig["nuxt-og-image"] = runtimeConfig;
497
642
  });
498
- nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
499
- nuxt.options.nitro.experimental.wasm = true;
500
643
  if (nuxt.options.dev) {
501
644
  setupDevHandler(config, resolve);
502
645
  setupDevToolsUI(config, resolve);
@@ -505,8 +648,9 @@ ${componentImports}
505
648
  } else if (nuxt.options.build) {
506
649
  await setupBuildHandler(config, resolve);
507
650
  }
508
- if (nuxt.options.nitro.prerender?.routes || nuxt.options._generate)
509
- setupPrerenderHandler(config, resolve);
651
+ if (nuxt.options.build)
652
+ addServerPlugin(resolve("./runtime/nitro/plugins/prerender"));
653
+ setupPrerenderHandler(config, resolve);
510
654
  }
511
655
  });
512
656