nuxt-og-image 3.0.0-beta.34 → 3.0.0-beta.36

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 (32) hide show
  1. package/dist/client/200.html +4 -4
  2. package/dist/client/404.html +4 -4
  3. package/dist/client/_nuxt/{IconCSS.554c71bf.js → IconCSS.45c66412.js} +1 -1
  4. package/dist/client/_nuxt/builds/latest.json +1 -1
  5. package/dist/client/_nuxt/builds/meta/5fe7e1a4-29eb-4b04-a44b-168ee98c91a6.json +1 -0
  6. package/dist/client/_nuxt/{entry.2fa3fdbe.js → entry.e67f1456.js} +3 -3
  7. package/dist/client/_nuxt/{error-404.1d509bc2.js → error-404.374ebaaf.js} +1 -1
  8. package/dist/client/_nuxt/{error-500.399895ac.js → error-500.07f448c5.js} +1 -1
  9. package/dist/client/index.html +4 -4
  10. package/dist/module.d.mts +1 -0
  11. package/dist/module.d.ts +1 -0
  12. package/dist/module.json +1 -1
  13. package/dist/module.mjs +23 -8
  14. package/dist/runtime/components/Templates/Community/NuxtSeo.vue +4 -4
  15. package/dist/runtime/composables/defineOgImageScreenshot.mjs +1 -1
  16. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  17. package/dist/runtime/core/cache/prerender.mjs +1 -1
  18. package/dist/runtime/core/env/assets.d.ts +0 -1
  19. package/dist/runtime/core/env/assets.mjs +0 -4
  20. package/dist/runtime/core/font/fetch.mjs +13 -10
  21. package/dist/runtime/core/renderers/chromium/screenshot.mjs +4 -5
  22. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +21 -12
  23. package/dist/runtime/core/utils/resolveRendererContext.mjs +8 -16
  24. package/dist/runtime/nitro/plugins/prerender.mjs +8 -8
  25. package/dist/runtime/nitro/utils.d.ts +2 -0
  26. package/dist/runtime/nitro/utils.mjs +17 -0
  27. package/dist/runtime/types.d.ts +1 -0
  28. package/package.json +4 -4
  29. package/dist/client/_nuxt/builds/meta/ca5f9e65-b8d1-42b5-96f6-21ca72c45b74.json +0 -1
  30. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  31. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
  32. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
@@ -1 +1 @@
1
- import{_ as a,u as n,o as r,c as l,a as e,t as s,b as d,w as c,d as p,e as f,p as x,f as h}from"./entry.2fa3fdbe.js";const m=t=>(x("data-v-05a2b8a3"),t=t(),h(),t),u={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},g=m(()=>e("div",{class:"fixed left-0 right-0 spotlight z-10"},null,-1)),b={class:"max-w-520px text-center z-20"},_=["textContent"],w=["textContent"],y={class:"w-full flex items-center justify-center"},S={__name:"error-404",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:404},statusMessage:{type:String,default:"Not Found"},description:{type:String,default:"Sorry, the page you are looking for could not be found."},backHome:{type:String,default:"Go back home"}},setup(t){const o=t;return n({title:`${o.statusCode} - ${o.statusMessage} | ${o.appName}`,script:[],style:[{children:'*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}a{color:inherit;text-decoration:inherit}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}'}]}),(k,v)=>{const i=f;return r(),l("div",u,[g,e("div",b,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,_),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:s(t.description)},null,8,w),e("div",y,[d(i,{to:"/",class:"gradient-border text-md sm:text-xl py-2 px-4 sm:py-3 sm:px-6 cursor-pointer"},{default:c(()=>[p(s(t.backHome),1)]),_:1})])])])}}},z=a(S,[["__scopeId","data-v-05a2b8a3"]]);export{z as default};
1
+ import{_ as a,u as n,o as r,c as l,a as e,t as s,b as d,w as c,d as p,e as f,p as x,f as h}from"./entry.e67f1456.js";const m=t=>(x("data-v-05a2b8a3"),t=t(),h(),t),u={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},g=m(()=>e("div",{class:"fixed left-0 right-0 spotlight z-10"},null,-1)),b={class:"max-w-520px text-center z-20"},_=["textContent"],w=["textContent"],y={class:"w-full flex items-center justify-center"},S={__name:"error-404",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:404},statusMessage:{type:String,default:"Not Found"},description:{type:String,default:"Sorry, the page you are looking for could not be found."},backHome:{type:String,default:"Go back home"}},setup(t){const o=t;return n({title:`${o.statusCode} - ${o.statusMessage} | ${o.appName}`,script:[],style:[{children:'*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}a{color:inherit;text-decoration:inherit}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}'}]}),(k,v)=>{const i=f;return r(),l("div",u,[g,e("div",b,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,_),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:s(t.description)},null,8,w),e("div",y,[d(i,{to:"/",class:"gradient-border text-md sm:text-xl py-2 px-4 sm:py-3 sm:px-6 cursor-pointer"},{default:c(()=>[p(s(t.backHome),1)]),_:1})])])])}}},z=a(S,[["__scopeId","data-v-05a2b8a3"]]);export{z as default};
@@ -1 +1 @@
1
- import{_ as i,u as a,o as r,c as n,a as e,t as s,p as l,f as d}from"./entry.2fa3fdbe.js";const c=t=>(l("data-v-c967d9a9"),t=t(),d(),t),p={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},h=c(()=>e("div",{class:"fixed -bottom-1/2 left-0 right-0 h-1/2 spotlight"},null,-1)),f={class:"max-w-520px text-center"},g=["textContent"],m=["textContent"],x={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:500},statusMessage:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const o=t;return a({title:`${o.statusCode} - ${o.statusMessage} | ${o.appName}`,script:[],style:[{children:'*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}'}]}),(u,b)=>(r(),n("div",p,[h,e("div",f,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,g),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:s(t.description)},null,8,m)])]))}},w=i(x,[["__scopeId","data-v-c967d9a9"]]);export{w as default};
1
+ import{_ as i,u as a,o as r,c as n,a as e,t as s,p as l,f as d}from"./entry.e67f1456.js";const c=t=>(l("data-v-c967d9a9"),t=t(),d(),t),p={class:"font-sans antialiased bg-white dark:bg-black text-black dark:text-white grid min-h-screen place-content-center overflow-hidden"},h=c(()=>e("div",{class:"fixed -bottom-1/2 left-0 right-0 h-1/2 spotlight"},null,-1)),f={class:"max-w-520px text-center"},g=["textContent"],m=["textContent"],x={__name:"error-500",props:{appName:{type:String,default:"Nuxt"},version:{type:String,default:""},statusCode:{type:Number,default:500},statusMessage:{type:String,default:"Server error"},description:{type:String,default:"This page is temporarily unavailable."}},setup(t){const o=t;return a({title:`${o.statusCode} - ${o.statusMessage} | ${o.appName}`,script:[],style:[{children:'*,:before,:after{-webkit-box-sizing:border-box;box-sizing:border-box;border-width:0;border-style:solid;border-color:#e0e0e0}*{--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(14, 165, 233, .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000}:root{-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{margin:0;font-family:inherit;line-height:inherit}html{-webkit-text-size-adjust:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";line-height:1.5}h1,p{margin:0}h1{font-size:inherit;font-weight:inherit}'}]}),(u,b)=>(r(),n("div",p,[h,e("div",f,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,g),e("p",{class:"text-xl px-8 sm:px-0 sm:text-4xl font-light mb-16 leading-tight",textContent:s(t.description)},null,8,m)])]))}},w=i(x,[["__scopeId","data-v-c967d9a9"]]);export{w as default};
@@ -3,12 +3,12 @@
3
3
  <head><meta charset="utf-8">
4
4
  <meta name="viewport" content="width=device-width, initial-scale=1">
5
5
  <link rel="stylesheet" href="/__nuxt-og-image/_nuxt/entry.f47d0628.css">
6
- <link rel="modulepreload" as="script" crossorigin href="/__nuxt-og-image/_nuxt/entry.2fa3fdbe.js">
6
+ <link rel="modulepreload" as="script" crossorigin href="/__nuxt-og-image/_nuxt/entry.e67f1456.js">
7
7
  <link rel="prefetch" as="style" href="/__nuxt-og-image/_nuxt/error-404.b751fa02.css">
8
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-og-image/_nuxt/error-404.1d509bc2.js">
8
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-og-image/_nuxt/error-404.374ebaaf.js">
9
9
  <link rel="prefetch" as="style" href="/__nuxt-og-image/_nuxt/error-500.69009e70.css">
10
- <link rel="prefetch" as="script" crossorigin href="/__nuxt-og-image/_nuxt/error-500.399895ac.js">
11
- <script type="module" src="/__nuxt-og-image/_nuxt/entry.2fa3fdbe.js" crossorigin></script><script>"use strict";(()=>{const a=window,e=document.documentElement,m=["dark","light"],c=window&&window.localStorage&&window.localStorage.getItem&&window.localStorage.getItem("nuxt-color-mode")||"system";let n=c==="system"?d():c;const l=e.getAttribute("data-color-mode-forced");l&&(n=l),i(n),a["__NUXT_COLOR_MODE__"]={preference:c,value:n,getColorScheme:d,addColorScheme:i,removeColorScheme:f};function i(o){const t=""+o+"",s="";e.classList?e.classList.add(t):e.className+=" "+t,s&&e.setAttribute("data-"+s,o)}function f(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 d(){if(a.matchMedia&&r("").media!=="not all"){for(const o of m)if(r(":"+o).matches)return o}return"light"}})();
10
+ <link rel="prefetch" as="script" crossorigin href="/__nuxt-og-image/_nuxt/error-500.07f448c5.js">
11
+ <script type="module" src="/__nuxt-og-image/_nuxt/entry.e67f1456.js" crossorigin></script><script>"use strict";(()=>{const a=window,e=document.documentElement,m=["dark","light"],c=window&&window.localStorage&&window.localStorage.getItem&&window.localStorage.getItem("nuxt-color-mode")||"system";let n=c==="system"?d():c;const l=e.getAttribute("data-color-mode-forced");l&&(n=l),i(n),a["__NUXT_COLOR_MODE__"]={preference:c,value:n,getColorScheme:d,addColorScheme:i,removeColorScheme:f};function i(o){const t=""+o+"",s="";e.classList?e.classList.add(t):e.className+=" "+t,s&&e.setAttribute("data-"+s,o)}function f(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 d(){if(a.matchMedia&&r("").media!=="not all"){for(const o of m)if(r(":"+o).matches)return o}return"light"}})();
12
12
  </script></head>
13
13
  <body ><div id="__nuxt"></div><script type="application/json" id="__NUXT_DATA__" data-ssr="false">[{"_errors":1,"serverRendered":2,"data":3,"state":4},{},false,{},{}]</script>
14
14
  <script>window.__NUXT__={};window.__NUXT__.config={public:{},app:{baseURL:"/__nuxt-og-image",buildAssetsDir:"/_nuxt/",cdnURL:""}}</script></body>
package/dist/module.d.mts CHANGED
@@ -83,6 +83,7 @@ interface FontConfig {
83
83
  name: string;
84
84
  weight: string | number;
85
85
  path?: string;
86
+ key?: string;
86
87
  }
87
88
  type InputFontConfig = (`${string}:${number}` | FontConfig);
88
89
 
package/dist/module.d.ts CHANGED
@@ -83,6 +83,7 @@ interface FontConfig {
83
83
  name: string;
84
84
  weight: string | number;
85
85
  path?: string;
86
+ key?: string;
86
87
  }
87
88
  type InputFontConfig = (`${string}:${number}` | FontConfig);
88
89
 
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "bridge": false
6
6
  },
7
7
  "configKey": "ogImage",
8
- "version": "3.0.0-beta.34"
8
+ "version": "3.0.0-beta.36"
9
9
  }
package/dist/module.mjs CHANGED
@@ -11,7 +11,7 @@ import { onDevToolsInitialized, extendServerRpc } from '@nuxt/devtools-kit';
11
11
  import { readFile, writeFile } from 'node:fs/promises';
12
12
  import { createHash } from 'node:crypto';
13
13
 
14
- const version = "3.0.0-beta.34";
14
+ const version = "3.0.0-beta.36";
15
15
 
16
16
  const autodetectableProviders = {
17
17
  azure_static: "azure",
@@ -383,17 +383,32 @@ const module = defineNuxtModule({
383
383
  await installNuxtSiteConfig();
384
384
  if (hasNuxtModule("@nuxt/content"))
385
385
  addServerPlugin(resolve("./runtime/nitro/plugins/nuxt-content"));
386
+ if (!config.fonts.length)
387
+ config.fonts = ["Inter:400", "Inter:700"];
388
+ config.fonts = config.fonts.map((font) => {
389
+ if (typeof font === "string" && font.startsWith("Inter:")) {
390
+ const [_, weight] = font.split(":");
391
+ return {
392
+ name: "Inter",
393
+ weight,
394
+ // nuxt server assets
395
+ key: `nuxt-og-image:fonts:inter-latin-ext-${weight}-normal.woff`
396
+ };
397
+ }
398
+ return font;
399
+ });
400
+ nuxt.hooks.hook("nitro:config", (nitroConfig) => {
401
+ nitroConfig.serverAssets = nitroConfig.serverAssets || [];
402
+ nitroConfig.serverAssets.push({ baseName: "nuxt-og-image:fonts", dir: resolve("./runtime/server/assets") });
403
+ });
386
404
  if (preset === "stackblitz") {
387
405
  config.fonts = (config.fonts || []).map((f) => {
388
- if (typeof f === "string" || !f.path) {
406
+ if (typeof f === "string" || !f.path && !f.key) {
389
407
  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.`);
390
408
  return false;
391
409
  }
392
410
  return f;
393
411
  }).filter(Boolean);
394
- } else {
395
- if (!config.fonts.length)
396
- config.fonts = ["Inter:400", "Inter:700"];
397
412
  }
398
413
  nuxt.options.experimental.componentIslands = true;
399
414
  addServerHandler({
@@ -535,7 +550,7 @@ ${componentImports}
535
550
  if (!nuxt.options._generate && nuxt.options.build) {
536
551
  nuxt.options.nitro.prerender = nuxt.options.nitro.prerender || {};
537
552
  nuxt.options.nitro.prerender.routes = nuxt.options.nitro.prerender.routes || [];
538
- normalisedFonts.filter((f) => !f.path).forEach(({ name, weight }) => {
553
+ normalisedFonts.filter((f) => !f.path && !f.key).forEach(({ name, weight }) => {
539
554
  nuxt.options.nitro.prerender.routes.push(`/__og-image__/font/${name}/${weight}.ttf`);
540
555
  });
541
556
  }
@@ -568,8 +583,8 @@ ${componentImports}
568
583
  } else if (nuxt.options.build) {
569
584
  await setupBuildHandler(config, resolve);
570
585
  }
571
- if (nuxt.options.nitro.prerender?.routes?.length || nuxt.options.nitro.prerender?.crawlLinks || nuxt.options._generate)
572
- addServerPlugin(resolve("./runtime/nitro/plugins/prerender.ts"));
586
+ if (nuxt.options.build)
587
+ addServerPlugin(resolve("./runtime/nitro/plugins/prerender"));
573
588
  setupPrerenderHandler(config, resolve);
574
589
  }
575
590
  });
@@ -104,9 +104,9 @@ if (typeof props.icon === 'string' && !runtimeConfig.hasNuxtIcon && process.dev)
104
104
  }"
105
105
  />
106
106
  <div class="h-full w-full justify-between relative">
107
- <div class="flex flex-row justify-between items-center">
108
- <div class="flex flex-col w-full" :style="icon ? { width: '65%' } : {}">
109
- <h1 class="font-bold mb-[30px] text-[75px] max-w-[70%]">
107
+ <div class="flex flex-row justify-between items-start">
108
+ <div class="flex flex-col w-full max-w-[65%]">
109
+ <h1 class="m-0 font-bold mb-[30px] text-[75px]">
110
110
  {{ title }}
111
111
  </h1>
112
112
  <p
@@ -118,7 +118,7 @@ if (typeof props.icon === 'string' && !runtimeConfig.hasNuxtIcon && process.dev)
118
118
  </p>
119
119
  </div>
120
120
  <div v-if="icon" style="width: 30%;" class="flex justify-end">
121
- <IconComponent :name="icon" size="250px" style="margin: 0 auto 0 100px;opacity: 0.9;" />
121
+ <IconComponent :name="icon" size="250px" style="margin: 0 auto; opacity: 0.7;" />
122
122
  </div>
123
123
  </div>
124
124
  <div class="flex flex-row justify-center items-center text-left w-full">
@@ -1,7 +1,7 @@
1
1
  import { defineOgImage, useRouter } from "#imports";
2
2
  export function defineOgImageScreenshot(options = {}) {
3
3
  const router = useRouter();
4
- const route = router.currentRoute.value?.path || "";
4
+ const route = router.currentRoute.value?.path || "/";
5
5
  return defineOgImage({
6
6
  alt: `Web page screenshot${route ? ` of ${route}` : ""}.`,
7
7
  renderer: "chromium",
@@ -1,6 +1,6 @@
1
1
  import type { Browser } from 'playwright-core';
2
2
  import type { OgImageOptions } from '../../types';
3
- export declare const prerenderCache: import("unstorage/dist/shared/unstorage.745f9650").a<OgImageOptions<"NuxtSeo">> | undefined;
3
+ export declare const prerenderOptionsCache: import("unstorage/dist/shared/unstorage.745f9650").a<OgImageOptions<"NuxtSeo">> | undefined;
4
4
  export declare const prerenderChromiumContext: {
5
5
  browser?: Browser;
6
6
  };
@@ -1,6 +1,6 @@
1
1
  import { createStorage } from "unstorage";
2
2
  import lruCacheDriver from "unstorage/drivers/lru-cache";
3
- export const prerenderCache = import.meta.prerender ? createStorage({
3
+ export const prerenderOptionsCache = import.meta.prerender ? createStorage({
4
4
  driver: lruCacheDriver({ max: 1e3 })
5
5
  }) : void 0;
6
6
  export const prerenderChromiumContext = { browser: void 0 };
@@ -1,2 +1 @@
1
- export declare function base64ToArrayBuffer(base64: string): ArrayBuffer;
2
1
  export declare function toBase64Image(fileName: string, data: string | ArrayBuffer): string;
@@ -1,8 +1,4 @@
1
1
  import { Buffer } from "node:buffer";
2
- export function base64ToArrayBuffer(base64) {
3
- const buffer = Buffer.from(base64, "base64");
4
- return new Uint8Array(buffer).buffer;
5
- }
6
2
  export function toBase64Image(fileName, data) {
7
3
  const base64 = typeof data === "string" ? data : Buffer.from(data).toString("base64");
8
4
  let type = "image/jpeg";
@@ -1,22 +1,26 @@
1
- import { Buffer } from "node:buffer";
2
1
  import { createError } from "h3";
3
- import { base64ToArrayBuffer } from "../env/assets.mjs";
4
2
  import { fontCache } from "./cache.mjs";
5
3
  import { useNitroOrigin, useStorage } from "#imports";
4
+ import { assets } from "#internal/nitro/virtual/server-assets";
6
5
  export async function loadFont({ e }, font) {
7
- const fontKey = `${font.name}:${font.weight}`;
8
- const storageKey = `assets:nuxt-og-image:font:${fontKey}`;
6
+ const fontKey = font.key || `${font.name}:${font.weight}`;
9
7
  if (fontCache[fontKey])
10
8
  return fontCache[fontKey];
11
- const [name, weight] = fontKey.split(":");
9
+ const { name, weight } = font;
12
10
  let data;
13
- if (await useStorage().hasItem(storageKey))
14
- data = base64ToArrayBuffer(await useStorage().getItem(storageKey));
11
+ if (font.key && await assets.hasItem(font.key))
12
+ data = await assets.getItemRaw(font.key);
15
13
  if (!data) {
16
14
  if (font.path) {
17
- if (import.meta.prerender) {
15
+ if (import.meta.dev || import.meta.prerender) {
18
16
  const key = `root:public${font.path.replace("./", ":").replace("/", ":")}`;
19
- data = await useStorage().getItemRaw(key);
17
+ if (await useStorage().hasItem(key))
18
+ data = await useStorage().getItemRaw(key);
19
+ if (!data) {
20
+ data = await e.$fetch(font.path, {
21
+ responseType: "arrayBuffer"
22
+ });
23
+ }
20
24
  } else {
21
25
  data = await e.$fetch(font.path, {
22
26
  baseURL: useNitroOrigin(e),
@@ -31,7 +35,6 @@ export async function loadFont({ e }, font) {
31
35
  }
32
36
  if (data) {
33
37
  fontCache[fontKey] = { name, weight: Number(weight), data, style: "normal" };
34
- await useStorage().setItem(storageKey, Buffer.from(data).toString("base64"));
35
38
  return fontCache[fontKey];
36
39
  }
37
40
  return createError({
@@ -1,22 +1,21 @@
1
1
  import { joinURL, withQuery } from "ufo";
2
2
  import { useNitroOrigin } from "#imports";
3
3
  export async function createScreenshot({ basePath, e, options, extension }, browser) {
4
- const path = options.component === "PageScreenshot" ? options.path : joinURL("/__og-image__/image", basePath, `og.html`);
4
+ const path = options.component === "PageScreenshot" ? basePath : joinURL("/__og-image__/image", basePath, `og.html`);
5
5
  const page = await browser.newPage({
6
6
  colorScheme: options.colorScheme,
7
7
  baseURL: useNitroOrigin(e)
8
8
  });
9
9
  if (import.meta.prerender && !options.html) {
10
- options.html = await e.$fetch(options.path);
10
+ options.html = await e.$fetch(path);
11
11
  }
12
12
  try {
13
13
  await page.setViewportSize({
14
14
  width: options.width || 1200,
15
15
  height: options.height || 630
16
16
  });
17
- const isHtml = options.html || options.path?.startsWith("html:");
18
- if (isHtml) {
19
- const html = options.html || options.path?.substring(5);
17
+ if (options.html) {
18
+ const html = options.html;
20
19
  await page.evaluate((html2) => {
21
20
  document.open("text/html");
22
21
  document.write(html2);
@@ -3,7 +3,7 @@ import { withBase } from "ufo";
3
3
  import sizeOf from "image-size";
4
4
  import { defineSatoriTransformer } from "../utils.mjs";
5
5
  import { toBase64Image } from "../../../env/assets.mjs";
6
- import { useNitroOrigin } from "#imports";
6
+ import { useNitroOrigin, useStorage } from "#imports";
7
7
  export default defineSatoriTransformer({
8
8
  filter: (node) => node.type === "img",
9
9
  transform: async (node, { e }) => {
@@ -12,23 +12,32 @@ export default defineSatoriTransformer({
12
12
  if (src) {
13
13
  let updated = false;
14
14
  let dimensions;
15
- if (!updated) {
16
- let valid = true;
17
- const response = await e.$fetch(src, {
15
+ let imageBuffer;
16
+ let valid = true;
17
+ if (import.meta.prerender || import.meta.dev) {
18
+ const key = `root:public${src.replace("./", ":").replace("/", ":")}`;
19
+ if (await useStorage().hasItem(key)) {
20
+ imageBuffer = await useStorage().getItemRaw(key);
21
+ updated = !!imageBuffer;
22
+ }
23
+ }
24
+ if (!import.meta.prerender && !updated) {
25
+ imageBuffer = await e.$fetch(src, {
18
26
  baseURL: useNitroOrigin(e),
19
27
  responseType: "arrayBuffer"
20
28
  }).catch(() => {
21
29
  valid = false;
22
30
  });
23
- if (valid) {
24
- node.props.src = toBase64Image(src, response);
25
- try {
26
- const imageSize = sizeOf(Buffer.from(response));
27
- dimensions = { width: imageSize.width, height: imageSize.height };
28
- } catch (e2) {
29
- }
30
- updated = true;
31
+ valid = !!imageBuffer;
32
+ }
33
+ if (valid) {
34
+ node.props.src = toBase64Image(src, imageBuffer);
35
+ try {
36
+ const imageSize = sizeOf(Buffer.from(imageBuffer));
37
+ dimensions = { width: imageSize.width, height: imageSize.height };
38
+ } catch (e2) {
31
39
  }
40
+ updated = true;
32
41
  }
33
42
  if (dimensions?.width && dimensions?.height) {
34
43
  const naturalAspectRatio = dimensions.width / dimensions.height;
@@ -1,13 +1,13 @@
1
- import { parseURL, withoutBase, withoutLeadingSlash, withoutTrailingSlash } from "ufo";
1
+ import { parseURL, withoutBase, withoutTrailingSlash } from "ufo";
2
2
  import { createError, getQuery } from "h3";
3
3
  import { defu } from "defu";
4
4
  import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
5
- import { hash } from "ohash";
6
5
  import { fetchPathHtmlAndExtractOptions } from "../options/fetch.mjs";
7
- import { prerenderCache } from "../cache/prerender.mjs";
6
+ import { prerenderOptionsCache } from "../cache/prerender.mjs";
8
7
  import { useChromiumRenderer, useSatoriRenderer } from "../renderers/satori/instances.mjs";
9
8
  import { separateProps, useOgImageRuntimeConfig } from "../../utils.mjs";
10
- import { useRuntimeConfig, useSiteConfig } from "#imports";
9
+ import { resolvePathCacheKey } from "../../nitro/utils.mjs";
10
+ import { useRuntimeConfig } from "#imports";
11
11
  export async function resolveRendererContext(e) {
12
12
  const runtimeConfig = useOgImageRuntimeConfig();
13
13
  const path = parseURL(e.path).pathname;
@@ -31,20 +31,12 @@ export async function resolveRendererContext(e) {
31
31
  queryParams.props = JSON.parse(queryParams.props || "{}");
32
32
  queryParams = separateProps(queryParams);
33
33
  const isDebugJsonPayload = extension === "json" && runtimeConfig.debug;
34
- const siteConfig = useSiteConfig(e);
35
- const key = [
36
- withoutLeadingSlash(basePath === "/" || !basePath ? "index" : basePath).replaceAll("/", "-"),
37
- hash([
38
- basePath,
39
- siteConfig.url,
40
- hash(queryParams)
41
- ])
42
- ].join(":");
34
+ const key = resolvePathCacheKey(e, basePath);
43
35
  let options = queryParams.options;
44
36
  if (!options) {
45
- if (import.meta.prerender) {
46
- options = await prerenderCache?.getItem(key);
47
- } else {
37
+ if (import.meta.prerender)
38
+ options = await prerenderOptionsCache?.getItem(key);
39
+ if (!options) {
48
40
  const payload = await fetchPathHtmlAndExtractOptions(e, basePath, key);
49
41
  if (payload instanceof Error)
50
42
  return payload;
@@ -1,16 +1,18 @@
1
- import { parseURL, withoutBase, withoutLeadingSlash } from "ufo";
1
+ import { parseURL, withoutBase } from "ufo";
2
2
  import { defineNitroPlugin } from "nitropack/dist/runtime/plugin";
3
3
  import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
4
4
  import { defu } from "defu";
5
5
  import { extractAndNormaliseOgImageOptions } from "../../core/options/extract.mjs";
6
- import { prerenderCache, prerenderChromiumContext } from "../../core/cache/prerender.mjs";
6
+ import { prerenderChromiumContext, prerenderOptionsCache } from "../../core/cache/prerender.mjs";
7
7
  import { isInternalRoute } from "../../utils.pure.mjs";
8
+ import { resolvePathCacheKey } from "../utils.mjs";
8
9
  import { useRuntimeConfig } from "#imports";
9
10
  export default defineNitroPlugin(async (nitro) => {
10
11
  if (!import.meta.prerender)
11
12
  return;
12
- nitro.hooks.hook("render:html", async ({ head, bodyAppend }, e) => {
13
- const path = parseURL(e.event.path).pathname;
13
+ nitro.hooks.hook("render:html", async (html, ctx) => {
14
+ const { head, bodyAppend } = html;
15
+ const path = parseURL(ctx.event.path).pathname;
14
16
  if (isInternalRoute(path))
15
17
  return;
16
18
  const runtimeConfig = useRuntimeConfig();
@@ -28,10 +30,8 @@ export default defineNitroPlugin(async (nitro) => {
28
30
  ].join("\n"));
29
31
  if (!options)
30
32
  return;
31
- const key = [
32
- withoutLeadingSlash(path === "/" || !path ? "index" : path).replaceAll("/", "-")
33
- ].join(":");
34
- await prerenderCache.setItem(key, options);
33
+ const key = resolvePathCacheKey(ctx.event);
34
+ await prerenderOptionsCache.setItem(key, options);
35
35
  });
36
36
  nitro.hooks.hook("close", () => {
37
37
  if (prerenderChromiumContext.browser) {
@@ -0,0 +1,2 @@
1
+ import type { H3Event } from 'h3';
2
+ export declare function resolvePathCacheKey(e: H3Event, path?: string): string;
@@ -0,0 +1,17 @@
1
+ import { withoutLeadingSlash, withoutTrailingSlash } from "ufo";
2
+ import { hash } from "ohash";
3
+ import { normalizeKey } from "unstorage";
4
+ import { getQuery } from "h3";
5
+ import { useSiteConfig } from "#imports";
6
+ export function resolvePathCacheKey(e, path) {
7
+ const siteConfig = useSiteConfig(e);
8
+ const basePath = withoutTrailingSlash(withoutLeadingSlash(normalizeKey(path || e.path)));
9
+ return [
10
+ !basePath ? "index" : basePath,
11
+ hash([
12
+ basePath,
13
+ siteConfig.url,
14
+ hash(getQuery(e))
15
+ ])
16
+ ].join(":");
17
+ }
@@ -110,6 +110,7 @@ export interface FontConfig {
110
110
  name: string;
111
111
  weight: string | number;
112
112
  path?: string;
113
+ key?: string;
113
114
  }
114
115
  export type InputFontConfig = (`${string}:${number}` | FontConfig);
115
116
  export type RendererOptions = Omit<OgImageOptions, 'extension'> & {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-og-image",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.34",
4
+ "version": "3.0.0-beta.36",
5
5
  "packageManager": "pnpm@8.11.0",
6
6
  "description": "Enlightened OG Image generation for Nuxt.",
7
7
  "author": {
@@ -65,7 +65,7 @@
65
65
  "yoga-wasm-web": "^0.3.3"
66
66
  },
67
67
  "devDependencies": {
68
- "@antfu/eslint-config": "2.2.2",
68
+ "@antfu/eslint-config": "2.3.1",
69
69
  "@img/sharp-linux-x64": "0.33.0",
70
70
  "@nuxt/content": "^2.9.0",
71
71
  "@nuxt/devtools": "1.0.4",
@@ -73,7 +73,7 @@
73
73
  "@nuxt/test-utils": "3.8.1",
74
74
  "@nuxt/ui": "^2.11.0",
75
75
  "@nuxtjs/eslint-config-typescript": "^12.1.0",
76
- "@nuxtjs/i18n": "8.0.0-rc.6",
76
+ "@nuxtjs/i18n": "8.0.0-rc.7",
77
77
  "@nuxtjs/tailwindcss": "^6.10.1",
78
78
  "@unocss/nuxt": "^0.58.0",
79
79
  "bumpp": "^9.2.0",
@@ -83,7 +83,7 @@
83
83
  "nuxt-icon": "0.6.6",
84
84
  "playwright": "^1.40.1",
85
85
  "sass": "^1.69.5",
86
- "vitest": "^0.34.6"
86
+ "vitest": "^1.0.1"
87
87
  },
88
88
  "build": {
89
89
  "externals": [
@@ -1 +0,0 @@
1
- {"id":"ca5f9e65-b8d1-42b5-96f6-21ca72c45b74","timestamp":1701700356644,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}