nuxt-og-image 3.0.0-beta.8 → 3.0.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. package/README.md +4 -4
  2. package/dist/client/200.html +6 -5
  3. package/dist/client/404.html +6 -5
  4. package/dist/client/_nuxt/IconCSS.9f95294e.js +1 -0
  5. package/dist/client/_nuxt/IconCSS.f0b56d3e.css +1 -0
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/01a72661-4cae-4637-8364-242cd0ee1a35.json +1 -0
  8. package/dist/client/_nuxt/entry.a30f63d0.css +1 -0
  9. package/dist/client/_nuxt/entry.c5e613a6.js +108 -0
  10. package/dist/client/_nuxt/{error-404.66c6f07b.js → error-404.e1564a51.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.fed3c621.js → error-500.90b12af8.js} +1 -1
  12. package/dist/client/_nuxt/vanilla-picker-NKbIFE8h.23409a58.js +8 -0
  13. package/dist/client/index.html +6 -5
  14. package/dist/module.d.mts +63 -48
  15. package/dist/module.d.ts +63 -48
  16. package/dist/module.json +2 -2
  17. package/dist/module.mjs +343 -164
  18. package/dist/runtime/cache.d.ts +7 -10
  19. package/dist/runtime/cache.mjs +40 -27
  20. package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
  21. package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
  22. package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
  23. package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
  24. package/dist/runtime/components/Templates/{Official → Community}/BrandedLogo.vue +3 -2
  25. package/dist/runtime/components/Templates/Community/Nuxt.vue +6 -5
  26. package/dist/runtime/components/Templates/Community/NuxtSeo.vue +137 -0
  27. package/dist/runtime/components/Templates/Community/Pergel.vue +104 -0
  28. package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
  29. package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
  30. package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
  31. package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
  32. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  33. package/dist/runtime/composables/defineOgImage.mjs +33 -117
  34. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  35. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  36. package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
  37. package/dist/runtime/composables/defineOgImageScreenshot.mjs +13 -0
  38. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  39. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  40. package/dist/runtime/core/bindings/resvg/wasm-fs.d.ts +40 -0
  41. package/dist/runtime/core/bindings/resvg/wasm-fs.mjs +6 -0
  42. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -5
  43. package/dist/runtime/core/bindings/satori/wasm-fs.mjs +13 -0
  44. package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
  45. package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
  46. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  47. package/dist/runtime/core/cache/emojis.mjs +5 -0
  48. package/dist/runtime/core/cache/fonts.d.ts +3 -0
  49. package/dist/runtime/core/cache/fonts.mjs +6 -0
  50. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  51. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  52. package/dist/runtime/core/cache/prerender.d.ts +1 -5
  53. package/dist/runtime/core/cache/prerender.mjs +1 -2
  54. package/dist/runtime/core/env/assets.d.ts +0 -1
  55. package/dist/runtime/core/env/assets.mjs +0 -4
  56. package/dist/runtime/core/font/fetch.d.ts +2 -3
  57. package/dist/runtime/core/font/fetch.mjs +26 -19
  58. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  59. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  60. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  61. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  62. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  63. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  64. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  65. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  66. package/dist/runtime/core/options/fetch.d.ts +1 -1
  67. package/dist/runtime/core/options/fetch.mjs +10 -5
  68. package/dist/runtime/core/renderers/chromium/index.mjs +12 -15
  69. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  70. package/dist/runtime/core/renderers/chromium/screenshot.mjs +20 -15
  71. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  72. package/dist/runtime/core/renderers/satori/index.mjs +51 -25
  73. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  74. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  75. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  76. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +60 -30
  77. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  78. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +45 -0
  79. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  80. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  81. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  82. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  83. package/dist/runtime/core/utils/resolveRendererContext.mjs +47 -29
  84. package/dist/runtime/core/utils/wasm.d.ts +3 -0
  85. package/dist/runtime/core/utils/wasm.mjs +16 -0
  86. package/dist/runtime/nitro/plugins/nuxt-content.mjs +7 -6
  87. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  88. package/dist/runtime/nitro/plugins/prerender.mjs +20 -18
  89. package/dist/runtime/nitro/utils.d.ts +2 -0
  90. package/dist/runtime/nitro/utils.mjs +17 -0
  91. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +43 -0
  92. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -51
  93. package/dist/runtime/nuxt/utils.d.ts +3 -0
  94. package/dist/runtime/nuxt/utils.mjs +69 -0
  95. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +2 -3
  96. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +5 -7
  97. package/dist/runtime/server/routes/__og-image__/image.mjs +88 -0
  98. package/dist/runtime/types.d.ts +96 -27
  99. package/dist/runtime/utils.d.ts +4 -0
  100. package/dist/runtime/utils.mjs +11 -0
  101. package/dist/runtime/utils.pure.d.ts +6 -0
  102. package/dist/runtime/utils.pure.mjs +63 -0
  103. package/package.json +33 -38
  104. package/virtual.d.ts +49 -0
  105. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  106. package/dist/client/_nuxt/IconCSS.b9d753bf.js +0 -1
  107. package/dist/client/_nuxt/builds/meta/720964ec-8728-4ffb-b268-2e25afc2779b.json +0 -1
  108. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  109. package/dist/client/_nuxt/entry.56d31ea0.js +0 -137
  110. package/dist/client/grid.png +0 -0
  111. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  112. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  113. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  114. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  115. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  116. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  117. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  118. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  119. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  120. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  121. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  122. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  123. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  124. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  125. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  126. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  127. package/dist/runtime/core/font/cache.d.ts +0 -1
  128. package/dist/runtime/core/font/cache.mjs +0 -1
  129. package/dist/runtime/core/html/fetch.d.ts +0 -3
  130. package/dist/runtime/core/options/normalise.d.ts +0 -2
  131. package/dist/runtime/core/options/normalise.mjs +0 -26
  132. package/dist/runtime/core/renderers/satori/fonts.d.ts +0 -3
  133. package/dist/runtime/core/renderers/satori/fonts.mjs +0 -8
  134. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  135. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  136. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  137. package/dist/runtime/utilts.d.ts +0 -2
  138. package/dist/runtime/utilts.mjs +0 -8
  139. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → wasm-fs.d.ts} +0 -0
  140. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  141. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
  142. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
  143. /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.8";
17
+ const version = "3.0.0-rc.0";
13
18
 
14
19
  const autodetectableProviders = {
15
20
  azure_static: "azure",
@@ -26,72 +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": "wasm",
79
- "satori": "node",
80
- "sharp": false
81
- },
82
- 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
+ }
83
84
  },
85
+ "firebase": awsLambda,
84
86
  "vercel": awsLambda,
85
87
  "vercel-edge": {
86
- bindings: {
87
- "chromium": false,
88
- "css-inline": "node",
89
- "resvg": "wasm",
90
- "satori": "node",
91
- "sharp": "node"
92
- },
93
- wasmStrategy: "inline",
94
- 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
+ }
95
97
  },
96
98
  "cloudflare-pages": cloudflare,
97
99
  "cloudflare": cloudflare
@@ -116,31 +118,75 @@ function getPresetNitroPresetCompatibility(target) {
116
118
  return compatibility;
117
119
  }
118
120
  function applyNitroPresetCompatibility(nitroConfig, options) {
119
- let compatibility = options?.compatibility;
120
121
  const target = resolveNitroPreset(nitroConfig);
121
- if (!compatibility)
122
- compatibility = getPresetNitroPresetCompatibility(target);
123
- 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 = {};
124
129
  function applyBinding(key) {
125
- const binding = compatibility.bindings[key];
126
- if (binding === false)
127
- return { [`#nuxt-og-image/bindings/${key}`]: "unenv/runtime/mock/empty" };
128
- 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
+ };
129
137
  }
130
138
  nitroConfig.alias = defu(
131
139
  applyBinding("chromium"),
132
140
  applyBinding("satori"),
133
141
  applyBinding("resvg"),
134
142
  applyBinding("sharp"),
143
+ applyBinding("css-inline"),
135
144
  nitroConfig.alias || {}
136
145
  );
137
- if (target.includes("cloudflare")) {
138
- nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
139
- nitroConfig.rollupConfig.output.inlineDynamicImports = true;
146
+ if (Object.values(compatibility).includes("wasm")) {
147
+ nitroConfig.experimental = nitroConfig.experimental || {};
148
+ nitroConfig.experimental.wasm = true;
140
149
  }
141
- 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
+ }));
142
169
  }
143
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
+ }
144
190
  function extendTypes(module, template) {
145
191
  const nuxt = useNuxt();
146
192
  const { resolve } = createResolver(import.meta.url);
@@ -192,9 +238,15 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
192
238
  rpc.broadcast.refreshRouteData(path).catch(() => {
193
239
  });
194
240
  }
195
- if (options.componentDirs.some((dir) => path.includes(dir)))
196
- rpc.broadcast.refreshGlobalData().catch(() => {
197
- });
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
+ }
198
250
  });
199
251
  });
200
252
  nuxt.hook("devtools:customTabs", (tabs) => {
@@ -216,38 +268,42 @@ function setupDevToolsUI(options, resolve, nuxt = useNuxt()) {
216
268
 
217
269
  function setupDevHandler(options, resolve, nuxt = useNuxt()) {
218
270
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
219
- nitroConfig.alias["#nuxt-og-image/renderers/satori"] = options.runtimeSatori ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
220
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = options.runtimeBrowser ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
221
- applyNitroPresetCompatibility(nitroConfig, { resolve });
271
+ applyNitroPresetCompatibility(nitroConfig, { compatibility: options.compatibility?.dev, resolve });
222
272
  });
223
273
  }
224
274
 
225
275
  function setupGenerateHandler(options, resolve, nuxt = useNuxt()) {
226
276
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
227
- nitroConfig.alias["#nuxt-og-image/renderers/satori"] = "unenv/runtime/mock/empty";
228
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = "unenv/runtime/mock/empty";
229
277
  applyNitroPresetCompatibility(nitroConfig, {
230
278
  compatibility: {
231
- bindings: {
232
- "css-inline": false,
233
- "chromium": false,
234
- "resvg": false,
235
- "satori": false,
236
- "sharp": false
237
- }
279
+ "chromium": false,
280
+ "satori": false,
281
+ "css-inline": false,
282
+ "resvg": false,
283
+ "sharp": false
238
284
  },
239
285
  resolve
240
286
  });
287
+ assertSiteConfig("nuxt-og-image", {
288
+ url: "OG Image tags are required to be absolute URLs."
289
+ }, {
290
+ throwError: true
291
+ });
241
292
  });
242
293
  }
243
294
 
244
295
  function setupPrerenderHandler(options, resolve, nuxt = useNuxt()) {
245
- addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
246
296
  nuxt.hooks.hook("nitro:init", async (nitro) => {
247
297
  nitro.hooks.hook("prerender:config", async (nitroConfig) => {
248
- nitroConfig.alias["#nuxt-og-image/renderers/satori"] = resolve("./runtime/core/renderers/satori");
249
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = resolve("./runtime/core/renderers/chromium");
250
- 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
+ });
251
307
  });
252
308
  });
253
309
  }
@@ -257,44 +313,97 @@ async function setupBuildHandler(config, resolve, nuxt = useNuxt()) {
257
313
  if (typeof config.runtimeCacheStorage === "object")
258
314
  nuxt.options.nitro.storage["og-image"] = config.runtimeCacheStorage;
259
315
  nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
260
- nitroConfig.alias["#nuxt-og-image/renderers/satori"] = config.runtimeSatori ? resolve("./runtime/core/renderers/satori") : "unenv/runtime/mock/empty";
261
- nitroConfig.alias["#nuxt-og-image/renderers/chromium"] = config.runtimeBrowser ? resolve("./runtime/core/renderers/chromium") : "unenv/runtime/mock/empty";
262
- applyNitroPresetCompatibility(nitroConfig, { resolve, compatibility: config.runtimeCompatibility });
316
+ applyNitroPresetCompatibility(nitroConfig, { compatibility: config.compatibility?.runtime, resolve });
263
317
  nitroConfig.alias.electron = "unenv/runtime/mock/proxy-cjs";
264
318
  nitroConfig.alias.bufferutil = "unenv/runtime/mock/proxy-cjs";
265
319
  nitroConfig.alias["utf-8-validate"] = "unenv/runtime/mock/proxy-cjs";
266
320
  nitroConfig.alias.queue = "unenv/runtime/mock/proxy-cjs";
267
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);
359
+ }
360
+
361
+ function normaliseFontInput(fonts) {
362
+ return fonts.map((f) => {
363
+ if (typeof f === "string") {
364
+ const [name, weight] = f.split(":");
365
+ return {
366
+ cacheKey: f,
367
+ name,
368
+ weight: weight || "400",
369
+ style: "normal",
370
+ path: void 0
371
+ };
372
+ }
373
+ return {
374
+ cacheKey: f.key || `${f.name}:${f.weight}`,
375
+ style: "normal",
376
+ weight: 400,
377
+ ...f
378
+ };
379
+ });
268
380
  }
269
381
 
270
382
  const module = defineNuxtModule({
271
383
  meta: {
272
384
  name: "nuxt-og-image",
273
385
  compatibility: {
274
- nuxt: "^3.7.0",
386
+ nuxt: "^3.8.2",
275
387
  bridge: false
276
388
  },
277
389
  configKey: "ogImage"
278
390
  },
279
- defaults(nuxt) {
391
+ defaults() {
280
392
  return {
281
393
  enabled: true,
282
394
  defaults: {
395
+ emojis: "noto",
283
396
  renderer: "satori",
284
- component: "Fallback",
397
+ component: "NuxtSeo",
285
398
  width: 1200,
286
399
  height: 600,
287
- cache: true,
288
- // default is to cache the image for 1 day (24 hours)
289
- cacheTtl: 24 * 60 * 60 * 1e3
400
+ // default is to cache the image for 3 day (72 hours)
401
+ cacheMaxAgeSeconds: 60 * 60 * 24 * 3
290
402
  },
291
403
  componentDirs: ["OgImage", "OgImageTemplate"],
292
- runtimeSatori: true,
293
- runtimeBrowser: nuxt.options.dev,
294
404
  fonts: [],
295
405
  runtimeCacheStorage: true,
296
- playground: env.NODE_ENV === "development" || nuxt.options.dev,
297
- debug: false
406
+ debug: isDevelopment
298
407
  };
299
408
  },
300
409
  async setup(config, nuxt) {
@@ -310,17 +419,91 @@ const module = defineNuxtModule({
310
419
  }
311
420
  const { resolve } = createResolver(import.meta.url);
312
421
  const preset = resolveNitroPreset(nuxt.options.nitro);
313
- const compatibility = getPresetNitroPresetCompatibility(preset);
314
- config.defaults.extension = "jpg";
315
- if (!compatibility.bindings.sharp)
316
- config.defaults.extension = "png";
422
+ const targetCompatibility = getPresetNitroPresetCompatibility(preset);
423
+ const hasSharpDependency = !!await tryResolveModule("sharp");
424
+ const userConfiguredExtension = config.defaults.extension;
425
+ const hasConfiguredJpegs = userConfiguredExtension && ["jpeg", "jpg"].includes(userConfiguredExtension);
426
+ config.defaults.extension = userConfiguredExtension || (hasSharpDependency && targetCompatibility.sharp ? "jpg" : "png");
427
+ if (hasConfiguredJpegs && config.defaults.renderer !== "chromium") {
428
+ if (hasSharpDependency && !targetCompatibility.sharp) {
429
+ logger.warn(`Rendering JPEGs requires sharp which does not work with ${preset}. Images will be rendered as PNG at runtime.`);
430
+ config.compatibility = defu(config.compatibility, {
431
+ runtime: { sharp: false }
432
+ });
433
+ } else if (!hasSharpDependency) {
434
+ logger.warn("You have enabled `JPEG` images. These require the `sharp` dependency which is missing, installing it for you.");
435
+ await ensureDependencies(["sharp"]);
436
+ logger.warn("Support for `sharp` is limited so check the compatibility guide.");
437
+ }
438
+ } else if (!hasSharpDependency) {
439
+ config.compatibility = defu(config.compatibility, {
440
+ runtime: { sharp: false },
441
+ dev: { sharp: false },
442
+ prerender: { sharp: false }
443
+ });
444
+ }
445
+ let hasChromeLocally = false;
446
+ try {
447
+ hasChromeLocally = !!Launcher.getFirstInstallation();
448
+ } catch {
449
+ }
450
+ const isUndefinedOrTruthy = (v) => typeof v === "undefined" || v !== false;
451
+ if (isUndefinedOrTruthy(config.compatibility?.prerender?.chromium) && isUndefinedOrTruthy(config.compatibility?.runtime?.chromium)) {
452
+ if (isCI)
453
+ await ensureChromium(logger);
454
+ const hasPlaywrightDependency = !!await tryResolveModule("playwright");
455
+ if (hasChromeLocally) {
456
+ config.compatibility = defu(config.compatibility, {
457
+ runtime: { chromium: false },
458
+ dev: { chromium: "node" },
459
+ prerender: { chromium: "node" }
460
+ });
461
+ } else if (hasPlaywrightDependency && targetCompatibility.chromium) {
462
+ config.compatibility = defu(config.compatibility, {
463
+ runtime: { chromium: "node" },
464
+ dev: { chromium: "node" },
465
+ prerender: { chromium: "node" }
466
+ });
467
+ }
468
+ } else if (!hasChromeLocally && nuxt.options.dev && config.compatibility?.dev?.chromium === "node") {
469
+ await ensureChromium(logger);
470
+ }
317
471
  await installNuxtSiteConfig();
318
- if (hasNuxtModule("@nuxt/content")) {
472
+ if (hasNuxtModule("@nuxt/content"))
319
473
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
320
- addPlugin(resolve("./runtime/nuxt/plugins/nuxt-content-canonical-urls"));
321
- }
322
474
  if (!config.fonts.length)
323
475
  config.fonts = ["Inter:400", "Inter:700"];
476
+ if (preset === "cloudflare") {
477
+ config.fonts = config.fonts.filter((f) => {
478
+ if (typeof f !== "string" && f.path) {
479
+ logger.warn(`The ${f.name}:${f.weight} font was skipped because remote fonts are not available in Cloudflare Workers, please use a Google font.`);
480
+ return false;
481
+ }
482
+ return true;
483
+ });
484
+ }
485
+ if (preset === "stackblitz") {
486
+ config.fonts = config.fonts.map((f) => {
487
+ if (typeof f === "string" && f.startsWith("Inter:")) {
488
+ const [_, weight] = f.split(":");
489
+ return {
490
+ name: "Inter",
491
+ weight,
492
+ // nuxt server assets
493
+ key: `nuxt-og-image:fonts:inter-latin-ext-${weight}-normal.woff`
494
+ };
495
+ }
496
+ if (typeof f === "string" || !f.path && !f.key) {
497
+ 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.`);
498
+ return false;
499
+ }
500
+ return f;
501
+ }).filter(Boolean);
502
+ nuxt.hooks.hook("nitro:config", (nitroConfig) => {
503
+ nitroConfig.serverAssets = nitroConfig.serverAssets || [];
504
+ nitroConfig.serverAssets.push({ baseName: "nuxt-og-image:fonts", dir: resolve("./runtime/server/assets") });
505
+ });
506
+ }
324
507
  nuxt.options.experimental.componentIslands = true;
325
508
  addServerHandler({
326
509
  lazy: true,
@@ -337,52 +520,34 @@ const module = defineNuxtModule({
337
520
  addServerHandler({
338
521
  lazy: true,
339
522
  route: "/__og-image__/image/**",
340
- handler: resolve("./runtime/server/routes/__og-image__/image-[path]-og.[extension]")
523
+ handler: resolve("./runtime/server/routes/__og-image__/image")
341
524
  });
342
525
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"] = [];
343
- [
344
- // deprecated
345
- "Dynamic",
346
- "Static",
347
- // new
348
- "index",
349
- "Cached",
350
- "Component",
351
- "WithoutCache",
352
- "Screenshot"
353
- ].forEach((name) => {
354
- name = name === "index" ? "defineOgImage" : `defineOgImage${name}`;
526
+ ["defineOgImage", "defineOgImageComponent", "defineOgImageScreenshot"].forEach((name) => {
355
527
  addImports({
356
528
  name,
357
- from: resolve("./runtime/composables/defineOgImage")
529
+ from: resolve(`./runtime/composables/${name}`)
358
530
  });
359
531
  nuxt.options.optimization.treeShake.composables.client["nuxt-og-image"].push(name);
360
532
  });
361
533
  await addComponentsDir({
362
534
  path: resolve("./runtime/components/Templates/Community"),
363
- island: true
364
- });
365
- await addComponentsDir({
366
- path: resolve("./runtime/components/Templates/Official"),
367
- island: true
535
+ island: true,
536
+ watch: true
368
537
  });
369
538
  [
370
- // deprecated
371
- "Static",
372
- "Dynamic",
373
539
  // new
374
- "index",
375
- "Cached",
376
- "WithoutCache",
377
- "Screenshot"
540
+ "OgImage",
541
+ "OgImageScreenshot"
378
542
  ].forEach((name) => {
379
543
  addComponent({
380
- global: hasNuxtModule("@nuxt/content"),
381
- name: name === "index" ? "OgImage" : `OgImage${name}`,
382
- filePath: resolve(`./runtime/components/OgImage/${name}`)
544
+ name,
545
+ filePath: resolve(`./runtime/components/OgImage/${name}`),
546
+ ...config.componentOptions
383
547
  });
384
548
  });
385
- addPlugin(resolve("./runtime/nuxt/plugins/route-rule-og-image.server"));
549
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/route-rule-og-image.server") });
550
+ addPlugin({ mode: "server", src: resolve("./runtime/nuxt/plugins/og-image-canonical-urls.server") });
386
551
  const ogImageComponentCtx = { components: [] };
387
552
  nuxt.hook("components:extend", (components) => {
388
553
  ogImageComponentCtx.components = [];
@@ -400,8 +565,6 @@ const module = defineNuxtModule({
400
565
  let category = "app";
401
566
  if (component.filePath.includes(resolve("./runtime/components/Templates/Community")))
402
567
  category = "community";
403
- else if (component.filePath.includes(resolve("./runtime/components/Templates/Official")))
404
- category = "official";
405
568
  const componentFile = fs.readFileSync(component.filePath, "utf-8");
406
569
  const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
407
570
  ogImageComponentCtx.components.push({
@@ -418,7 +581,7 @@ const module = defineNuxtModule({
418
581
  nuxt.hooks.hook("nuxt-og-image:components", ogImageComponentCtx);
419
582
  });
420
583
  addTemplate({
421
- filename: "og-image-component-names.mjs",
584
+ filename: "nuxt-og-image/components.mjs",
422
585
  getContents() {
423
586
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
424
587
  },
@@ -428,6 +591,16 @@ const module = defineNuxtModule({
428
591
  nuxt.options.nitro.virtual["#nuxt-og-image/component-names.mjs"] = () => {
429
592
  return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
430
593
  };
594
+ let unoCssConfig = { theme: {} };
595
+ nuxt.hook("tailwindcss:config", (tailwindConfig) => {
596
+ unoCssConfig = defu(tailwindConfig.theme.extend, { ...tailwindConfig.theme || {}, extend: void 0 });
597
+ });
598
+ nuxt.hook("unocss:config", (_unoCssConfig) => {
599
+ unoCssConfig = { ..._unoCssConfig.theme };
600
+ });
601
+ nuxt.options.nitro.virtual["#nuxt-og-image/unocss-config.mjs"] = () => {
602
+ return `export const theme = ${JSON.stringify(unoCssConfig)}`;
603
+ };
431
604
  extendTypes("nuxt-og-image", ({ typesPath }) => {
432
605
  const componentImports = ogImageComponentCtx.components.map((component) => {
433
606
  const relativeComponentPath = relative(resolve(nuxt.options.rootDir, nuxt.options.buildDir, "module"), component.path);
@@ -436,12 +609,17 @@ const module = defineNuxtModule({
436
609
  return `
437
610
  declare module 'nitropack' {
438
611
  interface NitroRouteRules {
439
- ogImage?: false | import('${typesPath}').OgImageOptions
612
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
440
613
  }
441
614
  interface NitroRouteConfig {
442
- ogImage?: false | import('${typesPath}').OgImageOptions
615
+ ogImage?: false | import('${typesPath}').OgImageOptions & Record<string, any>
616
+ }
617
+ interface NitroRuntimeHooks {
618
+ 'nuxt-og-image:context': (ctx: import('${typesPath}').OgImageRenderEventContext) => void | Promise<void>
619
+ 'nuxt-og-image:satori:vnodes': (vnodes: import('${typesPath}').VNode, ctx: ctx: import('${typesPath}').OgImageRenderEventContext) => void | Promise<void>
443
620
  }
444
621
  }
622
+
445
623
  declare module '#nuxt-og-image/components' {
446
624
  export interface OgImageComponents {
447
625
  ${componentImports}
@@ -449,45 +627,45 @@ ${componentImports}
449
627
  }
450
628
  `;
451
629
  });
630
+ const cacheEnabled = typeof config.runtimeCacheStorage !== "undefined" && config.runtimeCacheStorage !== false;
631
+ const runtimeCacheStorage = typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver;
632
+ let baseCacheKey = runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${version}` : `/nuxt-og-image@${version}`;
633
+ if (!cacheEnabled)
634
+ baseCacheKey = false;
452
635
  nuxt.hooks.hook("modules:done", async () => {
453
- nuxt.hooks.callHook("og-image:config", config);
454
- const normalisedFonts = config.fonts.map((f) => {
455
- if (typeof f === "string") {
456
- const [name, weight] = f.split(":");
457
- return {
458
- name,
459
- weight,
460
- path: void 0
461
- };
462
- }
463
- return f;
464
- });
636
+ const normalisedFonts = normaliseFontInput(config.fonts);
465
637
  if (!nuxt.options._generate && nuxt.options.build) {
466
638
  nuxt.options.nitro.prerender = nuxt.options.nitro.prerender || {};
467
639
  nuxt.options.nitro.prerender.routes = nuxt.options.nitro.prerender.routes || [];
468
- normalisedFonts.filter((f) => !f.path).forEach(({ name, weight }) => {
640
+ normalisedFonts.filter((f) => !f.path && !f.key).forEach(({ name, weight }) => {
469
641
  nuxt.options.nitro.prerender.routes.push(`/__og-image__/font/${name}/${weight}.ttf`);
470
642
  });
471
643
  }
472
- nuxt.options.runtimeConfig["nuxt-og-image"] = {
644
+ const hasColorModeModule = hasNuxtModule("@nuxtjs/color-mode");
645
+ const colorModeOptions = hasColorModeModule ? await getNuxtModuleOptions("@nuxtjs/color-mode") : {};
646
+ let colorPreference = colorModeOptions.preference;
647
+ if (!colorPreference || colorPreference === "system")
648
+ colorPreference = colorModeOptions.fallback;
649
+ if (!colorPreference || colorPreference === "system")
650
+ colorPreference = "light";
651
+ const runtimeConfig = {
473
652
  version,
474
653
  // binding options
475
654
  satoriOptions: config.satoriOptions || {},
476
655
  resvgOptions: config.resvgOptions || {},
477
656
  sharpOptions: config.sharpOptions || {},
478
- runtimeSatori: config.runtimeSatori,
479
- runtimeBrowser: config.runtimeBrowser,
480
- // @ts-expect-error runtime type
481
657
  defaults: config.defaults,
658
+ debug: config.debug,
482
659
  // avoid adding credentials
483
- runtimeCacheStorage: typeof config.runtimeCacheStorage === "boolean" ? "default" : config.runtimeCacheStorage.driver,
660
+ baseCacheKey,
484
661
  // convert the fonts to uniform type to fix ts issue
485
662
  fonts: normalisedFonts,
486
- hasNuxtIcon: hasNuxtModule("nuxt-icon")
663
+ hasNuxtIcon: hasNuxtModule("nuxt-icon"),
664
+ colorPreference
487
665
  };
666
+ nuxt.hooks.callHook("nuxt-og-image:runtime-config", runtimeConfig);
667
+ nuxt.options.runtimeConfig["nuxt-og-image"] = runtimeConfig;
488
668
  });
489
- nuxt.options.nitro.experimental = nuxt.options.nitro.experimental || {};
490
- nuxt.options.nitro.experimental.wasm = true;
491
669
  if (nuxt.options.dev) {
492
670
  setupDevHandler(config, resolve);
493
671
  setupDevToolsUI(config, resolve);
@@ -496,8 +674,9 @@ ${componentImports}
496
674
  } else if (nuxt.options.build) {
497
675
  await setupBuildHandler(config, resolve);
498
676
  }
499
- if (nuxt.options.nitro.prerender?.routes || nuxt.options._generate)
500
- setupPrerenderHandler(config, resolve);
677
+ if (nuxt.options.build)
678
+ addServerPlugin(resolve("./runtime/nitro/plugins/prerender"));
679
+ setupPrerenderHandler(config, resolve);
501
680
  }
502
681
  });
503
682