nuxt-og-image 2.0.0-beta.6 → 2.0.0-beta.60

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 (114) hide show
  1. package/README.md +311 -97
  2. package/dist/client/200.html +2 -2
  3. package/dist/client/404.html +2 -2
  4. package/dist/client/_nuxt/IconCSS.b41b9663.css +1 -0
  5. package/dist/client/_nuxt/IconCSS.c2e73ab2.js +1 -0
  6. package/dist/client/_nuxt/ImageLoader.7571516f.css +1 -0
  7. package/dist/client/_nuxt/ImageLoader.ed4bfccb.js +1 -0
  8. package/dist/client/_nuxt/entry.862302d7.css +1 -0
  9. package/dist/client/_nuxt/entry.f51ac6f7.js +7 -0
  10. package/dist/client/_nuxt/{error-404.1ff52902.js → error-404.a94c6c21.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.3955092a.js} +1 -1
  14. package/dist/client/_nuxt/index.17db8b1a.js +1 -0
  15. package/dist/client/_nuxt/index.403133d8.css +1 -0
  16. package/dist/client/_nuxt/options.3e6c211b.js +1 -0
  17. package/dist/client/_nuxt/png.23a5e57c.js +1 -0
  18. package/dist/client/_nuxt/{shiki.3a930bb8.js → shiki.2980d306.js} +1 -1
  19. package/dist/client/_nuxt/svg.a8bba1f1.js +1 -0
  20. package/dist/client/_nuxt/{vnodes.a799f183.js → vnodes.64d635d6.js} +1 -1
  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 +401 -141
  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 -3
  32. package/dist/runtime/components/OgImage/Cached.mjs +10 -0
  33. package/dist/runtime/components/{OgImageScreenshot.d.ts → OgImage/Screenshot.d.ts} +2 -4
  34. package/dist/runtime/components/{OgImageScreenshot.mjs → OgImage/Screenshot.mjs} +2 -2
  35. package/dist/runtime/components/{OgImageStatic.d.ts → OgImage/WithoutCache.d.ts} +2 -3
  36. package/dist/runtime/components/OgImage/WithoutCache.mjs +10 -0
  37. package/dist/runtime/components/OgImage/_OgImageDynamic.d.ts +7 -0
  38. package/dist/runtime/components/{OgImageDynamic.mjs → OgImage/_OgImageDynamic.mjs} +3 -3
  39. package/dist/runtime/components/OgImage/_OgImageStatic.d.ts +7 -0
  40. package/dist/runtime/components/{OgImageStatic.mjs → OgImage/_OgImageStatic.mjs} +3 -3
  41. package/dist/runtime/components/OgImage/index.d.ts +4 -0
  42. package/dist/runtime/components/OgImage/index.mjs +9 -0
  43. package/dist/runtime/components/OgImageTemplate/Fallback.vue +155 -0
  44. package/dist/runtime/composables/defineOgImage.d.ts +12 -4
  45. package/dist/runtime/composables/defineOgImage.mjs +46 -20
  46. package/dist/runtime/nitro/middleware/og.png.mjs +54 -8
  47. package/dist/runtime/nitro/middleware/playground.mjs +4 -3
  48. package/dist/runtime/nitro/plugins/prerender.d.ts +3 -0
  49. package/dist/runtime/nitro/plugins/prerender.mjs +28 -0
  50. package/dist/runtime/nitro/providers/browser/lambda.d.ts +1 -1
  51. package/dist/runtime/nitro/providers/browser/lambda.mjs +3 -3
  52. package/dist/runtime/nitro/providers/browser/{node.mjs → playwright.mjs} +0 -9
  53. package/dist/runtime/nitro/providers/browser/universal.d.ts +1 -0
  54. package/dist/runtime/nitro/providers/browser/universal.mjs +33 -0
  55. package/dist/runtime/nitro/providers/png/resvg-node.d.ts +4 -0
  56. package/dist/runtime/nitro/providers/png/resvg-node.mjs +6 -0
  57. package/dist/runtime/nitro/providers/png/resvg-wasm.d.ts +3 -0
  58. package/dist/runtime/nitro/providers/png/resvg-wasm.mjs +11 -0
  59. package/dist/runtime/nitro/providers/{svg2png/universal.d.ts → png/svg2png.d.ts} +2 -3
  60. package/dist/runtime/nitro/providers/png/svg2png.mjs +11 -0
  61. package/dist/runtime/nitro/providers/satori/{webworker.d.ts → yoga-wasm.d.ts} +2 -3
  62. package/dist/runtime/nitro/providers/satori/{webworker.mjs → yoga-wasm.mjs} +4 -5
  63. package/dist/runtime/nitro/renderers/browser.d.ts +2 -2
  64. package/dist/runtime/nitro/renderers/browser.mjs +14 -10
  65. package/dist/runtime/nitro/renderers/satori/index.d.ts +2 -2
  66. package/dist/runtime/nitro/renderers/satori/index.mjs +27 -32
  67. package/dist/runtime/nitro/renderers/satori/plugins/emojis.d.ts +1 -1
  68. package/dist/runtime/nitro/renderers/satori/plugins/emojis.mjs +19 -6
  69. package/dist/runtime/nitro/renderers/satori/plugins/encoding.d.ts +1 -1
  70. package/dist/runtime/nitro/renderers/satori/plugins/encoding.mjs +6 -7
  71. package/dist/runtime/nitro/renderers/satori/plugins/flex.d.ts +1 -1
  72. package/dist/runtime/nitro/renderers/satori/plugins/flex.mjs +8 -10
  73. package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.d.ts +1 -1
  74. package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.mjs +45 -13
  75. package/dist/runtime/nitro/renderers/satori/plugins/twClasses.d.ts +1 -1
  76. package/dist/runtime/nitro/renderers/satori/plugins/twClasses.mjs +5 -7
  77. package/dist/runtime/nitro/renderers/satori/utils.d.ts +4 -5
  78. package/dist/runtime/nitro/renderers/satori/utils.mjs +28 -17
  79. package/dist/runtime/nitro/routes/debug.d.ts +8 -0
  80. package/dist/runtime/nitro/routes/debug.mjs +14 -0
  81. package/dist/runtime/nitro/routes/font.mjs +2 -2
  82. package/dist/runtime/nitro/routes/html.mjs +100 -25
  83. package/dist/runtime/nitro/routes/options.d.ts +2 -2
  84. package/dist/runtime/nitro/routes/options.mjs +25 -22
  85. package/dist/runtime/nitro/routes/svg.mjs +5 -3
  86. package/dist/runtime/nitro/routes/vnode.mjs +5 -3
  87. package/dist/runtime/nitro/utils-pure.d.ts +3 -2
  88. package/dist/runtime/nitro/utils-pure.mjs +9 -10
  89. package/dist/runtime/nitro/utils.d.ts +11 -11
  90. package/dist/runtime/nitro/utils.mjs +68 -54
  91. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  92. package/dist/runtime/public-assets-optional/resvg/resvg.wasm +0 -0
  93. package/dist/types.d.ts +6 -0
  94. package/package.json +38 -27
  95. package/dist/client/_nuxt/IconCSS.a041aca0.js +0 -1
  96. package/dist/client/_nuxt/ImageLoader.9bf39d71.js +0 -1
  97. package/dist/client/_nuxt/entry.74018bda.js +0 -5
  98. package/dist/client/_nuxt/entry.7a8c1ab2.css +0 -1
  99. package/dist/client/_nuxt/error-404.1469f10f.css +0 -1
  100. package/dist/client/_nuxt/error-500.92b94fae.css +0 -1
  101. package/dist/client/_nuxt/error-component.cf7543e5.js +0 -3
  102. package/dist/client/_nuxt/index.3f356409.js +0 -1
  103. package/dist/client/_nuxt/options.56a3e5f9.js +0 -1
  104. package/dist/client/_nuxt/png.37f3e77b.js +0 -1
  105. package/dist/client/_nuxt/svg.186c6bd1.js +0 -1
  106. package/dist/runtime/components/OgImageBasic.island.vue +0 -92
  107. package/dist/runtime/nitro/providers/svg2png/universal.mjs +0 -9
  108. /package/dist/runtime/nitro/providers/browser/{node.d.ts → playwright.d.ts} +0 -0
  109. /package/dist/runtime/nitro/providers/satori/{node.d.ts → default.d.ts} +0 -0
  110. /package/dist/runtime/nitro/providers/satori/{node.mjs → default.mjs} +0 -0
  111. /package/dist/runtime/{public-assets → public-assets-optional/inter-font}/inter-latin-ext-400-normal.woff +0 -0
  112. /package/dist/runtime/{public-assets → public-assets-optional/inter-font}/inter-latin-ext-700-normal.woff +0 -0
  113. /package/dist/runtime/{public-assets → public-assets-optional/svg2png}/svg2png.wasm +0 -0
  114. /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
 
@@ -46,13 +46,33 @@ Enlightened OG Image generation for Nuxt 3.
46
46
  - [StackBlitz - Minimal Playground Example](https://stackblitz.com/edit/nuxt-starter-pxs3wk?file=pages/index.vue)
47
47
  - [StackBlitz - Alpine Theme](https://stackblitz.com/edit/github-hgunsf?file=package.json)
48
48
 
49
+ ## Runtime Provider Compatibility
50
+
51
+ Both Satori and Browser will work in Node based environments. Prerendering is fully supported.
52
+
53
+ When you want to generate dynamic images at runtime there are certain Nitro runtime limitations.
54
+
55
+ | Provider | Satori | Browser |
56
+ |---------------------------------------------------------------------------------|-----------------------|---------|
57
+ | Node | ✅ | ✅ |
58
+ | [Vercel](https://nuxt-og-image-playground.vercel.app/) | ✅ | ❌ |
59
+ | [Vercel Edge](https://nuxt-og-image-playground-gkdt.vercel.app/) | ✅ | ❌ |
60
+ | [Cloudflare Pages](https://nuxt-og-image-playground.pages.dev/) | ✅ | ❌ |
61
+ | [Netlify](https://nuxt-og-image-playground-netlify.netlify.app/) | ✅ | ❌ |
62
+ | [Netlify Edge](https://nuxt-og-image-playground-netlify-edge.netlify.app/) | (Soon) | ❌ |
63
+ | [StackBlitz](https://stackblitz.com/edit/nuxt-starter-pxs3wk?file=package.json) | ✅ (emojis don't work) | ❌ |
64
+
65
+ Other providers are yet to be tested. Please create an issue if your nitro preset is not listed.
66
+
49
67
  ## Install
50
68
 
69
+ Note: The `main` branch is documentation for the beta version, it's recommended to use this version.
70
+
51
71
  ```bash
52
72
  # Install module
53
- npm install --save-dev nuxt-og-image
73
+ npm install --save-dev nuxt-og-image@beta
54
74
  # Using yarn
55
- yarn add --dev nuxt-og-image
75
+ yarn add --dev nuxt-og-image@beta
56
76
  ```
57
77
 
58
78
  ## Setup
@@ -67,30 +87,8 @@ export default defineNuxtConfig({
67
87
  })
68
88
  ```
69
89
 
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
- ```
90
+ This module requires [Nuxt Server Components](https://nuxt.com/docs/guide/directory-structure/components#standalone-server-components)
91
+ which will be enabled for you.
94
92
 
95
93
  # Guides
96
94
 
@@ -98,31 +96,31 @@ export default defineNuxtConfig({
98
96
 
99
97
  For this guide, you will create your Satori OG image using the default component for your home page.
100
98
 
101
- ### 1. Define a static OG Image
102
-
103
- Within your `pages/index.vue`, use `defineOgImageStatic` or `OgImageStatic` to define your `og:image` component.
99
+ ### 1. Define an OG Image
104
100
 
105
- Make sure you have defined some metadata as props will be inferred from it.
101
+ Within your `pages/index.vue`, use `defineOgImage()` or `<OgImage />` to define your `og:image` component.
106
102
 
107
103
  ```vue
108
104
  <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()
105
+ const ogImageOptions = {
106
+ title: 'My awesome home page.',
107
+ }
108
+ // a. Use the Composition API
109
+ defineOgImage(ogImageOptions)
116
110
  </script>
117
111
 
118
112
  <template>
119
113
  <div>
120
- <!-- 2b. OR Component API -->
121
- <OgImageStatic />
114
+ <!-- b. OR Component API -->
115
+ <OgImage v-bind="ogImageOptions" />
122
116
  </div>
123
117
  </template>
124
118
  ```
125
119
 
120
+ This will use the default template [OgImageBasic](./src/runtime/components/OgImageBasic.island.vue),
121
+ provided by this module.
122
+
123
+
126
124
  ### 2. View your `og:image`
127
125
 
128
126
  Appending `/__og_image__` to the end of the URL will show you the playground for that pages `og:image`. This provides
@@ -132,54 +130,58 @@ For example, if your local site is hosted at `http://localhost:3000`, you can vi
132
130
 
133
131
  ### 3. Customize your `og:image`
134
132
 
135
- While you have the playground open, start customising the OG Image by providing options to the `defineOgImageStatic` function.
136
-
137
- ```vue
138
- <script lang="ts" setup>
139
- defineOgImageStatic({
140
- title: 'Welcome to my site!',
141
- background: 'lightblue'
142
- })
143
- </script>
144
- ```
133
+ While you have the playground open, start customizing the OG Image by modifying the `ogImageOptions`.
134
+ Full HMR is supported, so you should see your changes instantly.
145
135
 
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.
136
+ Congrats, you've set up your first Satori `og:image`!
137
+ You can check out the [options](./src/runtime/components/OgImageBasic.island.vue) of the default template.
147
138
 
148
139
  ## Making your own Satori template
149
140
 
150
141
  Templates for OG images are powered by Nuxt Islands, which are just Vue components. In this guide we'll create a new
151
142
  template and use it for our `og:image`.
152
143
 
153
- ### 1. Create an island component
154
-
155
- Make a folder in your components directory called `islands`.
144
+ ### 1. Create your template component
156
145
 
157
- Within this directory make a new component called `MyOgImage.vue`,
158
- you can use the following template to begin:
146
+ Make a new file at the path `./components/OgImage/Default.vue` with the following contents:
159
147
 
160
148
  ```vue
161
149
  <script setup lang="ts">
162
150
  const props = defineProps({
163
151
  title: String,
164
152
  })
153
+
154
+ // inherited attrs can mess up the satori parser
155
+ defineOptions({
156
+ inheritAttrs: false,
157
+ })
165
158
  </script>
166
159
 
167
160
  <template>
168
161
  <div class="w-full h-full flex text-white bg-blue-500 items-center justify-center">
169
- <h1 :style="{ fontSize: '70px' }">
162
+ <h1>
170
163
  {{ title }} 👋
171
164
  </h1>
172
165
  </div>
173
166
  </template>
167
+ <style scoped>
168
+ h1 {
169
+ font-size: 70px;
170
+ }
171
+ </style>
174
172
  ```
175
173
 
174
+ The convention is to use either the `OgImage` or `OgImageTemplate` folders within `components`.
175
+
176
+ See [componentDirs](#component-dirs) if you prefer to use a different named directory.
177
+
176
178
  ### 2. Use the new template
177
179
 
178
- Now that you have your template, you can use it in for your `defineOgImageStatic` function.
180
+ Now that you have your template, you can use it in for your `defineOgImage` composable.
179
181
 
180
182
  ```vue
181
183
  <script lang="ts" setup>
182
- defineOgImageStatic({
184
+ defineOgImage({
183
185
  component: 'MyOgImage',
184
186
  title: 'Welcome to my site!'
185
187
  })
@@ -192,7 +194,7 @@ View this image in your browser by appending `/__og_image__` to the end of the U
192
194
 
193
195
  Now that you have your template, you can start customizing it.
194
196
 
195
- Any options you pass to the `defineOgImageStatic` composable will be available in the component. With this in mind, we can
197
+ Any options you pass to the `defineOgImage` composable will be available in the component. With this in mind, we can
196
198
  add support for changing the background color.
197
199
 
198
200
  ```vue
@@ -205,18 +207,23 @@ const props = defineProps({
205
207
 
206
208
  <template>
207
209
  <div :class="[backgroundColor]" class="w-full h-full flex text-white items-center justify-center">
208
- <h1 :style="{ fontSize: '70px' }">
210
+ <h1>
209
211
  {{ title }} 👋
210
212
  </h1>
211
213
  </div>
212
214
  </template>
215
+ <style scoped>
216
+ h1 {
217
+ font-size: 70px;
218
+ }
219
+ </style>
213
220
  ```
214
221
 
215
- Now let's customise the background to be green instead.
222
+ Now let's customize the background to be green instead.
216
223
 
217
224
  ```vue
218
225
  <script lang="ts" setup>
219
- defineOgImageStatic({
226
+ defineOgImage({
220
227
  component: 'MyOgImage',
221
228
  title: 'Welcome to my site!',
222
229
  backgroundColor: 'bg-green-500'
@@ -241,6 +248,86 @@ Out of the box, this module provides support for the following:
241
248
 
242
249
  If you find Satori is too limiting for your needs, you can always use the `browser` provider to capture browser screenshots instead.
243
250
 
251
+
252
+ ## Bypassing cache
253
+
254
+ Caching og images is enabled by default, if you need to generate dynamically at runtime,
255
+ you can modify the use the `defineOgImageWithoutCache(options)` composable or `<OgImageWithoutCache v-bind="options" />` component.
256
+
257
+ This mode is not compatible with `nuxt generate`.
258
+
259
+ ## SSG Images
260
+
261
+ When using `nuxt generate`, you will need to provide some additional configuration.
262
+
263
+ - You must provide a `siteUrl` so that the meta tags can be generated correctly as absolute URLs.
264
+
265
+ ```ts
266
+ export default defineNuxtConfig({
267
+ // Recommended
268
+ runtimeConfig: {
269
+ public: {
270
+ siteUrl: process.env.NUXT_PUBLIC_SITE_URL || 'https://example.com',
271
+ }
272
+ },
273
+ // OR
274
+ ogImage: {
275
+ host: 'https://example.com',
276
+ },
277
+ })
278
+ ```
279
+
280
+ - You must prerender all pages that use `og:image`.
281
+
282
+ ```ts
283
+ export default defineNuxtConfig({
284
+ nitro: {
285
+ prerender: {
286
+ crawlLinks: true, // recommended
287
+ routes: [
288
+ '/',
289
+ // list all routes that use og:image if you're not using crawlLinks
290
+ '/about',
291
+ '/blog',
292
+ '/blog/my-first-post',
293
+ ]
294
+ }
295
+ }
296
+ })
297
+ ```
298
+
299
+ ## SSR Images
300
+
301
+ When using `nuxt build`, you can only use the `browser` provider with the `node` Nitro preset.
302
+
303
+ If you intend to use the `browser` provider in production, make sure you include the `playwright` dependency.
304
+
305
+ ```bash
306
+ npm i playwright
307
+ ```
308
+
309
+ You can get around this by prerendering any pages that use `og:image`. Note that dynamic browser generated images are not supported at all,
310
+ you should use the Satori provider.
311
+
312
+
313
+ ```ts
314
+ export default defineNuxtConfig({
315
+ nitro: {
316
+ prerender: {
317
+ crawlLinks: true, // recommended
318
+ routes: [
319
+ '/',
320
+ // list all routes that use og:image if you're not using crawlLinks
321
+ '/about',
322
+ '/blog',
323
+ '/blog/my-first-post',
324
+ ]
325
+ }
326
+ }
327
+ })
328
+ ```
329
+
330
+
244
331
  ## Taking screenshots
245
332
 
246
333
  If you want to simply take a screenshot of your page, you can use the `OgImageScreenshot` component or `defineOgImageScreenshot` composable.
@@ -251,11 +338,11 @@ defineOgImageScreenshot()
251
338
  </script>
252
339
  ```
253
340
 
254
- Alternatively you can pass the `{ provider: 'browser' }` option to `defineOgImageStatic`.
341
+ Alternatively you can pass the `{ provider: 'browser' }` option to `defineOgImage`.
255
342
 
256
343
  ```vue
257
344
  <script lang="ts" setup>
258
- defineOgImageStatic({
345
+ defineOgImage({
259
346
  component: 'MyAwesomeOgImage',
260
347
  // this will take a browser screenshot
261
348
  provider: 'browser'
@@ -282,15 +369,144 @@ _package.json_
282
369
  }
283
370
  ```
284
371
 
372
+ ## Custom Fonts / Supporting non-english characters
373
+
374
+ When creating your OG Image, you'll probably want to use a font custom to your project.
375
+
376
+ To make this easier for you, Google Fonts are loaded by default with Inter 400 and Inter 700.
377
+
378
+ You can easily load different Google Fonts by using their name+weight. For example:
379
+
380
+ ```ts
381
+ export default defineNuxtConfig({
382
+ ogImage: {
383
+ fonts: [
384
+ // will load the Noto Sans font from Google fonts
385
+ 'Noto+Sans:400'
386
+ ]
387
+ }
388
+ })
389
+ ```
390
+
391
+ This also lets you support non-english characters by adding the appropriate font to your config.
392
+
393
+ For example, to support Hebrew characters, you can use the config:
394
+
395
+ ```ts
396
+ export default defineNuxtConfig({
397
+ ogImage: {
398
+ fonts: [
399
+ // will load this font from Google fonts
400
+ 'Noto+Sans+Hebrew:400'
401
+ ]
402
+ }
403
+ })
404
+ ````
405
+
406
+ If you'd like to load a font locally,
407
+ then you can provide the configuration as an object:
408
+
409
+ ```ts
410
+ export default defineNuxtConfig({
411
+ ogImage: {
412
+ fonts: [
413
+ {
414
+ name: 'optieinstein',
415
+ weight: 800,
416
+ // path must point to a public font file
417
+ path: '/OPTIEinstein-Black.otf',
418
+ }
419
+ ],
420
+ }
421
+ })
422
+ ```
423
+
424
+ Make sure to set the font family in your component to match the font name.
425
+
426
+ ```vue
427
+ <template>
428
+ <div :style="{ fontFamily: 'optieinstein' }">
429
+ <!-- Your component -->
430
+ </div>
431
+ </template>
432
+ ```
433
+
434
+ ## Runtime Caching
435
+
436
+ When images are generated at runtime, caching is enabled by default to reduce the load on your server.
437
+
438
+ By default, it will use the default storage engine for your Nitro preset.
439
+ You can customise the storage engine by providing a `runtimeCacheStorage` option to the `ogImage` config.
440
+
441
+ The option takes the same configuration as the Nuxt `nitro.storage` option.
442
+ See the [Nitro Storage Layer](https://nitro.unjs.io/guide/storage) documentation for more details.
443
+
444
+ For example:
445
+
446
+ ```ts
447
+ export default defineNuxtConfig({
448
+ ogImage: {
449
+ // cloudflare kv binding example, set your own config
450
+ runtimeCacheStorage: {
451
+ driver: 'cloudflare-kv-binding',
452
+ binding: 'OG_IMAGE_CACHE'
453
+ }
454
+ }
455
+ })
456
+ ````
457
+
458
+ By default, static images will be cached for 24 hours. You can change the image TTL by providing `cacheTtl` when defining the image.
459
+
460
+ ```ts
461
+ defineOgImage({
462
+ // ...
463
+ cacheTtl: 60 * 60 * 24 * 7 // 7 days
464
+ })
465
+ ```
466
+
467
+ Alternatively, you can change the default cacheTtl time in your nuxt.config.
468
+
469
+
470
+ ```ts
471
+ export default defineNuxtConfig({
472
+ ogImage: {
473
+ defaults: {
474
+ cacheTtl: 60 * 60 * 24 * 7 // 7 days
475
+ }
476
+ }
477
+ })
478
+ ````
479
+
480
+ You can also provide a configuration for the `cacheKey`. This gives you control over the cache bursting of the images.
481
+
482
+ ```vue
483
+ <script lang="ts" setup>
484
+ defineOgImage({
485
+ cacheKey: `${myData.id}:${myData.updatedAt}`,
486
+ })
487
+ </script>
488
+ ```
489
+
490
+ If you prefer not to cache your images you can always disable them by providing a `false` value.
491
+
492
+ ```ts
493
+ export default defineNuxtConfig({
494
+ ogImage: {
495
+ // no runtime cache
496
+ runtimeCacheStorage: false
497
+ }
498
+ })
499
+ ````
500
+
285
501
  # API
286
502
 
287
503
  The module exposes a composition and component API to implement your `og:image` generation. You should pick
288
504
  whichever one you prefer using.
289
505
 
290
- ## OgImageStatic / defineOgImageStatic
506
+ ## OgImage / defineOgImage
291
507
 
292
- The `OgImageStatic` component and the `defineOgImageStatic` composable creates a static image
293
- that will be pre-rendered.
508
+ The `OgImage` component and the `defineOgImage` composable creates a static image
509
+ that will be prerendered.
294
510
 
295
511
  The options follow the [OgImageOptions](#OgImageOptions) interface,
296
512
  any additional options will be passed to the `component` as props.
@@ -302,7 +518,7 @@ It is useful for images that do not change at runtime.
302
518
  ```vue
303
519
  <script setup lang="ts">
304
520
  // a. Composition API
305
- defineOgImageStatic({
521
+ defineOgImage({
306
522
  component: 'MyOgImageTemplate',
307
523
  title: 'Hello world',
308
524
  theme: 'dark'
@@ -311,7 +527,7 @@ defineOgImageStatic({
311
527
 
312
528
  <template>
313
529
  <!-- b. Component API -->
314
- <OgImageStatic
530
+ <OgImage
315
531
  component="MyOgImageTemplate"
316
532
  title="Hello world"
317
533
  theme="dark"
@@ -320,9 +536,9 @@ defineOgImageStatic({
320
536
  ```
321
537
 
322
538
 
323
- ## OgImageDynamic / defineOgImageDynamic
539
+ ## OgImageWithoutCache / defineOgImageWithoutCache
324
540
 
325
- The `OgImageDynamic` component and the `defineOgImageDynamic` composable creates a dynamic image. They are not pre-rendered and will
541
+ The `OgImageWithoutCache` component and the `defineOgImageWithoutCache` composable creates a dynamic image. They are not prerendered and will
326
542
  be generated at runtime.
327
543
 
328
544
  The options follow the [OgImageOptions](#OgImageOptions) interface,
@@ -337,19 +553,19 @@ This feature is not compatible with static sites built using `nuxi generate`.
337
553
  const dynamicData = await fetch('https://example.com/api')
338
554
 
339
555
  // a. Composition API
340
- defineOgImageDynamic({
556
+ defineOgImageWithoutCache({
341
557
  component: 'MyOgImageTemplate',
342
558
  title: 'Hello world',
343
- dynamicData,
559
+ ...dynamicData,
344
560
  })
345
561
  </script>
346
562
 
347
563
  <template>
348
564
  <!-- b. Component API -->
349
- <OgImageDynamic
565
+ <OgImageWithoutCache
350
566
  component="MyOgImageTemplate"
351
567
  title="Hello world"
352
- :dynamic-data="dynamicData"
568
+ v-bind="dynamicData"
353
569
  />
354
570
  </template>
355
571
  ```
@@ -396,12 +612,14 @@ The name of the component to use as the template. By default, it uses OgImageBas
396
612
  - Required: `false`
397
613
 
398
614
  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.
615
+ When you use `browser` it will use Playwright to generate the image.
400
616
 
401
- ### `prerender`
617
+ ### `cache`
402
618
 
403
619
  - Type: `boolean`
404
- - Default: `true` when static, `false` when dynamic
620
+ - Default: `true` when using `defineOgImage`, `false` when dynamic
621
+
622
+ Controls the prerendering of the image. A non-static image is one that will be generated at runtime and not cached.
405
623
 
406
624
 
407
625
  ## OgImageScreenshot / defineOgImageScreenshot
@@ -495,13 +713,13 @@ defineOgImageScreenshot({
495
713
 
496
714
  ## Module Config
497
715
 
498
- ### `host`
716
+ ### `siteUrl`
499
717
 
500
718
  - Type: `string`
501
719
  - Default: `undefined`
502
720
  - Required: `true`
503
721
 
504
- The host of your site. This is required to generate the absolute path of the `og:image`.
722
+ The site URL of your site. This is required when prerendering to generate the absolute path of the `og:image`.
505
723
 
506
724
  ### `defaults`
507
725
 
@@ -511,15 +729,6 @@ The host of your site. This is required to generate the absolute path of the `og
511
729
 
512
730
  The default options to use when generating images.
513
731
 
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
732
  ### `fonts`
524
733
 
525
734
  - Type: ``${string}:${number}`[]`
@@ -546,16 +755,21 @@ export default defineNuxtConfig({
546
755
 
547
756
  Options to pass to Satori when generating images. See the [Satori docs](https://github.com/vercel/satori).
548
757
 
549
- ### `experimentalNitroBrowser` (experimental)
758
+ ### `runtimeSatori`
550
759
 
551
760
  - Type: `boolean`
552
- - Default: `false`
553
- - Required: `false`
761
+ - Default: `true`
762
+
763
+ Whether to use Satori at runtime. This is useful to disable if you're prerendering all your images.
764
+
765
+ ### `runtimeBrowser`
766
+
767
+ - Type: `boolean`
768
+ - Default: `process.dev`
554
769
 
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.
770
+ Whether to use Playwright at runtime. You will need to enable this for production environments and ensure you are using
771
+ a supported nitro preset and have the required dependencies.
557
772
 
558
- This is experimental and may not work in all environments.
559
773
 
560
774
  ## Examples
561
775
 
@@ -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.f51ac6f7.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.862302d7.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.a94c6c21.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.3955092a.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.862302d7.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.f51ac6f7.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.f51ac6f7.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.862302d7.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.a94c6c21.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.3955092a.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.862302d7.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.f51ac6f7.js" crossorigin></script></body>
7
7
  </html>
@@ -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
+ import{g as r,G as u,H as p,m as t,o as l,c as _,q as m,_ as f}from"./entry.f51ac6f7.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:m({width:o.value,height:o.value})},null,4))}});const g=f(d,[["__scopeId","data-v-1172c8f8"]]);export{g as default};
@@ -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}