nuxt-og-image 1.0.0-beta.2 → 1.0.0-beta.4
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.
- package/README.md +1 -0
- package/dist/client/200.html +2 -2
- package/dist/client/404.html +2 -2
- package/dist/client/_nuxt/{Icon.be9fb21b.js → Icon.881857b6.js} +1 -1
- package/dist/client/_nuxt/{entry.a0824e7e.js → entry.db5a4449.js} +2 -2
- package/dist/client/_nuxt/{error-404.15b637ef.js → error-404.1c1c2700.js} +1 -1
- package/dist/client/_nuxt/{error-500.037a45db.js → error-500.6a615525.js} +1 -1
- package/dist/client/_nuxt/{error-component.541b3e05.js → error-component.834f3c34.js} +2 -2
- package/dist/client/index.html +2 -2
- package/dist/module.d.ts +8 -8
- package/dist/module.json +1 -1
- package/dist/module.mjs +48 -29
- package/dist/runtime/components/{OgImageTemplate.island.vue → OgImageBasic.island.vue} +2 -2
- package/dist/runtime/components/OgImageDynamic.d.ts +2 -2
- package/dist/runtime/components/OgImageScreenshot.d.ts +2 -2
- package/dist/runtime/components/OgImageStatic.d.ts +2 -2
- package/dist/runtime/composables/defineOgImage.d.ts +5 -5
- package/dist/runtime/composables/defineOgImage.mjs +11 -6
- package/dist/runtime/nitro/providers/browser.mjs +2 -6
- package/dist/runtime/nitro/providers/satori.mjs +21 -25
- package/dist/runtime/nitro/routes/__og_image__/html.mjs +6 -8
- package/dist/runtime/nitro/routes/__og_image__/index.mjs +3 -3
- package/dist/runtime/nitro/routes/__og_image__/og.png.mjs +7 -11
- package/dist/runtime/nitro/routes/__og_image__/options.d.ts +4 -0
- package/dist/runtime/nitro/routes/__og_image__/{payload.mjs → options.mjs} +18 -28
- package/dist/runtime/nitro/routes/__og_image__/svg.mjs +4 -4
- package/dist/runtime/nitro/utils.d.ts +3 -3
- package/dist/runtime/nitro/utils.mjs +4 -4
- package/package.json +2 -2
- package/dist/runtime/nitro/routes/__og_image__/payload.d.ts +0 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
import{s as n,v as a,o as r,l,x as e,t as s,y as d,z as c,A as p,B as f,C as x,D as h}from"./entry.
|
|
1
|
+
import{s as n,v as a,o as r,l,x as e,t as s,y as d,z as c,A as p,B as f,C as x,D as h}from"./entry.db5a4449.js";const m=t=>(x("data-v-18337f8d"),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)),_={class:"max-w-520px text-center z-20"},b=["textContent"],y=["textContent"],w={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 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}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=p;return r(),l("div",u,[g,e("div",_,[e("h1",{class:"text-8xl sm:text-10xl font-medium mb-8",textContent:s(t.statusCode)},null,8,b),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,y),e("div",w,[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(()=>[f(s(t.backHome),1)]),_:1})])])])}}},z=n(S,[["__scopeId","data-v-18337f8d"]]);export{z as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{s as i,v as a,o as r,l as n,x as e,t as s,C as l,D as d}from"./entry.
|
|
1
|
+
import{s as i,v as a,o as r,l as n,x as e,t as s,C as l,D as d}from"./entry.db5a4449.js";const c=t=>(l("data-v-428e244b"),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}'}]}),(b,u)=>(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-428e244b"]]);export{w as default};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{d as n,_ as o,o as _,c as f,n as g,g as E,u as r}from"./entry.
|
|
1
|
+
import{d as n,_ as o,o as _,c as f,n as g,g as E,u as r}from"./entry.db5a4449.js";const k={__name:"nuxt-error-page",props:{error:Object},setup(t){(t.error.stack||"").split(`
|
|
2
2
|
`).splice(1).map(e=>({text:e.replace("webpack:/","").replace(".vue",".js").trim(),internal:e.includes("node_modules")&&!e.includes(".cache")||e.includes("internal")||e.includes("new Promise")})).map(e=>`<span class="stack${e.internal?" internal":""}">${e.text}</span>`).join(`
|
|
3
|
-
`);const s=Number(t.error.statusCode||500),a=s===404,c=t.error.statusMessage??(a?"Page Not Found":"Internal Server Error"),u=t.error.message||t.error.toString(),i=void 0,d=n(()=>o(()=>import("./error-404.
|
|
3
|
+
`);const s=Number(t.error.statusCode||500),a=s===404,c=t.error.statusMessage??(a?"Page Not Found":"Internal Server Error"),u=t.error.message||t.error.toString(),i=void 0,d=n(()=>o(()=>import("./error-404.1c1c2700.js"),["./error-404.1c1c2700.js","./entry.db5a4449.js","./entry.0827acf4.css","./error-404.68aa58b4.css"],import.meta.url).then(e=>e.default||e)),l=n(()=>o(()=>import("./error-500.6a615525.js"),["./error-500.6a615525.js","./entry.db5a4449.js","./entry.0827acf4.css","./error-500.dc5710d1.css"],import.meta.url).then(e=>e.default||e)),m=a?d:l;return(e,p)=>(_(),f(r(m),g(E({statusCode:r(s),statusMessage:r(c),description:r(u),stack:r(i)})),null,16))}},v=k;export{v as default};
|
package/dist/client/index.html
CHANGED
|
@@ -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.
|
|
4
|
+
<meta name="viewport" content="width=device-width, initial-scale=1"><link rel="modulepreload" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/entry.db5a4449.js"><link rel="preload" as="style" href="/__nuxt_og_image__/client/_nuxt/entry.0827acf4.css"><link rel="prefetch" as="script" crossorigin href="/__nuxt_og_image__/client/_nuxt/error-component.834f3c34.js"><link rel="stylesheet" href="/__nuxt_og_image__/client/_nuxt/entry.0827acf4.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"}
|
|
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.
|
|
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.db5a4449.js" crossorigin></script></body>
|
|
7
7
|
</html>
|
package/dist/module.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
|
+
import { SatoriOptions } from 'satori';
|
|
2
3
|
|
|
3
4
|
interface ScreenshotOptions {
|
|
4
5
|
colorScheme?: 'dark' | 'light';
|
|
@@ -21,7 +22,7 @@ interface ScreenshotOptions {
|
|
|
21
22
|
*/
|
|
22
23
|
delay?: number;
|
|
23
24
|
}
|
|
24
|
-
interface
|
|
25
|
+
interface OgImageOptions extends Partial<ScreenshotOptions> {
|
|
25
26
|
provider?: 'browser' | 'satori';
|
|
26
27
|
prerender?: boolean;
|
|
27
28
|
title?: string;
|
|
@@ -30,19 +31,18 @@ interface OgImagePayload extends Partial<ScreenshotOptions> {
|
|
|
30
31
|
alt?: string;
|
|
31
32
|
[key: string]: any;
|
|
32
33
|
}
|
|
33
|
-
type OgImageScreenshotPayload = Omit<OgImagePayload, 'component'>;
|
|
34
|
-
declare module 'nitropack' {
|
|
35
|
-
interface NitroRouteRules {
|
|
36
|
-
ogImage?: false | OgImageScreenshotPayload | OgImagePayload;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
34
|
|
|
40
|
-
interface ModuleOptions
|
|
35
|
+
interface ModuleOptions {
|
|
41
36
|
/**
|
|
42
37
|
* The hostname of your website.
|
|
43
38
|
*/
|
|
44
39
|
host: string;
|
|
40
|
+
defaults: OgImageOptions;
|
|
45
41
|
experimentalNitroBrowser: boolean;
|
|
42
|
+
satoriFonts: Array<Partial<SatoriOptions['fonts'][number]> & {
|
|
43
|
+
publicPath: string;
|
|
44
|
+
}>;
|
|
45
|
+
satoriOptions: Partial<SatoriOptions>;
|
|
46
46
|
forcePrerender: boolean;
|
|
47
47
|
}
|
|
48
48
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions>;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
|
-
import { useNuxt, addTemplate, defineNuxtModule, createResolver, addServerHandler, addImports, addComponent } from '@nuxt/kit';
|
|
3
|
+
import { useNuxt, addTemplate, defineNuxtModule, createResolver, getNuxtVersion, useLogger, addServerHandler, addImports, addComponent } from '@nuxt/kit';
|
|
4
4
|
import { execa } from 'execa';
|
|
5
5
|
import chalk from 'chalk';
|
|
6
6
|
import defu from 'defu';
|
|
@@ -57,13 +57,8 @@ async function screenshot(browser, url, options) {
|
|
|
57
57
|
return await page.screenshot();
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
const PayloadScriptId = "nuxt-og-image-payload";
|
|
61
|
-
const Constants = {
|
|
62
|
-
PayloadScriptId
|
|
63
|
-
};
|
|
64
|
-
|
|
65
60
|
function exposeConfig(alias, filename, config) {
|
|
66
|
-
const exports = Object.entries(config).map(([k, v]) => `export const ${k} =
|
|
61
|
+
const exports = Object.entries(config).map(([k, v]) => `export const ${k} = ${JSON.stringify(v)}`).join("\n");
|
|
67
62
|
useNuxt().options.alias[alias] = addTemplate({
|
|
68
63
|
filename,
|
|
69
64
|
getContents: () => exports
|
|
@@ -72,6 +67,16 @@ function exposeConfig(alias, filename, config) {
|
|
|
72
67
|
nitroConfig.virtual[alias] = exports;
|
|
73
68
|
});
|
|
74
69
|
}
|
|
70
|
+
function extractOgImageOptions(html) {
|
|
71
|
+
const options = html.match(/<script id="nuxt-og-image-options" type="application\/json">(.+?)<\/script>/)?.[1];
|
|
72
|
+
if (options) {
|
|
73
|
+
return JSON.parse(options);
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
function stripOgImageOptions(html) {
|
|
78
|
+
return html.replace(/<script id="nuxt-og-image-options" type="application\/json">(.*?)<\/script>/, "");
|
|
79
|
+
}
|
|
75
80
|
|
|
76
81
|
function setupPlaygroundRPC(nuxt, config) {
|
|
77
82
|
const serverFunctions = {
|
|
@@ -155,13 +160,6 @@ function getBodyJson(req) {
|
|
|
155
160
|
});
|
|
156
161
|
}
|
|
157
162
|
|
|
158
|
-
function extractOgPayload(html) {
|
|
159
|
-
const payload = html.match(new RegExp(`<script id="${PayloadScriptId}" type="application/json">(.+?)<\/script>`))?.[1];
|
|
160
|
-
if (payload) {
|
|
161
|
-
return JSON.parse(payload);
|
|
162
|
-
}
|
|
163
|
-
return false;
|
|
164
|
-
}
|
|
165
163
|
const PATH = "/__nuxt_og_image__";
|
|
166
164
|
const PATH_ENTRY = `${PATH}/entry`;
|
|
167
165
|
const PATH_PLAYGROUND = `${PATH}/client`;
|
|
@@ -179,8 +177,26 @@ const module = defineNuxtModule({
|
|
|
179
177
|
experimentalNitroBrowser: false,
|
|
180
178
|
forcePrerender: !nuxt.options.dev && nuxt.options._generate,
|
|
181
179
|
host: nuxt.options.runtimeConfig.public?.siteUrl,
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
defaults: {
|
|
181
|
+
component: "OgImageBasic",
|
|
182
|
+
width: 1200,
|
|
183
|
+
height: 630
|
|
184
|
+
},
|
|
185
|
+
satoriFonts: [
|
|
186
|
+
{
|
|
187
|
+
name: "Inter",
|
|
188
|
+
weight: 400,
|
|
189
|
+
style: "normal",
|
|
190
|
+
publicPath: "/inter-latin-ext-400-normal.woff"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
name: "Inter",
|
|
194
|
+
weight: 700,
|
|
195
|
+
style: "normal",
|
|
196
|
+
publicPath: "/inter-latin-ext-700-normal.woff"
|
|
197
|
+
}
|
|
198
|
+
],
|
|
199
|
+
satoriOptions: {}
|
|
184
200
|
};
|
|
185
201
|
},
|
|
186
202
|
async setup(config, nuxt) {
|
|
@@ -193,6 +209,10 @@ const module = defineNuxtModule({
|
|
|
193
209
|
};
|
|
194
210
|
nuxt.options.experimental.componentIslands = true;
|
|
195
211
|
const isEdge = (process.env.NITRO_PRESET || "").includes("edge");
|
|
212
|
+
const hasIslandSupport = getNuxtVersion(nuxt) !== "3.0.0";
|
|
213
|
+
const logger = useLogger("nuxt-og-image");
|
|
214
|
+
if (!hasIslandSupport)
|
|
215
|
+
logger.warn("You are using Nuxt 3.0.0 with `nuxt-og-image`, which only supports screenshots.\nPlease upgrade to Nuxt 3.0.1 or the edge channel: https://nuxt.com/docs/guide/going-further/edge-channel.");
|
|
196
216
|
addTemplate({
|
|
197
217
|
filename: "nuxt-og-image.d.ts",
|
|
198
218
|
getContents: () => {
|
|
@@ -211,7 +231,7 @@ export {}
|
|
|
211
231
|
nuxt.hooks.hook("prepare:types", ({ references }) => {
|
|
212
232
|
references.push({ path: resolve(nuxt.options.buildDir, "nuxt-og-image.d.ts") });
|
|
213
233
|
});
|
|
214
|
-
["html", "
|
|
234
|
+
["html", "options", "svg", "og.png"].forEach((type) => {
|
|
215
235
|
addServerHandler({
|
|
216
236
|
handler: resolve(`./runtime/nitro/routes/__og_image__/${type}`)
|
|
217
237
|
});
|
|
@@ -238,8 +258,8 @@ export {}
|
|
|
238
258
|
});
|
|
239
259
|
});
|
|
240
260
|
await addComponent({
|
|
241
|
-
name: "
|
|
242
|
-
filePath: resolve("./runtime/components/
|
|
261
|
+
name: "OgImageBasic",
|
|
262
|
+
filePath: resolve("./runtime/components/OgImageBasic.island.vue"),
|
|
243
263
|
global: true,
|
|
244
264
|
island: true
|
|
245
265
|
});
|
|
@@ -252,7 +272,6 @@ export {}
|
|
|
252
272
|
});
|
|
253
273
|
const runtimeDir = resolve("./runtime");
|
|
254
274
|
nuxt.options.build.transpile.push(runtimeDir);
|
|
255
|
-
exposeConfig("#nuxt-og-image/constants", "nuxt-og-image-constants.mjs", Constants);
|
|
256
275
|
exposeConfig("#nuxt-og-image/config", "nuxt-og-image-config.mjs", config);
|
|
257
276
|
nuxt.hooks.hook("nitro:config", (nitroConfig) => {
|
|
258
277
|
nitroConfig.externals = defu(nitroConfig.externals || {}, {
|
|
@@ -292,19 +311,19 @@ export {}
|
|
|
292
311
|
const html = ctx.contents;
|
|
293
312
|
if (!html)
|
|
294
313
|
return;
|
|
295
|
-
const
|
|
296
|
-
ctx.contents = html
|
|
314
|
+
const extractedOptions = extractOgImageOptions(html);
|
|
315
|
+
ctx.contents = stripOgImageOptions(html);
|
|
297
316
|
const routeRules = defu({}, ..._routeRulesMatcher.matchAll(ctx.route).reverse());
|
|
298
|
-
if (!
|
|
317
|
+
if (!extractedOptions || routeRules.ogImage === false)
|
|
299
318
|
return;
|
|
300
|
-
const
|
|
319
|
+
const options = {
|
|
301
320
|
path: ctx.route,
|
|
302
|
-
...
|
|
321
|
+
...extractedOptions,
|
|
303
322
|
...routeRules.ogImage || {},
|
|
304
323
|
ctx
|
|
305
324
|
};
|
|
306
|
-
if ((nuxt.options._generate ||
|
|
307
|
-
screenshotQueue.push(
|
|
325
|
+
if ((nuxt.options._generate || options.prerender) && options.provider === "browser")
|
|
326
|
+
screenshotQueue.push(options);
|
|
308
327
|
});
|
|
309
328
|
if (nuxt.options.dev)
|
|
310
329
|
return;
|
|
@@ -333,8 +352,8 @@ export {}
|
|
|
333
352
|
const filename = joinURL(dirname, "/og.png");
|
|
334
353
|
try {
|
|
335
354
|
const imgBuffer = await screenshot(browser, `${host}${entry.path}`, {
|
|
336
|
-
...config,
|
|
337
|
-
...entry
|
|
355
|
+
...config.defaults || {},
|
|
356
|
+
...entry || {}
|
|
338
357
|
});
|
|
339
358
|
try {
|
|
340
359
|
await mkdir(dirname, { recursive: true });
|
|
@@ -10,10 +10,10 @@ const props = defineProps({
|
|
|
10
10
|
<div :style="{ padding: '0 60px', width: '100%', height: '100%', backgroundColor: '#0c0c0c', backgroundImage: 'linear-gradient(to bottom, #dbf4ff, #fff1f1)', display: 'flex', alignItems: 'center' }">
|
|
11
11
|
<div :style="{ padding: '0 30px', display: 'flex', flexDirection: 'column' }">
|
|
12
12
|
<p :style="{ fontSize: '60px', fontWeight: 'bold', marginBottom: '20px' }">
|
|
13
|
-
{{ title }}
|
|
13
|
+
{{ title || 'Og Image Template' }}
|
|
14
14
|
</p>
|
|
15
15
|
<p :style="{ fontSize: '26px' }">
|
|
16
|
-
{{ description }}
|
|
16
|
+
{{ description || 'Set a description to change me.' }}
|
|
17
17
|
</p>
|
|
18
18
|
</div>
|
|
19
19
|
</div>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
declare const _default: import("vue").DefineComponent<
|
|
1
|
+
import type { OgImageOptions } from '../../types';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
}>;
|
|
5
5
|
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
declare const _default: import("vue").DefineComponent<
|
|
1
|
+
import type { OgImageScreenshotOptions } from '../../types';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<OgImageScreenshotOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageScreenshotOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
[x: number]: any;
|
|
5
5
|
}>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
declare const _default: import("vue").DefineComponent<
|
|
1
|
+
import type { OgImageOptions } from '../../types';
|
|
2
|
+
declare const _default: import("vue").DefineComponent<OgImageOptions, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<OgImageOptions>>, {
|
|
3
3
|
[x: string]: any;
|
|
4
4
|
}>;
|
|
5
5
|
export default _default;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
export declare function defineOgImageScreenshot(options?:
|
|
3
|
-
export declare function defineOgImageDynamic(options?:
|
|
4
|
-
export declare function defineOgImageStatic(options?:
|
|
5
|
-
export declare function defineOgImage(options?:
|
|
1
|
+
import type { OgImageOptions, OgImageScreenshotOptions } from '../../types';
|
|
2
|
+
export declare function defineOgImageScreenshot(options?: OgImageScreenshotOptions): void;
|
|
3
|
+
export declare function defineOgImageDynamic(options?: OgImageOptions): void;
|
|
4
|
+
export declare function defineOgImageStatic(options?: OgImageOptions): void;
|
|
5
|
+
export declare function defineOgImage(options?: OgImageOptions): void;
|
|
@@ -2,8 +2,7 @@ import { useServerHead } from "@vueuse/head";
|
|
|
2
2
|
import { withBase } from "ufo";
|
|
3
3
|
import { useRequestEvent } from "#app";
|
|
4
4
|
import { useRouter } from "#imports";
|
|
5
|
-
import {
|
|
6
|
-
import { forcePrerender, height, host, width } from "#nuxt-og-image/config";
|
|
5
|
+
import { defaults, forcePrerender, host } from "#nuxt-og-image/config";
|
|
7
6
|
export function defineOgImageScreenshot(options = {}) {
|
|
8
7
|
const router = useRouter();
|
|
9
8
|
const route = router?.currentRoute?.value?.path || "";
|
|
@@ -45,11 +44,11 @@ export function defineOgImage(options = {}) {
|
|
|
45
44
|
},
|
|
46
45
|
{
|
|
47
46
|
property: "og:image:width",
|
|
48
|
-
content: width
|
|
47
|
+
content: options.width || defaults.width
|
|
49
48
|
},
|
|
50
49
|
{
|
|
51
50
|
property: "og:image:height",
|
|
52
|
-
content: height
|
|
51
|
+
content: options.height || defaults.height
|
|
53
52
|
}
|
|
54
53
|
];
|
|
55
54
|
if (options.alt) {
|
|
@@ -62,9 +61,15 @@ export function defineOgImage(options = {}) {
|
|
|
62
61
|
meta,
|
|
63
62
|
script: [
|
|
64
63
|
{
|
|
65
|
-
id:
|
|
64
|
+
id: "nuxt-og-image-options",
|
|
66
65
|
type: "application/json",
|
|
67
|
-
children: () =>
|
|
66
|
+
children: () => {
|
|
67
|
+
const payload = {};
|
|
68
|
+
Object.entries(options).forEach(([key, val]) => {
|
|
69
|
+
payload[key.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = val;
|
|
70
|
+
});
|
|
71
|
+
return payload;
|
|
72
|
+
}
|
|
68
73
|
}
|
|
69
74
|
]
|
|
70
75
|
});
|
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { screenshot } from "../../browserUtil.mjs";
|
|
2
|
-
import { height, width } from "#nuxt-og-image/config";
|
|
3
2
|
import { createBrowser } from "#nuxt-og-image/browser";
|
|
4
3
|
export default {
|
|
5
4
|
name: "browser",
|
|
6
5
|
createSvg: function createSvg() {
|
|
7
6
|
throw new Error("Browser provider isn't able to create SVGs.");
|
|
8
7
|
},
|
|
9
|
-
createPng: async function createPng(basePath) {
|
|
8
|
+
createPng: async function createPng(basePath, options) {
|
|
10
9
|
const browser = await createBrowser();
|
|
11
|
-
return screenshot(browser, basePath,
|
|
12
|
-
width: Number(width),
|
|
13
|
-
height: Number(height)
|
|
14
|
-
});
|
|
10
|
+
return screenshot(browser, basePath, options);
|
|
15
11
|
}
|
|
16
12
|
};
|
|
@@ -2,47 +2,43 @@ import { fileURLToPath } from "node:url";
|
|
|
2
2
|
import { promises as fsp } from "node:fs";
|
|
3
3
|
import { html as convertHtmlToSatori } from "satori-html";
|
|
4
4
|
import satori from "satori";
|
|
5
|
-
import { parseURL } from "ufo";
|
|
5
|
+
import { parseURL, withBase } from "ufo";
|
|
6
6
|
import { Resvg } from "@resvg/resvg-js";
|
|
7
7
|
import { dirname, resolve } from "pathe";
|
|
8
|
-
import { height, width } from "#nuxt-og-image/config";
|
|
9
8
|
import { getAsset } from "#internal/nitro/virtual/public-assets";
|
|
9
|
+
import { satoriFonts, satoriOptions } from "#nuxt-og-image/config";
|
|
10
10
|
export default {
|
|
11
11
|
name: "satori",
|
|
12
|
-
createPng: async function createPng(baseUrl) {
|
|
13
|
-
const svg = await this.createSvg(baseUrl);
|
|
12
|
+
createPng: async function createPng(baseUrl, options) {
|
|
13
|
+
const svg = await this.createSvg(baseUrl, options);
|
|
14
14
|
const resvg = new Resvg(svg, {});
|
|
15
15
|
const pngData = resvg.render();
|
|
16
16
|
return pngData.asPng();
|
|
17
17
|
},
|
|
18
|
-
createSvg: async function createSvg(baseUrl) {
|
|
18
|
+
createSvg: async function createSvg(baseUrl, options) {
|
|
19
19
|
const url = parseURL(baseUrl);
|
|
20
20
|
const html = await $fetch(url.pathname);
|
|
21
21
|
const body = html.match(/<body[^>]*>([\s\S]*)<\/body>/)?.[1];
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
const parseFont = async (font) => {
|
|
23
|
+
if (typeof font.publicPath === "string") {
|
|
24
|
+
const file = getAsset(font.publicPath);
|
|
25
|
+
if (file) {
|
|
26
|
+
const serverDir = dirname(fileURLToPath(import.meta.url));
|
|
27
|
+
font.data = await fsp.readFile(resolve(serverDir, file.path));
|
|
28
|
+
}
|
|
29
|
+
if (!font.data)
|
|
30
|
+
font.data = await (await $fetch(withBase(font.publicPath, `${url.protocol}//${url.host}`))).arrayBuffer();
|
|
28
31
|
}
|
|
29
|
-
|
|
30
|
-
fontData = await (await $fetch(`${url.protocol}//${url.host}/inter-latin-ext-${weight}-normal.woff`)).arrayBuffer();
|
|
31
|
-
return {
|
|
32
|
-
name: "Inter",
|
|
33
|
-
weight,
|
|
34
|
-
style: "normal",
|
|
35
|
-
data: fontData
|
|
36
|
-
};
|
|
32
|
+
return font;
|
|
37
33
|
};
|
|
34
|
+
satoriOptions.fonts = satoriOptions.fonts || [];
|
|
35
|
+
for (const font of satoriFonts)
|
|
36
|
+
satoriOptions.fonts.push(await parseFont(font));
|
|
38
37
|
const satoriTree = convertHtmlToSatori(body);
|
|
39
38
|
return await satori(satoriTree, {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
await font(400),
|
|
44
|
-
await font(700)
|
|
45
|
-
]
|
|
39
|
+
...satoriOptions,
|
|
40
|
+
width: options.width,
|
|
41
|
+
height: options.height
|
|
46
42
|
});
|
|
47
43
|
}
|
|
48
44
|
};
|
|
@@ -2,19 +2,17 @@ import { parseURL, withBase, withoutTrailingSlash } from "ufo";
|
|
|
2
2
|
import { renderSSRHead } from "@unhead/ssr";
|
|
3
3
|
import { createHeadCore } from "@unhead/vue";
|
|
4
4
|
import { defineEventHandler, sendRedirect } from "h3";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { fetchOptions, renderIsland, useHostname } from "../../utils.mjs";
|
|
6
|
+
import { defaults } from "#nuxt-og-image/config";
|
|
7
7
|
export default defineEventHandler(async (e) => {
|
|
8
8
|
const path = parseURL(e.path).pathname;
|
|
9
9
|
if (!path.endsWith("__og_image__/html"))
|
|
10
10
|
return;
|
|
11
11
|
const basePath = withoutTrailingSlash(path.replace("__og_image__/html", ""));
|
|
12
|
-
const
|
|
13
|
-
if (
|
|
12
|
+
const options = await fetchOptions(basePath);
|
|
13
|
+
if (options.provider === "browser")
|
|
14
14
|
return sendRedirect(e, withBase(basePath, useHostname(e)));
|
|
15
|
-
const
|
|
16
|
-
delete payload.component;
|
|
17
|
-
const island = await renderIsland(component, payload);
|
|
15
|
+
const island = await renderIsland(options);
|
|
18
16
|
const head = createHeadCore();
|
|
19
17
|
head.push(island.head);
|
|
20
18
|
head.push({
|
|
@@ -38,6 +36,6 @@ export default defineEventHandler(async (e) => {
|
|
|
38
36
|
return `<!DOCTYPE html>
|
|
39
37
|
<html ${headChunk.htmlAttrs}>
|
|
40
38
|
<head>${headChunk.headTags}</head>
|
|
41
|
-
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="width: ${width}px; height: ${height}px; display: flex; margin: 0 auto;">${island.html}</div>${headChunk.bodyTags}</body>
|
|
39
|
+
<body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="width: ${defaults.width}px; height: ${defaults.height}px; display: flex; margin: 0 auto;">${island.html}</div>${headChunk.bodyTags}</body>
|
|
42
40
|
</html>`;
|
|
43
41
|
});
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { defineEventHandler } from "h3";
|
|
2
2
|
import { parseURL, withoutTrailingSlash } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { fetchOptions, useHostname } from "../../utils.mjs";
|
|
4
4
|
export default defineEventHandler(async (e) => {
|
|
5
5
|
const path = parseURL(e.path).pathname;
|
|
6
6
|
if (!path.endsWith("/__og_image__"))
|
|
7
7
|
return;
|
|
8
8
|
const basePath = withoutTrailingSlash(path.replace("__og_image__", ""));
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
9
|
+
const options = await fetchOptions(basePath);
|
|
10
|
+
if (!options)
|
|
11
11
|
return `The route ${basePath} has not been set up for og:image generation.`;
|
|
12
12
|
return `
|
|
13
13
|
<style>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler, setHeader } from "h3";
|
|
2
2
|
import { joinURL, parseURL, withBase, withoutTrailingSlash } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { fetchOptions, useHostname } from "../../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
5
|
export default defineEventHandler(async (e) => {
|
|
6
6
|
const path = parseURL(e.path).pathname;
|
|
@@ -9,15 +9,11 @@ export default defineEventHandler(async (e) => {
|
|
|
9
9
|
const basePath = withoutTrailingSlash(
|
|
10
10
|
path.replace("__og_image__/og.png", "")
|
|
11
11
|
);
|
|
12
|
-
const
|
|
12
|
+
const options = await fetchOptions(basePath);
|
|
13
13
|
setHeader(e, "Content-Type", "image/png");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
setHeader(e, "Expires", "0");
|
|
20
|
-
}
|
|
21
|
-
const provider = await useProvider(providerName);
|
|
22
|
-
return provider.createPng(withBase(joinURL(basePath, "/__og_image__/html"), useHostname(e)));
|
|
14
|
+
setHeader(e, "Cache-Control", "no-cache, no-store, must-revalidate");
|
|
15
|
+
setHeader(e, "Pragma", "no-cache");
|
|
16
|
+
setHeader(e, "Expires", "0");
|
|
17
|
+
const provider = await useProvider(options.provider);
|
|
18
|
+
return provider.createPng(withBase(joinURL(basePath, "/__og_image__/html"), useHostname(e)), options);
|
|
23
19
|
});
|
|
@@ -1,31 +1,29 @@
|
|
|
1
1
|
import { parseURL, withoutTrailingSlash } from "ufo";
|
|
2
2
|
import { defineEventHandler, getQuery } from "h3";
|
|
3
|
-
import {
|
|
3
|
+
import { extractOgImageOptions } from "../../../../utils";
|
|
4
4
|
import { getRouteRules } from "#internal/nitro";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return JSON.parse(payload);
|
|
9
|
-
}
|
|
10
|
-
return false;
|
|
11
|
-
};
|
|
12
|
-
export const inferOgPayload = (html) => {
|
|
13
|
-
const payload = {};
|
|
5
|
+
import { defaults } from "#nuxt-og-image/config";
|
|
6
|
+
export const inferOgImageOptions = (html) => {
|
|
7
|
+
const options = {};
|
|
14
8
|
const title = html.match(/<meta property="og:title" content="(.*?)">/)?.[1];
|
|
15
9
|
if (title)
|
|
16
|
-
|
|
10
|
+
options.title = title;
|
|
11
|
+
else
|
|
12
|
+
options.title = html.match(/<title>(.*?)<\/title>/)?.[1];
|
|
17
13
|
const description = html.match(/<meta property="og:description" content="(.*?)">/)?.[1];
|
|
18
14
|
if (description)
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
options.description = description;
|
|
16
|
+
else
|
|
17
|
+
options.description = html.match(/<meta name="description" content="(.*?)">/)?.[1];
|
|
18
|
+
return options;
|
|
21
19
|
};
|
|
22
20
|
export default defineEventHandler(async (e) => {
|
|
23
21
|
const path = parseURL(e.path).pathname;
|
|
24
|
-
if (!path.endsWith("__og_image__/
|
|
22
|
+
if (!path.endsWith("__og_image__/options"))
|
|
25
23
|
return;
|
|
26
|
-
const basePath = withoutTrailingSlash(path.replace("__og_image__/
|
|
24
|
+
const basePath = withoutTrailingSlash(path.replace("__og_image__/options", ""));
|
|
27
25
|
const html = await $fetch(basePath);
|
|
28
|
-
const extractedPayload =
|
|
26
|
+
const extractedPayload = extractOgImageOptions(html);
|
|
29
27
|
if (!extractedPayload)
|
|
30
28
|
return false;
|
|
31
29
|
e.node.req.url = basePath;
|
|
@@ -34,20 +32,12 @@ export default defineEventHandler(async (e) => {
|
|
|
34
32
|
e.node.req.url = e.path;
|
|
35
33
|
if (routeRules === false)
|
|
36
34
|
return false;
|
|
37
|
-
|
|
35
|
+
return {
|
|
38
36
|
path: basePath,
|
|
39
|
-
...
|
|
40
|
-
...
|
|
37
|
+
...defaults,
|
|
38
|
+
...inferOgImageOptions(html),
|
|
41
39
|
...routeRules || {},
|
|
40
|
+
...extractedPayload,
|
|
42
41
|
...getQuery(e)
|
|
43
42
|
};
|
|
44
|
-
if (payload.provider === "satori") {
|
|
45
|
-
payload = {
|
|
46
|
-
title: "Hello World",
|
|
47
|
-
description: "Example description",
|
|
48
|
-
image: "https://example.com/image.png",
|
|
49
|
-
...payload
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
return payload;
|
|
53
43
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { defineEventHandler, setHeader } from "h3";
|
|
2
2
|
import { joinURL, parseURL, withBase, withoutTrailingSlash } from "ufo";
|
|
3
|
-
import {
|
|
3
|
+
import { fetchOptions, useHostname } from "../../utils.mjs";
|
|
4
4
|
import { useProvider } from "#nuxt-og-image/provider";
|
|
5
5
|
export default defineEventHandler(async (e) => {
|
|
6
6
|
const path = parseURL(e.path).pathname;
|
|
@@ -9,8 +9,8 @@ export default defineEventHandler(async (e) => {
|
|
|
9
9
|
const basePath = withoutTrailingSlash(
|
|
10
10
|
path.replace("__og_image__/svg", "")
|
|
11
11
|
);
|
|
12
|
-
const
|
|
12
|
+
const options = await fetchOptions(basePath);
|
|
13
13
|
setHeader(e, "Content-Type", "image/svg+xml");
|
|
14
|
-
const provider = await useProvider(
|
|
15
|
-
return provider.createSvg(withBase(joinURL(basePath, "/__og_image__/html"), useHostname(e)));
|
|
14
|
+
const provider = await useProvider(options.provider);
|
|
15
|
+
return provider.createSvg(withBase(joinURL(basePath, "/__og_image__/html"), useHostname(e)), options);
|
|
16
16
|
});
|