nuxt-og-image 2.0.0-beta.7 → 2.0.0-beta.71

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 (117) hide show
  1. package/README.md +312 -97
  2. package/dist/client/200.html +2 -2
  3. package/dist/client/404.html +2 -2
  4. package/dist/client/_nuxt/IconCSS.0f60f096.js +1 -0
  5. package/dist/client/_nuxt/IconCSS.b41b9663.css +1 -0
  6. package/dist/client/_nuxt/ImageLoader.7571516f.css +1 -0
  7. package/dist/client/_nuxt/ImageLoader.87552e43.js +1 -0
  8. package/dist/client/_nuxt/entry.07d246ba.js +143 -0
  9. package/dist/client/_nuxt/entry.1311cc29.css +1 -0
  10. package/dist/client/_nuxt/{error-404.1ff52902.js → error-404.23b0054d.js} +1 -1
  11. package/dist/client/_nuxt/error-404.f3dd5020.css +1 -0
  12. package/dist/client/_nuxt/error-500.06915589.css +1 -0
  13. package/dist/client/_nuxt/{error-500.f7d30da5.js → error-500.6db75894.js} +1 -1
  14. package/dist/client/_nuxt/index.a32ee818.js +1 -0
  15. package/dist/client/_nuxt/index.ffbea0a9.css +1 -0
  16. package/dist/client/_nuxt/options.9bea558a.js +1 -0
  17. package/dist/client/_nuxt/png.d8e4cfeb.js +1 -0
  18. package/dist/client/_nuxt/{shiki.3a930bb8.js → shiki.aaf0d7e1.js} +1 -1
  19. package/dist/client/_nuxt/svg.43caac0d.js +1 -0
  20. package/dist/client/_nuxt/vnodes.574f3876.js +1 -0
  21. package/dist/client/index.html +2 -2
  22. package/dist/client/options/index.html +2 -2
  23. package/dist/client/png/index.html +2 -2
  24. package/dist/client/svg/index.html +2 -2
  25. package/dist/client/vnodes/index.html +2 -2
  26. package/dist/module.d.ts +101 -11
  27. package/dist/module.json +2 -2
  28. package/dist/module.mjs +394 -134
  29. package/dist/runtime/browserUtil.d.ts +1 -0
  30. package/dist/runtime/browserUtil.mjs +10 -5
  31. package/dist/runtime/components/{OgImageDynamic.d.ts → OgImage/Cached.d.ts} +2 -2
  32. package/dist/runtime/components/OgImage/Cached.mjs +10 -0
  33. package/dist/runtime/components/OgImage/Dynamic.d.ts +8 -0
  34. package/dist/runtime/components/{OgImageDynamic.mjs → OgImage/Dynamic.mjs} +3 -3
  35. package/dist/runtime/components/{OgImageScreenshot.d.ts → OgImage/Screenshot.d.ts} +2 -2
  36. package/dist/runtime/components/{OgImageScreenshot.mjs → OgImage/Screenshot.mjs} +2 -2
  37. package/dist/runtime/components/OgImage/Static.d.ts +8 -0
  38. package/dist/runtime/components/{OgImageStatic.mjs → OgImage/Static.mjs} +3 -3
  39. package/dist/runtime/components/{OgImageStatic.d.ts → OgImage/WithoutCache.d.ts} +2 -2
  40. package/dist/runtime/components/OgImage/WithoutCache.mjs +10 -0
  41. package/dist/runtime/components/OgImage/index.d.ts +5 -0
  42. package/dist/runtime/components/OgImage/index.mjs +10 -0
  43. package/dist/runtime/components/OgImageTemplate/Fallback.vue +170 -0
  44. package/dist/runtime/composables/defineOgImage.d.ts +12 -4
  45. package/dist/runtime/composables/defineOgImage.mjs +31 -49
  46. package/dist/runtime/composables/util.d.ts +2 -0
  47. package/dist/runtime/composables/util.mjs +26 -0
  48. package/dist/runtime/nitro/middleware/og.png.mjs +54 -8
  49. package/dist/runtime/nitro/middleware/playground.mjs +4 -3
  50. package/dist/runtime/nitro/plugins/prerender.d.ts +3 -0
  51. package/dist/runtime/nitro/plugins/prerender.mjs +28 -0
  52. package/dist/runtime/nitro/providers/browser/lambda.d.ts +1 -1
  53. package/dist/runtime/nitro/providers/browser/lambda.mjs +3 -3
  54. package/dist/runtime/nitro/providers/browser/{node.mjs → playwright.mjs} +0 -9
  55. package/dist/runtime/nitro/providers/browser/universal.d.ts +1 -0
  56. package/dist/runtime/nitro/providers/browser/universal.mjs +33 -0
  57. package/dist/runtime/nitro/providers/png/resvg-node.d.ts +4 -0
  58. package/dist/runtime/nitro/providers/png/resvg-node.mjs +6 -0
  59. package/dist/runtime/nitro/providers/png/resvg-wasm.d.ts +3 -0
  60. package/dist/runtime/nitro/providers/png/resvg-wasm.mjs +11 -0
  61. package/dist/runtime/nitro/providers/{svg2png/universal.d.ts → png/svg2png.d.ts} +2 -3
  62. package/dist/runtime/nitro/providers/png/svg2png.mjs +11 -0
  63. package/dist/runtime/nitro/providers/satori/{webworker.d.ts → yoga-wasm.d.ts} +2 -3
  64. package/dist/runtime/nitro/providers/satori/{webworker.mjs → yoga-wasm.mjs} +4 -5
  65. package/dist/runtime/nitro/renderers/browser.d.ts +2 -2
  66. package/dist/runtime/nitro/renderers/browser.mjs +14 -10
  67. package/dist/runtime/nitro/renderers/satori/index.d.ts +2 -2
  68. package/dist/runtime/nitro/renderers/satori/index.mjs +27 -32
  69. package/dist/runtime/nitro/renderers/satori/plugins/emojis.d.ts +1 -1
  70. package/dist/runtime/nitro/renderers/satori/plugins/emojis.mjs +19 -6
  71. package/dist/runtime/nitro/renderers/satori/plugins/encoding.d.ts +1 -1
  72. package/dist/runtime/nitro/renderers/satori/plugins/encoding.mjs +5 -7
  73. package/dist/runtime/nitro/renderers/satori/plugins/flex.d.ts +1 -1
  74. package/dist/runtime/nitro/renderers/satori/plugins/flex.mjs +8 -10
  75. package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.d.ts +1 -1
  76. package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.mjs +45 -13
  77. package/dist/runtime/nitro/renderers/satori/plugins/twClasses.d.ts +1 -1
  78. package/dist/runtime/nitro/renderers/satori/plugins/twClasses.mjs +5 -7
  79. package/dist/runtime/nitro/renderers/satori/utils.d.ts +4 -5
  80. package/dist/runtime/nitro/renderers/satori/utils.mjs +28 -17
  81. package/dist/runtime/nitro/routes/debug.d.ts +8 -0
  82. package/dist/runtime/nitro/routes/debug.mjs +14 -0
  83. package/dist/runtime/nitro/routes/font.mjs +2 -2
  84. package/dist/runtime/nitro/routes/html.mjs +102 -27
  85. package/dist/runtime/nitro/routes/options.d.ts +2 -2
  86. package/dist/runtime/nitro/routes/options.mjs +25 -22
  87. package/dist/runtime/nitro/routes/svg.mjs +5 -3
  88. package/dist/runtime/nitro/routes/vnode.mjs +5 -3
  89. package/dist/runtime/nitro/utils-pure.d.ts +2 -2
  90. package/dist/runtime/nitro/utils-pure.mjs +1 -4
  91. package/dist/runtime/nitro/utils.d.ts +11 -11
  92. package/dist/runtime/nitro/utils.mjs +69 -54
  93. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  94. package/dist/runtime/public-assets-optional/resvg/resvg.wasm +0 -0
  95. package/dist/types.d.ts +6 -0
  96. package/package.json +39 -27
  97. package/dist/client/_nuxt/IconCSS.a041aca0.js +0 -1
  98. package/dist/client/_nuxt/ImageLoader.9bf39d71.js +0 -1
  99. package/dist/client/_nuxt/entry.74018bda.js +0 -5
  100. package/dist/client/_nuxt/entry.7a8c1ab2.css +0 -1
  101. package/dist/client/_nuxt/error-404.1469f10f.css +0 -1
  102. package/dist/client/_nuxt/error-500.92b94fae.css +0 -1
  103. package/dist/client/_nuxt/error-component.cf7543e5.js +0 -3
  104. package/dist/client/_nuxt/index.3f356409.js +0 -1
  105. package/dist/client/_nuxt/options.56a3e5f9.js +0 -1
  106. package/dist/client/_nuxt/png.37f3e77b.js +0 -1
  107. package/dist/client/_nuxt/svg.186c6bd1.js +0 -1
  108. package/dist/client/_nuxt/vnodes.a799f183.js +0 -1
  109. package/dist/runtime/components/OgImageBasic.island.vue +0 -92
  110. package/dist/runtime/nitro/providers/svg2png/universal.mjs +0 -9
  111. /package/dist/runtime/nitro/providers/browser/{node.d.ts → playwright.d.ts} +0 -0
  112. /package/dist/runtime/nitro/providers/satori/{node.d.ts → default.d.ts} +0 -0
  113. /package/dist/runtime/nitro/providers/satori/{node.mjs → default.mjs} +0 -0
  114. /package/dist/runtime/{public-assets → public-assets-optional/inter-font}/inter-latin-ext-400-normal.woff +0 -0
  115. /package/dist/runtime/{public-assets → public-assets-optional/inter-font}/inter-latin-ext-700-normal.woff +0 -0
  116. /package/dist/runtime/{public-assets → public-assets-optional/svg2png}/svg2png.wasm +0 -0
  117. /package/dist/runtime/{public-assets → public-assets-optional/yoga}/yoga.wasm +0 -0
package/README.md CHANGED
@@ -13,7 +13,7 @@
13
13
  Enlightened OG Image generation for Nuxt 3.
14
14
  </p>
15
15
 
16
- <img src="https://repository-images.githubusercontent.com/578125755/05ce0b00-ef15-48d0-94b5-b999373a20f9">
16
+ <img src="https://repository-images.githubusercontent.com/578125755/90f77ca8-95be-4e06-9600-332afe1ba24f">
17
17
 
18
18
  <p align="center">
19
19
  <table>
@@ -38,7 +38,7 @@ Enlightened OG Image generation for Nuxt 3.
38
38
  - ▲ Render using [Satori](https://github.com/vercel/satori): Tailwind classes, Google fonts, emoji support and more!
39
39
  - 🤖 Or prerender using the Browser: Supporting painless, complex templates
40
40
  - 📸 Feeling lazy? Just generate screenshots for every page: hide elements, wait for animations, and more
41
- - ⚙️ Works on the edge: Vercel Edge and Cloudflare Workers
41
+ - ⚙️ Works on the edge: Vercel Edge, Netlify Edge and Cloudflare Workers
42
42
 
43
43
  ## Demos
44
44
 
@@ -50,9 +50,11 @@ Enlightened OG Image generation for Nuxt 3.
50
50
 
51
51
  ```bash
52
52
  # Install module
53
- npm install --save-dev nuxt-og-image
53
+ npm install --save-dev nuxt-og-image@beta
54
54
  # Using yarn
55
- yarn add --dev nuxt-og-image
55
+ yarn add --dev nuxt-og-image@beta
56
+ #
57
+ pnpm add -D nuxt-og-image@beta
56
58
  ```
57
59
 
58
60
  ## Setup
@@ -67,30 +69,8 @@ export default defineNuxtConfig({
67
69
  })
68
70
  ```
69
71
 
70
- #### Requirements
71
-
72
- This feature uses Nuxt Islands, which requires Nuxt >= 3.1.
73
-
74
- ### Add your host name
75
-
76
- The `og:image` meta tag requires the full URL, so you must provide your site host.
77
-
78
- _nuxt.config.ts_
79
-
80
- ```ts
81
- export default defineNuxtConfig({
82
- // Recommended
83
- runtimeConfig: {
84
- public: {
85
- siteUrl: process.env.NUXT_PUBLIC_SITE_URL || 'https://example.com',
86
- }
87
- },
88
- // OR
89
- ogImage: {
90
- host: 'https://example.com',
91
- },
92
- })
93
- ```
72
+ This module requires [Nuxt Server Components](https://nuxt.com/docs/guide/directory-structure/components#standalone-server-components)
73
+ which will be enabled for you.
94
74
 
95
75
  # Guides
96
76
 
@@ -98,31 +78,31 @@ export default defineNuxtConfig({
98
78
 
99
79
  For this guide, you will create your Satori OG image using the default component for your home page.
100
80
 
101
- ### 1. Define a static OG Image
81
+ ### 1. Define an OG Image
102
82
 
103
- Within your `pages/index.vue`, use `defineOgImageStatic` or `OgImageStatic` to define your `og:image` component.
104
-
105
- Make sure you have defined some metadata as props will be inferred from it.
83
+ Within your `pages/index.vue`, use `defineOgImage()` or `<OgImage />` to define your `og:image` component.
106
84
 
107
85
  ```vue
108
86
  <script lang="ts" setup>
109
- // 1. make sure you have some meta
110
- useSeoMeta({
111
- title: 'Home',
112
- description: 'My awesome home page.',
113
- })
114
- // 2a. Use the Composition API
115
- defineOgImageStatic()
87
+ const ogImageOptions = {
88
+ title: 'My awesome home page.',
89
+ }
90
+ // a. Use the Composition API
91
+ defineOgImage(ogImageOptions)
116
92
  </script>
117
93
 
118
94
  <template>
119
95
  <div>
120
- <!-- 2b. OR Component API -->
121
- <OgImageStatic />
96
+ <!-- b. OR Component API -->
97
+ <OgImage v-bind="ogImageOptions" />
122
98
  </div>
123
99
  </template>
124
100
  ```
125
101
 
102
+ This will use the default template [OgImageBasic](./src/runtime/components/OgImageBasic.island.vue),
103
+ provided by this module.
104
+
105
+
126
106
  ### 2. View your `og:image`
127
107
 
128
108
  Appending `/__og_image__` to the end of the URL will show you the playground for that pages `og:image`. This provides
@@ -132,54 +112,58 @@ For example, if your local site is hosted at `http://localhost:3000`, you can vi
132
112
 
133
113
  ### 3. Customize your `og:image`
134
114
 
135
- While you have the playground open, start customising the OG Image by providing options to the `defineOgImageStatic` function.
115
+ While you have the playground open, start customizing the OG Image by modifying the `ogImageOptions`.
116
+ Full HMR is supported, so you should see your changes instantly.
136
117
 
137
- ```vue
138
- <script lang="ts" setup>
139
- defineOgImageStatic({
140
- title: 'Welcome to my site!',
141
- background: 'lightblue'
142
- })
143
- </script>
144
- ```
145
-
146
- Congrats, you've set up your first Satori `og:image`! You can checkout the [options](./src/runtime/components/OgImageBasic.island.vue) of the default template.
118
+ Congrats, you've set up your first Satori `og:image`!
119
+ You can check out the [options](./src/runtime/components/OgImageBasic.island.vue) of the default template.
147
120
 
148
121
  ## Making your own Satori template
149
122
 
150
123
  Templates for OG images are powered by Nuxt Islands, which are just Vue components. In this guide we'll create a new
151
124
  template and use it for our `og:image`.
152
125
 
153
- ### 1. Create an island component
154
-
155
- Make a folder in your components directory called `islands`.
126
+ ### 1. Create your template component
156
127
 
157
- Within this directory make a new component called `MyOgImage.vue`,
158
- you can use the following template to begin:
128
+ Make a new file at the path `./components/OgImage/Default.vue` with the following contents:
159
129
 
160
130
  ```vue
161
131
  <script setup lang="ts">
162
132
  const props = defineProps({
163
133
  title: String,
164
134
  })
135
+
136
+ // inherited attrs can mess up the satori parser
137
+ defineOptions({
138
+ inheritAttrs: false,
139
+ })
165
140
  </script>
166
141
 
167
142
  <template>
168
143
  <div class="w-full h-full flex text-white bg-blue-500 items-center justify-center">
169
- <h1 :style="{ fontSize: '70px' }">
144
+ <h1>
170
145
  {{ title }} 👋
171
146
  </h1>
172
147
  </div>
173
148
  </template>
149
+ <style scoped>
150
+ h1 {
151
+ font-size: 70px;
152
+ }
153
+ </style>
174
154
  ```
175
155
 
156
+ The convention is to use either the `OgImage` or `OgImageTemplate` folders within `components`.
157
+
158
+ See [componentDirs](#component-dirs) if you prefer to use a different named directory.
159
+
176
160
  ### 2. Use the new template
177
161
 
178
- Now that you have your template, you can use it in for your `defineOgImageStatic` function.
162
+ Now that you have your template, you can use it in for your `defineOgImage` composable.
179
163
 
180
164
  ```vue
181
165
  <script lang="ts" setup>
182
- defineOgImageStatic({
166
+ defineOgImage({
183
167
  component: 'MyOgImage',
184
168
  title: 'Welcome to my site!'
185
169
  })
@@ -192,7 +176,7 @@ View this image in your browser by appending `/__og_image__` to the end of the U
192
176
 
193
177
  Now that you have your template, you can start customizing it.
194
178
 
195
- Any options you pass to the `defineOgImageStatic` composable will be available in the component. With this in mind, we can
179
+ Any options you pass to the `defineOgImage` composable will be available in the component. With this in mind, we can
196
180
  add support for changing the background color.
197
181
 
198
182
  ```vue
@@ -205,18 +189,23 @@ const props = defineProps({
205
189
 
206
190
  <template>
207
191
  <div :class="[backgroundColor]" class="w-full h-full flex text-white items-center justify-center">
208
- <h1 :style="{ fontSize: '70px' }">
192
+ <h1>
209
193
  {{ title }} 👋
210
194
  </h1>
211
195
  </div>
212
196
  </template>
197
+ <style scoped>
198
+ h1 {
199
+ font-size: 70px;
200
+ }
201
+ </style>
213
202
  ```
214
203
 
215
- Now let's customise the background to be green instead.
204
+ Now let's customize the background to be green instead.
216
205
 
217
206
  ```vue
218
207
  <script lang="ts" setup>
219
- defineOgImageStatic({
208
+ defineOgImage({
220
209
  component: 'MyOgImage',
221
210
  title: 'Welcome to my site!',
222
211
  backgroundColor: 'bg-green-500'
@@ -241,6 +230,105 @@ Out of the box, this module provides support for the following:
241
230
 
242
231
  If you find Satori is too limiting for your needs, you can always use the `browser` provider to capture browser screenshots instead.
243
232
 
233
+
234
+ ## Bypassing cache
235
+
236
+ Caching og images is enabled by default, if you need to generate dynamically at runtime,
237
+ you can modify the use the `defineOgImageWithoutCache(options)` composable or `<OgImageWithoutCache v-bind="options" />` component.
238
+
239
+ This mode is not compatible with `nuxt generate`.
240
+
241
+ ## SSG Images
242
+
243
+ When using `nuxt generate`, you will need to provide some additional configuration.
244
+
245
+ - You must provide a `siteUrl` so that the meta tags can be generated correctly as absolute URLs.
246
+
247
+ ```ts
248
+ export default defineNuxtConfig({
249
+ // Recommended
250
+ runtimeConfig: {
251
+ public: {
252
+ siteUrl: process.env.NUXT_PUBLIC_SITE_URL || 'https://example.com',
253
+ }
254
+ },
255
+ // OR
256
+ ogImage: {
257
+ host: 'https://example.com',
258
+ },
259
+ })
260
+ ```
261
+
262
+ - You must prerender all pages that use `og:image`.
263
+
264
+ ```ts
265
+ export default defineNuxtConfig({
266
+ nitro: {
267
+ prerender: {
268
+ crawlLinks: true, // recommended
269
+ routes: [
270
+ '/',
271
+ // list all routes that use og:image if you're not using crawlLinks
272
+ '/about',
273
+ '/blog',
274
+ '/blog/my-first-post',
275
+ ]
276
+ }
277
+ }
278
+ })
279
+ ```
280
+
281
+ ## SSR Images
282
+
283
+ ### Compatibility
284
+
285
+ Both Satori and Browser will work in Node based environments. Prerendering is fully supported.
286
+
287
+ When you want to generate dynamic images at runtime there are certain Nitro runtime limitations.
288
+
289
+ | Provider | Satori | Browser |
290
+ |---------------------------------------------------------------------------------|-----------------------|---------|
291
+ | Node | ✅ | ✅ |
292
+ | [Vercel](https://nuxt-og-image-playground.vercel.app/) | ✅ | ❌ |
293
+ | [Vercel Edge](https://nuxt-og-image-playground-gkdt.vercel.app/) | ✅ | ❌ |
294
+ | [Cloudflare Pages](https://nuxt-og-image-playground.pages.dev/) | ✅ | ❌ |
295
+ | [Netlify](https://nuxt-og-image-playground-netlify.netlify.app/) | ✅ | ❌ |
296
+ | [Netlify Edge](https://nuxt-og-image-playground-netlify-edge.netlify.app/) | (Soon) | ❌ |
297
+ | [StackBlitz](https://stackblitz.com/edit/nuxt-starter-pxs3wk?file=package.json) | ✅ (emojis don't work) | ❌ |
298
+
299
+ Other providers are yet to be tested. Please create an issue if your nitro preset is not listed.
300
+
301
+
302
+ When using `nuxt build`, you can only use the `browser` provider with the `node` Nitro preset.
303
+
304
+ If you intend to use the `browser` provider in production, make sure you include the `playwright` dependency.
305
+
306
+ ```bash
307
+ npm i playwright
308
+ ```
309
+
310
+ You can get around this by prerendering any pages that use `og:image`. Note that dynamic browser generated images are not supported at all,
311
+ you should use the Satori provider.
312
+
313
+
314
+ ```ts
315
+ export default defineNuxtConfig({
316
+ nitro: {
317
+ prerender: {
318
+ crawlLinks: true, // recommended
319
+ routes: [
320
+ '/',
321
+ // list all routes that use og:image if you're not using crawlLinks
322
+ '/about',
323
+ '/blog',
324
+ '/blog/my-first-post',
325
+ ]
326
+ }
327
+ }
328
+ })
329
+ ```
330
+
331
+
244
332
  ## Taking screenshots
245
333
 
246
334
  If you want to simply take a screenshot of your page, you can use the `OgImageScreenshot` component or `defineOgImageScreenshot` composable.
@@ -251,11 +339,11 @@ defineOgImageScreenshot()
251
339
  </script>
252
340
  ```
253
341
 
254
- Alternatively you can pass the `{ provider: 'browser' }` option to `defineOgImageStatic`.
342
+ Alternatively you can pass the `{ provider: 'browser' }` option to `defineOgImage`.
255
343
 
256
344
  ```vue
257
345
  <script lang="ts" setup>
258
- defineOgImageStatic({
346
+ defineOgImage({
259
347
  component: 'MyAwesomeOgImage',
260
348
  // this will take a browser screenshot
261
349
  provider: 'browser'
@@ -282,15 +370,144 @@ _package.json_
282
370
  }
283
371
  ```
284
372
 
373
+ ## Custom Fonts / Supporting non-english characters
374
+
375
+ When creating your OG Image, you'll probably want to use a font custom to your project.
376
+
377
+ To make this easier for you, Google Fonts are loaded by default with Inter 400 and Inter 700.
378
+
379
+ You can easily load different Google Fonts by using their name+weight. For example:
380
+
381
+ ```ts
382
+ export default defineNuxtConfig({
383
+ ogImage: {
384
+ fonts: [
385
+ // will load the Noto Sans font from Google fonts
386
+ 'Noto+Sans:400'
387
+ ]
388
+ }
389
+ })
390
+ ```
391
+
392
+ This also lets you support non-english characters by adding the appropriate font to your config.
393
+
394
+ For example, to support Hebrew characters, you can use the config:
395
+
396
+ ```ts
397
+ export default defineNuxtConfig({
398
+ ogImage: {
399
+ fonts: [
400
+ // will load this font from Google fonts
401
+ 'Noto+Sans+Hebrew:400'
402
+ ]
403
+ }
404
+ })
405
+ ````
406
+
407
+ If you'd like to load a font locally,
408
+ then you can provide the configuration as an object:
409
+
410
+ ```ts
411
+ export default defineNuxtConfig({
412
+ ogImage: {
413
+ fonts: [
414
+ {
415
+ name: 'optieinstein',
416
+ weight: 800,
417
+ // path must point to a public font file
418
+ path: '/OPTIEinstein-Black.otf',
419
+ }
420
+ ],
421
+ }
422
+ })
423
+ ```
424
+
425
+ Make sure to set the font family in your component to match the font name.
426
+
427
+ ```vue
428
+ <template>
429
+ <div :style="{ fontFamily: 'optieinstein' }">
430
+ <!-- Your component -->
431
+ </div>
432
+ </template>
433
+ ```
434
+
435
+ ## Runtime Caching
436
+
437
+ When images are generated at runtime, caching is enabled by default to reduce the load on your server.
438
+
439
+ By default, it will use the default storage engine for your Nitro preset.
440
+ You can customise the storage engine by providing a `runtimeCacheStorage` option to the `ogImage` config.
441
+
442
+ The option takes the same configuration as the Nuxt `nitro.storage` option.
443
+ See the [Nitro Storage Layer](https://nitro.unjs.io/guide/storage) documentation for more details.
444
+
445
+ For example:
446
+
447
+ ```ts
448
+ export default defineNuxtConfig({
449
+ ogImage: {
450
+ // cloudflare kv binding example, set your own config
451
+ runtimeCacheStorage: {
452
+ driver: 'cloudflare-kv-binding',
453
+ binding: 'OG_IMAGE_CACHE'
454
+ }
455
+ }
456
+ })
457
+ ````
458
+
459
+ By default, static images will be cached for 24 hours. You can change the image TTL by providing `cacheTtl` when defining the image.
460
+
461
+ ```ts
462
+ defineOgImage({
463
+ // ...
464
+ cacheTtl: 60 * 60 * 24 * 7 // 7 days
465
+ })
466
+ ```
467
+
468
+ Alternatively, you can change the default cacheTtl time in your nuxt.config.
469
+
470
+
471
+ ```ts
472
+ export default defineNuxtConfig({
473
+ ogImage: {
474
+ defaults: {
475
+ cacheTtl: 60 * 60 * 24 * 7 // 7 days
476
+ }
477
+ }
478
+ })
479
+ ````
480
+
481
+ You can also provide a configuration for the `cacheKey`. This gives you control over the cache bursting of the images.
482
+
483
+ ```vue
484
+ <script lang="ts" setup>
485
+ defineOgImage({
486
+ cacheKey: `${myData.id}:${myData.updatedAt}`,
487
+ })
488
+ </script>
489
+ ```
490
+
491
+ If you prefer not to cache your images you can always disable them by providing a `false` value.
492
+
493
+ ```ts
494
+ export default defineNuxtConfig({
495
+ ogImage: {
496
+ // no runtime cache
497
+ runtimeCacheStorage: false
498
+ }
499
+ })
500
+ ````
501
+
285
502
  # API
286
503
 
287
504
  The module exposes a composition and component API to implement your `og:image` generation. You should pick
288
505
  whichever one you prefer using.
289
506
 
290
- ## OgImageStatic / defineOgImageStatic
507
+ ## OgImage / defineOgImage
291
508
 
292
- The `OgImageStatic` component and the `defineOgImageStatic` composable creates a static image
293
- that will be pre-rendered.
509
+ The `OgImage` component and the `defineOgImage` composable creates a static image
510
+ that will be prerendered.
294
511
 
295
512
  The options follow the [OgImageOptions](#OgImageOptions) interface,
296
513
  any additional options will be passed to the `component` as props.
@@ -302,7 +519,7 @@ It is useful for images that do not change at runtime.
302
519
  ```vue
303
520
  <script setup lang="ts">
304
521
  // a. Composition API
305
- defineOgImageStatic({
522
+ defineOgImage({
306
523
  component: 'MyOgImageTemplate',
307
524
  title: 'Hello world',
308
525
  theme: 'dark'
@@ -311,7 +528,7 @@ defineOgImageStatic({
311
528
 
312
529
  <template>
313
530
  <!-- b. Component API -->
314
- <OgImageStatic
531
+ <OgImage
315
532
  component="MyOgImageTemplate"
316
533
  title="Hello world"
317
534
  theme="dark"
@@ -320,9 +537,9 @@ defineOgImageStatic({
320
537
  ```
321
538
 
322
539
 
323
- ## OgImageDynamic / defineOgImageDynamic
540
+ ## OgImageWithoutCache / defineOgImageWithoutCache
324
541
 
325
- The `OgImageDynamic` component and the `defineOgImageDynamic` composable creates a dynamic image. They are not pre-rendered and will
542
+ The `OgImageWithoutCache` component and the `defineOgImageWithoutCache` composable creates a dynamic image. They are not prerendered and will
326
543
  be generated at runtime.
327
544
 
328
545
  The options follow the [OgImageOptions](#OgImageOptions) interface,
@@ -337,19 +554,19 @@ This feature is not compatible with static sites built using `nuxi generate`.
337
554
  const dynamicData = await fetch('https://example.com/api')
338
555
 
339
556
  // a. Composition API
340
- defineOgImageDynamic({
557
+ defineOgImageWithoutCache({
341
558
  component: 'MyOgImageTemplate',
342
559
  title: 'Hello world',
343
- dynamicData,
560
+ ...dynamicData,
344
561
  })
345
562
  </script>
346
563
 
347
564
  <template>
348
565
  <!-- b. Component API -->
349
- <OgImageDynamic
566
+ <OgImageWithoutCache
350
567
  component="MyOgImageTemplate"
351
568
  title="Hello world"
352
- :dynamic-data="dynamicData"
569
+ v-bind="dynamicData"
353
570
  />
354
571
  </template>
355
572
  ```
@@ -396,12 +613,14 @@ The name of the component to use as the template. By default, it uses OgImageBas
396
613
  - Required: `false`
397
614
 
398
615
  The provider to use to generate the image. The default provider is `satori`.
399
- When you use `browser` it will use Puppeteer to generate the image.
616
+ When you use `browser` it will use Playwright to generate the image.
400
617
 
401
- ### `prerender`
618
+ ### `cache`
402
619
 
403
620
  - Type: `boolean`
404
- - Default: `true` when static, `false` when dynamic
621
+ - Default: `true` when using `defineOgImage`, `false` when dynamic
622
+
623
+ Controls the prerendering of the image. A non-static image is one that will be generated at runtime and not cached.
405
624
 
406
625
 
407
626
  ## OgImageScreenshot / defineOgImageScreenshot
@@ -495,13 +714,13 @@ defineOgImageScreenshot({
495
714
 
496
715
  ## Module Config
497
716
 
498
- ### `host`
717
+ ### `siteUrl`
499
718
 
500
719
  - Type: `string`
501
720
  - Default: `undefined`
502
721
  - Required: `true`
503
722
 
504
- The host of your site. This is required to generate the absolute path of the `og:image`.
723
+ The site URL of your site. This is required when prerendering to generate the absolute path of the `og:image`.
505
724
 
506
725
  ### `defaults`
507
726
 
@@ -511,15 +730,6 @@ The host of your site. This is required to generate the absolute path of the `og
511
730
 
512
731
  The default options to use when generating images.
513
732
 
514
- ### `forcePrerender`
515
-
516
- - Type: `boolean`
517
- - Default: `false`
518
- - Required: `false`
519
-
520
- This is enabled when you run `nuxi generate`. It forces all OG images to be pre-rendered as the server is not available to generate
521
- runtime images.
522
-
523
733
  ### `fonts`
524
734
 
525
735
  - Type: ``${string}:${number}`[]`
@@ -546,16 +756,21 @@ export default defineNuxtConfig({
546
756
 
547
757
  Options to pass to Satori when generating images. See the [Satori docs](https://github.com/vercel/satori).
548
758
 
549
- ### `experimentalNitroBrowser` (experimental)
759
+ ### `runtimeSatori`
550
760
 
551
761
  - Type: `boolean`
552
- - Default: `false`
553
- - Required: `false`
762
+ - Default: `true`
763
+
764
+ Whether to use Satori at runtime. This is useful to disable if you're prerendering all your images.
765
+
766
+ ### `runtimeBrowser`
767
+
768
+ - Type: `boolean`
769
+ - Default: `process.dev`
554
770
 
555
- In a server runtime, the default behaviour is to generate images using Satori. If you'd like to generate runtime images using the a browser instance
556
- for screenshots, you can enable this setting.
771
+ Whether to use Playwright at runtime. You will need to enable this for production environments and ensure you are using
772
+ a supported nitro preset and have the required dependencies.
557
773
 
558
- This is experimental and may not work in all environments.
559
774
 
560
775
  ## Examples
561
776
 
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html >
3
3
  <head><meta charset="utf-8">
4
- <meta name="viewport" content="width=device-width, initial-scale=1"><link rel="modulepreload" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/entry.74018bda.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.7a8c1ab2.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-component.cf7543e5.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.7a8c1ab2.css"><script>"use strict";const w=window,de=document.documentElement,knownColorSchemes=["dark","light"],preference=window.localStorage.getItem("nuxt-color-mode")||"system";let value=preference==="system"?getColorScheme():preference;const forcedColorMode=de.getAttribute("data-color-mode-forced");forcedColorMode&&(value=forcedColorMode),addColorScheme(value),w["__NUXT_COLOR_MODE__"]={preference,value,getColorScheme,addColorScheme,removeColorScheme};function addColorScheme(e){const o=""+e+"",t="";de.classList?de.classList.add(o):de.className+=" "+o,t&&de.setAttribute("data-"+t,e)}function removeColorScheme(e){const o=""+e+"",t="";de.classList?de.classList.remove(o):de.className=de.className.replace(new RegExp(o,"g"),""),t&&de.removeAttribute("data-"+t)}function prefersColorScheme(e){return w.matchMedia("(prefers-color-scheme"+e+")")}function getColorScheme(){if(w.matchMedia&&prefersColorScheme("").media!=="not all"){for(const e of knownColorSchemes)if(prefersColorScheme(":"+e).matches)return e}return"light"}
4
+ <meta name="viewport" content="width=device-width, initial-scale=1"><link rel="modulepreload" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/entry.07d246ba.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.1311cc29.css"><link rel="prefetch" as="style" href="/__nuxt_og_image__/client/_nuxt/error-404.f3dd5020.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-404.23b0054d.js"><link rel="prefetch" as="style" href="/__nuxt_og_image__/client/_nuxt/error-500.06915589.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-500.6db75894.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.1311cc29.css"><script>"use strict";(()=>{const a=window,e=document.documentElement,m=["dark","light"],c=window.localStorage.getItem("nuxt-color-mode")||"system";let n=c==="system"?f():c;const l=e.getAttribute("data-color-mode-forced");l&&(n=l),i(n),a["__NUXT_COLOR_MODE__"]={preference:c,value:n,getColorScheme:f,addColorScheme:i,removeColorScheme:d};function i(o){const t=""+o+"",s="";e.classList?e.classList.add(t):e.className+=" "+t,s&&e.setAttribute("data-"+s,o)}function d(o){const t=""+o+"",s="";e.classList?e.classList.remove(t):e.className=e.className.replace(new RegExp(t,"g"),""),s&&e.removeAttribute("data-"+s)}function r(o){return a.matchMedia("(prefers-color-scheme"+o+")")}function f(){if(a.matchMedia&&r("").media!=="not all"){for(const o of m)if(r(":"+o).matches)return o}return"light"}})();
5
5
  </script></head>
6
- <body ><div id="__nuxt"></div><script>window.__NUXT__={serverRendered:false,config:{public:{},app:{baseURL:"\u002F__nuxt_og_image__\u002Fclient",buildAssetsDir:"\u002F_nuxt\u002F",cdnURL:""}},data:{},state:{}}</script><script type="module" src="/__nuxt_og_image__/client/_nuxt/entry.74018bda.js" crossorigin></script></body>
6
+ <body ><div id="__nuxt"><svg class="nuxt-spa-loading" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 25" fill="none" width="80"><path d="M24.236 22.006h10.742L25.563 5.822l-8.979 14.31a4 4 0 0 1-3.388 1.874H2.978l11.631-20 5.897 10.567"></path></svg><style>.nuxt-spa-loading{position:fixed;top:50%;left:50%;transform:translate(-50%, -50%)}.nuxt-spa-loading>path{fill:none;stroke:#00DC82;stroke-width:4px;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:128;stroke-dashoffset:128;animation:nuxt-spa-loading-move 3s linear infinite}@keyframes nuxt-spa-loading-move{100%{stroke-dashoffset:-128}}</style></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"_errors":1,"serverRendered":2,"data":3,"state":4},{},false,{},{}]</script><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt_og_image__/client",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="module" src="/__nuxt_og_image__/client/_nuxt/entry.07d246ba.js" crossorigin></script></body>
7
7
  </html>
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html >
3
3
  <head><meta charset="utf-8">
4
- <meta name="viewport" content="width=device-width, initial-scale=1"><link rel="modulepreload" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/entry.74018bda.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.7a8c1ab2.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-component.cf7543e5.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.7a8c1ab2.css"><script>"use strict";const w=window,de=document.documentElement,knownColorSchemes=["dark","light"],preference=window.localStorage.getItem("nuxt-color-mode")||"system";let value=preference==="system"?getColorScheme():preference;const forcedColorMode=de.getAttribute("data-color-mode-forced");forcedColorMode&&(value=forcedColorMode),addColorScheme(value),w["__NUXT_COLOR_MODE__"]={preference,value,getColorScheme,addColorScheme,removeColorScheme};function addColorScheme(e){const o=""+e+"",t="";de.classList?de.classList.add(o):de.className+=" "+o,t&&de.setAttribute("data-"+t,e)}function removeColorScheme(e){const o=""+e+"",t="";de.classList?de.classList.remove(o):de.className=de.className.replace(new RegExp(o,"g"),""),t&&de.removeAttribute("data-"+t)}function prefersColorScheme(e){return w.matchMedia("(prefers-color-scheme"+e+")")}function getColorScheme(){if(w.matchMedia&&prefersColorScheme("").media!=="not all"){for(const e of knownColorSchemes)if(prefersColorScheme(":"+e).matches)return e}return"light"}
4
+ <meta name="viewport" content="width=device-width, initial-scale=1"><link rel="modulepreload" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/entry.07d246ba.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.1311cc29.css"><link rel="prefetch" as="style" href="/__nuxt_og_image__/client/_nuxt/error-404.f3dd5020.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-404.23b0054d.js"><link rel="prefetch" as="style" href="/__nuxt_og_image__/client/_nuxt/error-500.06915589.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-500.6db75894.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.1311cc29.css"><script>"use strict";(()=>{const a=window,e=document.documentElement,m=["dark","light"],c=window.localStorage.getItem("nuxt-color-mode")||"system";let n=c==="system"?f():c;const l=e.getAttribute("data-color-mode-forced");l&&(n=l),i(n),a["__NUXT_COLOR_MODE__"]={preference:c,value:n,getColorScheme:f,addColorScheme:i,removeColorScheme:d};function i(o){const t=""+o+"",s="";e.classList?e.classList.add(t):e.className+=" "+t,s&&e.setAttribute("data-"+s,o)}function d(o){const t=""+o+"",s="";e.classList?e.classList.remove(t):e.className=e.className.replace(new RegExp(t,"g"),""),s&&e.removeAttribute("data-"+s)}function r(o){return a.matchMedia("(prefers-color-scheme"+o+")")}function f(){if(a.matchMedia&&r("").media!=="not all"){for(const o of m)if(r(":"+o).matches)return o}return"light"}})();
5
5
  </script></head>
6
- <body ><div id="__nuxt"></div><script>window.__NUXT__={serverRendered:false,config:{public:{},app:{baseURL:"\u002F__nuxt_og_image__\u002Fclient",buildAssetsDir:"\u002F_nuxt\u002F",cdnURL:""}},data:{},state:{}}</script><script type="module" src="/__nuxt_og_image__/client/_nuxt/entry.74018bda.js" crossorigin></script></body>
6
+ <body ><div id="__nuxt"><svg class="nuxt-spa-loading" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 37 25" fill="none" width="80"><path d="M24.236 22.006h10.742L25.563 5.822l-8.979 14.31a4 4 0 0 1-3.388 1.874H2.978l11.631-20 5.897 10.567"></path></svg><style>.nuxt-spa-loading{position:fixed;top:50%;left:50%;transform:translate(-50%, -50%)}.nuxt-spa-loading>path{fill:none;stroke:#00DC82;stroke-width:4px;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:128;stroke-dashoffset:128;animation:nuxt-spa-loading-move 3s linear infinite}@keyframes nuxt-spa-loading-move{100%{stroke-dashoffset:-128}}</style></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"_errors":1,"serverRendered":2,"data":3,"state":4},{},false,{},{}]</script><script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt_og_image__/client",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script><script type="module" src="/__nuxt_og_image__/client/_nuxt/entry.07d246ba.js" crossorigin></script></body>
7
7
  </html>
@@ -0,0 +1 @@
1
+ import{g as r,H as u,I as p,n as t,o as l,c as _,s as f,_ as m}from"./entry.07d246ba.js";const d=r({__name:"IconCSS",props:{name:{type:String,required:!0},size:{type:String,default:""}},setup(a){const s=a;u(e=>({"193e663e":i.value}));const n=p();n?.nuxtIcon?.aliases;const c=t(()=>(n?.nuxtIcon?.aliases||{})[s.name]||s.name),i=t(()=>`url('https://api.iconify.design/${c.value.replace(":","/")}.svg')`),o=t(()=>{if(!s.size&&typeof n.nuxtIcon?.size=="boolean"&&!n.nuxtIcon?.size)return;const e=s.size||n.nuxtIcon?.size||"1em";return String(Number(e))===e?`${e}px`:e});return(e,x)=>(l(),_("span",{style:f({width:o.value,height:o.value})},null,4))}});const g=m(d,[["__scopeId","data-v-1172c8f8"]]);export{g as default};
@@ -0,0 +1 @@
1
+ span[data-v-1172c8f8]{background-color:currentColor;display:inline-block;-webkit-mask-image:var(--193e663e);mask-image:var(--193e663e);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;vertical-align:middle}
@@ -0,0 +1 @@
1
+ img[data-v-23ec6856]{height:auto!important;margin:0 auto;max-width:100%;transition:.4s ease-in-out;width:auto!important}
@@ -0,0 +1 @@
1
+ import{g as p,r as c,k as m,l as r,n as u,q as d,o as g,c as f,s as y,_ as v}from"./entry.07d246ba.js";const x=p({__name:"ImageLoader",props:{src:String,aspectRatio:Number,description:String},setup(a){const s=a,n=c(),o=c(0);function i(e){const t=n.value,_=Date.now();t.src="",o.value=0,t.style.opacity="0",t.onload=()=>{t.style.opacity="1",o.value=Date.now()-_},t.src=e}m(()=>{r(()=>s.src,e=>{i(e)},{immediate:!0})});const l=u(()=>s.description.replace("%s",o.value.toString()));return r(l,e=>{d.value=e}),(e,t)=>(g(),f("img",{ref_key:"image",ref:n,class:"max-h-full border-1 border-light-500 rounded",style:y({aspectRatio:a.aspectRatio})},null,4))}});const S=v(x,[["__scopeId","data-v-23ec6856"]]);export{S as _};