nuxt-og-image 3.0.0-beta.4 → 3.0.0-beta.41

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 (136) hide show
  1. package/README.md +4 -4
  2. package/dist/client/200.html +5 -5
  3. package/dist/client/404.html +5 -5
  4. package/dist/client/_nuxt/IconCSS.7e8f1f7b.css +1 -0
  5. package/dist/client/_nuxt/{IconCSS.6583687a.js → IconCSS.aa1d279a.js} +1 -1
  6. package/dist/client/_nuxt/builds/latest.json +1 -1
  7. package/dist/client/_nuxt/builds/meta/fa0d9e15-6d49-41d0-bdff-8eca0446edd7.json +1 -0
  8. package/dist/client/_nuxt/entry.16c420c7.js +137 -0
  9. package/dist/client/_nuxt/entry.47aab0b4.css +1 -0
  10. package/dist/client/_nuxt/{error-404.214d08e9.js → error-404.26fce296.js} +1 -1
  11. package/dist/client/_nuxt/{error-500.f9a9234a.js → error-500.89729d99.js} +1 -1
  12. package/dist/client/index.html +5 -5
  13. package/dist/module.d.mts +46 -27
  14. package/dist/module.d.ts +46 -27
  15. package/dist/module.json +2 -2
  16. package/dist/module.mjs +195 -103
  17. package/dist/runtime/cache.d.ts +7 -10
  18. package/dist/runtime/cache.mjs +40 -27
  19. package/dist/runtime/components/OgImage/OgImage.d.ts +5 -0
  20. package/dist/runtime/components/OgImage/{index.mjs → OgImage.mjs} +1 -1
  21. package/dist/runtime/components/OgImage/OgImageScreenshot.d.ts +5 -0
  22. package/dist/runtime/components/OgImage/{Screenshot.mjs → OgImageScreenshot.mjs} +1 -1
  23. package/dist/runtime/components/Templates/{Official → Community}/BrandedLogo.vue +3 -2
  24. package/dist/runtime/components/Templates/Community/Nuxt.vue +6 -5
  25. package/dist/runtime/components/Templates/Community/NuxtSeo.vue +137 -0
  26. package/dist/runtime/components/Templates/{Official → Community}/SimpleBlog.vue +7 -5
  27. package/dist/runtime/components/Templates/Community/UnJs.vue +108 -0
  28. package/dist/runtime/components/Templates/{Official → Community}/Wave.vue +3 -2
  29. package/dist/runtime/components/Templates/{Official → Community}/WithEmoji.vue +3 -2
  30. package/dist/runtime/composables/defineOgImage.d.ts +2 -23
  31. package/dist/runtime/composables/defineOgImage.mjs +33 -116
  32. package/dist/runtime/composables/defineOgImageComponent.d.ts +3 -0
  33. package/dist/runtime/composables/defineOgImageComponent.mjs +8 -0
  34. package/dist/runtime/composables/defineOgImageScreenshot.d.ts +2 -0
  35. package/dist/runtime/composables/defineOgImageScreenshot.mjs +14 -0
  36. package/dist/runtime/core/bindings/css-inline/node.d.ts +2 -5
  37. package/dist/runtime/core/bindings/css-inline/node.mjs +2 -10
  38. package/dist/runtime/core/bindings/resvg/stackblitz.d.ts +40 -0
  39. package/dist/runtime/core/bindings/resvg/stackblitz.mjs +6 -0
  40. package/dist/runtime/core/bindings/resvg/wasm.mjs +2 -3
  41. package/dist/runtime/core/bindings/satori/stackblitz.mjs +13 -0
  42. package/dist/runtime/core/bindings/satori/wasm.d.ts +6 -0
  43. package/dist/runtime/core/bindings/satori/wasm.mjs +14 -0
  44. package/dist/runtime/core/cache/emojis.d.ts +1 -0
  45. package/dist/runtime/core/cache/emojis.mjs +5 -0
  46. package/dist/runtime/core/cache/htmlPayload.d.ts +5 -0
  47. package/dist/runtime/core/cache/htmlPayload.mjs +6 -0
  48. package/dist/runtime/core/cache/prerender.d.ts +1 -1
  49. package/dist/runtime/core/cache/prerender.mjs +1 -1
  50. package/dist/runtime/core/env/assets.d.ts +0 -1
  51. package/dist/runtime/core/env/assets.mjs +0 -4
  52. package/dist/runtime/core/font/fetch.d.ts +2 -3
  53. package/dist/runtime/core/font/fetch.mjs +32 -15
  54. package/dist/runtime/core/html/applyEmojis.d.ts +3 -0
  55. package/dist/runtime/core/html/applyEmojis.mjs +37 -0
  56. package/dist/runtime/core/html/applyInlineCss.d.ts +3 -0
  57. package/dist/runtime/core/html/applyInlineCss.mjs +32 -0
  58. package/dist/runtime/core/html/devIframeTemplate.d.ts +2 -0
  59. package/dist/runtime/core/html/{fetch.mjs → devIframeTemplate.mjs} +33 -42
  60. package/dist/runtime/core/html/fetchIsland.d.ts +3 -0
  61. package/dist/runtime/core/html/fetchIsland.mjs +17 -0
  62. package/dist/runtime/core/options/fetch.d.ts +1 -1
  63. package/dist/runtime/core/options/fetch.mjs +10 -5
  64. package/dist/runtime/core/options/normalise.d.ts +2 -2
  65. package/dist/runtime/core/options/normalise.mjs +3 -2
  66. package/dist/runtime/core/renderers/chromium/index.mjs +6 -7
  67. package/dist/runtime/core/renderers/chromium/screenshot.d.ts +2 -3
  68. package/dist/runtime/core/renderers/chromium/screenshot.mjs +8 -8
  69. package/dist/runtime/core/renderers/satori/fonts.d.ts +2 -2
  70. package/dist/runtime/core/renderers/satori/fonts.mjs +2 -2
  71. package/dist/runtime/core/renderers/satori/index.d.ts +2 -3
  72. package/dist/runtime/core/renderers/satori/index.mjs +26 -22
  73. package/dist/runtime/core/renderers/satori/instances.d.ts +3 -0
  74. package/dist/runtime/core/renderers/satori/instances.mjs +15 -0
  75. package/dist/runtime/core/renderers/satori/plugins/emojis.mjs +15 -13
  76. package/dist/runtime/core/renderers/satori/plugins/imageSrc.mjs +23 -10
  77. package/dist/runtime/core/renderers/satori/plugins/unocss.d.ts +2 -0
  78. package/dist/runtime/core/renderers/satori/plugins/unocss.mjs +45 -0
  79. package/dist/runtime/core/renderers/satori/utils.d.ts +2 -3
  80. package/dist/runtime/core/renderers/satori/vnodes.d.ts +2 -3
  81. package/dist/runtime/core/renderers/satori/vnodes.mjs +16 -6
  82. package/dist/runtime/core/utils/resolveRendererContext.d.ts +2 -6
  83. package/dist/runtime/core/utils/resolveRendererContext.mjs +47 -29
  84. package/dist/runtime/core/utils/wasm.d.ts +3 -0
  85. package/dist/runtime/core/utils/wasm.mjs +16 -0
  86. package/dist/runtime/nitro/plugins/nuxt-content.mjs +3 -4
  87. package/dist/runtime/nitro/plugins/prerender.d.ts +1 -1
  88. package/dist/runtime/nitro/plugins/prerender.mjs +20 -12
  89. package/dist/runtime/nitro/utils.d.ts +2 -0
  90. package/dist/runtime/nitro/utils.mjs +17 -0
  91. package/dist/runtime/nuxt/plugins/og-image-canonical-urls.server.mjs +31 -0
  92. package/dist/runtime/nuxt/plugins/route-rule-og-image.server.mjs +16 -50
  93. package/dist/runtime/nuxt/utils.d.ts +2 -0
  94. package/dist/runtime/nuxt/utils.mjs +53 -0
  95. package/dist/runtime/server/routes/__og-image__/debug.json.d.ts +1 -3
  96. package/dist/runtime/server/routes/__og-image__/debug.json.mjs +4 -8
  97. package/dist/runtime/server/routes/__og-image__/image.mjs +87 -0
  98. package/dist/runtime/types.d.ts +77 -25
  99. package/dist/runtime/utils.d.ts +4 -0
  100. package/dist/runtime/utils.mjs +11 -0
  101. package/dist/runtime/utils.pure.d.ts +5 -0
  102. package/dist/runtime/utils.pure.mjs +43 -0
  103. package/package.json +28 -30
  104. package/virtual.d.ts +49 -0
  105. package/dist/client/_nuxt/IconCSS.8f429b14.css +0 -1
  106. package/dist/client/_nuxt/builds/meta/0ca67bfd-95de-4c16-8f0a-055751cdca51.json +0 -1
  107. package/dist/client/_nuxt/entry.089f6f0f.js +0 -137
  108. package/dist/client/_nuxt/entry.434c2c45.css +0 -1
  109. package/dist/client/grid.png +0 -0
  110. package/dist/runtime/components/OgImage/Cached.d.ts +0 -5
  111. package/dist/runtime/components/OgImage/Cached.mjs +0 -10
  112. package/dist/runtime/components/OgImage/Dynamic.d.ts +0 -8
  113. package/dist/runtime/components/OgImage/Dynamic.mjs +0 -10
  114. package/dist/runtime/components/OgImage/Screenshot.d.ts +0 -6
  115. package/dist/runtime/components/OgImage/Static.d.ts +0 -8
  116. package/dist/runtime/components/OgImage/Static.mjs +0 -10
  117. package/dist/runtime/components/OgImage/WithoutCache.d.ts +0 -5
  118. package/dist/runtime/components/OgImage/WithoutCache.mjs +0 -10
  119. package/dist/runtime/components/OgImage/index.d.ts +0 -5
  120. package/dist/runtime/components/Templates/Official/Fallback.vue +0 -147
  121. package/dist/runtime/core/bindings/css-inline/mock.d.ts +0 -5
  122. package/dist/runtime/core/bindings/css-inline/mock.mjs +0 -3
  123. package/dist/runtime/core/bindings/satori/yoga-wasm.mjs +0 -7
  124. package/dist/runtime/core/bindings/sharp/wasm.d.ts +0 -2
  125. package/dist/runtime/core/bindings/sharp/wasm.mjs +0 -2
  126. package/dist/runtime/core/html/fetch.d.ts +0 -3
  127. package/dist/runtime/nuxt/plugins/nuxt-content-canonical-urls.mjs +0 -29
  128. package/dist/runtime/public-assets/__nuxt_og_image__/browser-provider-not-supported.png +0 -0
  129. package/dist/runtime/server/routes/__og-image__/image-[path]-og.[extension].mjs +0 -45
  130. package/dist/runtime/utilts.d.ts +0 -2
  131. package/dist/runtime/utilts.mjs +0 -8
  132. /package/dist/runtime/core/bindings/satori/{yoga-wasm.d.ts → stackblitz.d.ts} +0 -0
  133. /package/dist/runtime/nuxt/plugins/{nuxt-content-canonical-urls.d.ts → og-image-canonical-urls.server.d.ts} +0 -0
  134. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-400-normal.woff +0 -0
  135. /package/dist/runtime/{public-assets-optional/inter-font → server/assets}/inter-latin-ext-700-normal.woff +0 -0
  136. /package/dist/runtime/server/routes/__og-image__/{image-[path]-og.[extension].d.ts → image.d.ts} +0 -0
@@ -2,8 +2,9 @@ import { defu } from "defu";
2
2
  import { parseURL, withoutBase } from "ufo";
3
3
  import { createRouter as createRadixRouter, toRouteMatcher } from "radix3";
4
4
  import { normaliseOptions } from "../../core/options/normalise.mjs";
5
- import { getOgImagePath, isInternalRoute } from "../../utilts.mjs";
6
- import { defineNuxtPlugin, useRequestEvent, useRuntimeConfig } from "#imports";
5
+ import { getOgImagePath, isInternalRoute, useOgImageRuntimeConfig } from "../../utils.mjs";
6
+ import { createOgImageMeta } from "../utils.mjs";
7
+ import { defineNuxtPlugin, useRequestEvent } from "#imports";
7
8
  export default defineNuxtPlugin((nuxtApp) => {
8
9
  nuxtApp.hooks.hook("app:rendered", async (ctx) => {
9
10
  const { ssrContext } = ctx;
@@ -14,59 +15,24 @@ export default defineNuxtPlugin((nuxtApp) => {
14
15
  const _routeRulesMatcher = toRouteMatcher(
15
16
  createRadixRouter({ routes: ssrContext?.runtimeConfig?.nitro?.routeRules })
16
17
  );
17
- const routeRules = defu({}, ..._routeRulesMatcher.matchAll(
18
+ let routeRules = defu({}, ..._routeRulesMatcher.matchAll(
18
19
  withoutBase(path.split("?")[0], ssrContext?.runtimeConfig?.app.baseURL)
19
20
  ).reverse()).ogImage;
20
21
  if (typeof routeRules === "undefined")
21
22
  return;
22
- const payloadIndex = ssrContext.head.headEntries().findIndex((entry) => {
23
- return entry.input?.script?.[0]?.id === "nuxt-og-image-options";
24
- });
25
- if (payloadIndex >= 0 && routeRules === false) {
26
- ssrContext.head.headEntries().splice(payloadIndex, 1);
23
+ const ogImageInstances = nuxtApp.ssrContext._ogImageInstances || [];
24
+ if (routeRules === false) {
25
+ ogImageInstances?.forEach((e2) => {
26
+ e2.dispose();
27
+ });
28
+ nuxtApp.ssrContext._ogImagePayload = void 0;
29
+ nuxtApp.ssrContext._ogImageInstances = void 0;
27
30
  return;
28
31
  }
29
- if (payloadIndex >= 0)
30
- return;
31
- const options = normaliseOptions(routeRules);
32
- const { defaults } = useRuntimeConfig()["nuxt-og-image"];
33
- const optionsWithDefault = normaliseOptions(defu(options, defaults));
34
- const src = getOgImagePath(ssrContext.url, optionsWithDefault.extension);
35
- ssrContext?.head.push({
36
- script: [
37
- {
38
- id: "nuxt-og-image-options",
39
- type: "application/json",
40
- processTemplateParams: true,
41
- innerHTML: () => {
42
- const payload = {
43
- title: "%s"
44
- };
45
- Object.entries(options).forEach(([key, val]) => {
46
- payload[key.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = val;
47
- });
48
- return payload;
49
- },
50
- // we want this to be last in our head
51
- tagPosition: "bodyClose"
52
- }
53
- ],
54
- meta: [
55
- { property: "og:image", content: src },
56
- { property: "og:image:width", content: optionsWithDefault.width },
57
- { property: "og:image:height", content: optionsWithDefault.height },
58
- { property: "og:image:type", content: `image/${optionsWithDefault.extension}` },
59
- { property: "og:image:alt", content: optionsWithDefault.alt },
60
- // twitter
61
- { name: "twitter:card", content: "summary_large_image" },
62
- { name: "twitter:image:src", content: src },
63
- { name: "twitter:image:width", content: optionsWithDefault.width },
64
- { name: "twitter:image:height", content: optionsWithDefault.height },
65
- { name: "twitter:image:alt", content: optionsWithDefault.alt }
66
- ]
67
- }, {
68
- mode: "server",
69
- tagPriority: 35
70
- });
32
+ routeRules = defu(nuxtApp.ssrContext?.event.context._nitro?.routeRules?.ogImage, routeRules);
33
+ const { defaults } = useOgImageRuntimeConfig();
34
+ const resolvedOptions = normaliseOptions(defu(routeRules, defaults));
35
+ const src = getOgImagePath(ssrContext.url, resolvedOptions);
36
+ createOgImageMeta(src, routeRules, resolvedOptions, nuxtApp.ssrContext);
71
37
  });
72
38
  });
@@ -0,0 +1,2 @@
1
+ import type { OgImageOptions, OgImagePrebuilt } from '../types';
2
+ export declare function createOgImageMeta(src: string | null, input: OgImageOptions | OgImagePrebuilt, resolvedOptions: OgImageOptions, ssrContext: Record<string, any>): void;
@@ -0,0 +1,53 @@
1
+ import { defu } from "defu";
2
+ import { separateProps } from "../utils.mjs";
3
+ import { useServerHead } from "#imports";
4
+ export function createOgImageMeta(src, input, resolvedOptions, ssrContext) {
5
+ const _input = separateProps(defu(input, ssrContext._ogImagePayload));
6
+ const url = src || input.url || resolvedOptions.url;
7
+ let urlExtension = (url.split("/").pop() || url).split(".").pop() || resolvedOptions.extension;
8
+ if (urlExtension === "jpg")
9
+ urlExtension = "jpeg";
10
+ const meta = [
11
+ { property: "og:image", content: url },
12
+ { property: "og:image:type", content: `image/${urlExtension}` },
13
+ { name: "twitter:card", content: "summary_large_image" },
14
+ { name: "twitter:image:src", content: url }
15
+ ];
16
+ if (resolvedOptions.width) {
17
+ meta.push({ property: "og:image:width", content: resolvedOptions.width });
18
+ meta.push({ name: "twitter:image:width", content: resolvedOptions.width });
19
+ }
20
+ if (resolvedOptions.height) {
21
+ meta.push({ property: "og:image:height", content: resolvedOptions.height });
22
+ meta.push({ name: "twitter:image:height", content: resolvedOptions.height });
23
+ }
24
+ if (resolvedOptions.alt) {
25
+ meta.push({ property: "og:image:alt", content: resolvedOptions.alt });
26
+ meta.push({ name: "twitter:image:alt", content: resolvedOptions.alt });
27
+ }
28
+ ssrContext._ogImageInstances = ssrContext._ogImageInstances || [];
29
+ const script = [];
30
+ if (src) {
31
+ script.push({
32
+ id: "nuxt-og-image-options",
33
+ type: "application/json",
34
+ processTemplateParams: true,
35
+ innerHTML: () => {
36
+ if (!_input.props.title)
37
+ _input.props.title = "%s";
38
+ delete _input.url;
39
+ return _input;
40
+ },
41
+ // we want this to be last in our head
42
+ tagPosition: "bodyClose"
43
+ });
44
+ }
45
+ const instance = useServerHead({
46
+ script,
47
+ meta
48
+ }, {
49
+ tagPriority: 35
50
+ });
51
+ ssrContext._ogImagePayload = _input;
52
+ ssrContext._ogImageInstances.push(instance);
53
+ }
@@ -4,8 +4,6 @@ declare const _default: import("h3").EventHandler<import("h3").EventHandlerReque
4
4
  source: any;
5
5
  };
6
6
  componentNames: any;
7
- runtimeConfig: any;
8
- baseCacheKey: string;
9
- cachedKeys: string[];
7
+ runtimeConfig: import("../../../types").OgImageRuntimeConfig;
10
8
  }>>;
11
9
  export default _default;
@@ -1,21 +1,17 @@
1
1
  import { defineEventHandler, setHeader } from "h3";
2
- import { prefixStorage } from "unstorage";
3
- import { useRuntimeConfig, useSiteConfig, useStorage } from "#imports";
2
+ import { useOgImageRuntimeConfig } from "../../../utils.mjs";
3
+ import { useSiteConfig } from "#imports";
4
4
  import { componentNames } from "#nuxt-og-image/component-names.mjs";
5
5
  export default defineEventHandler(async (e) => {
6
6
  setHeader(e, "Content-Type", "application/json");
7
- const runtimeConfig = useRuntimeConfig()["nuxt-og-image"];
7
+ const runtimeConfig = useOgImageRuntimeConfig();
8
8
  const siteConfig = await useSiteConfig(e, { debug: true });
9
- const baseCacheKey = runtimeConfig.runtimeCacheStorage === "default" ? `/cache/nuxt-og-image@${runtimeConfig.version}` : `/nuxt-og-image@${runtimeConfig.version}`;
10
- const cache = prefixStorage(useStorage(), `${baseCacheKey}/`);
11
9
  return {
12
10
  siteConfigUrl: {
13
11
  value: siteConfig.url,
14
12
  source: siteConfig._context.url || "unknown"
15
13
  },
16
14
  componentNames,
17
- runtimeConfig,
18
- baseCacheKey,
19
- cachedKeys: await cache.getKeys()
15
+ runtimeConfig
20
16
  };
21
17
  });
@@ -0,0 +1,87 @@
1
+ import { H3Error, createError, defineEventHandler, getQuery, setHeader } from "h3";
2
+ import { resolveRendererContext } from "../../../core/utils/resolveRendererContext.mjs";
3
+ import { fetchIsland } from "../../../core/html/fetchIsland.mjs";
4
+ import { devIframeTemplate } from "../../../core/html/devIframeTemplate.mjs";
5
+ import { applyInlineCss } from "../../../core/html/applyInlineCss.mjs";
6
+ import { useOgImageBufferCache } from "../../../cache.mjs";
7
+ import { useOgImageRuntimeConfig } from "../../../utils.mjs";
8
+ import { useSiteConfig } from "#imports";
9
+ export default defineEventHandler(async (e) => {
10
+ const ctx = await resolveRendererContext(e);
11
+ if (ctx instanceof H3Error)
12
+ return ctx;
13
+ const { isDebugJsonPayload, extension, options, renderer } = ctx;
14
+ const { debug, baseCacheKey } = useOgImageRuntimeConfig();
15
+ const compatibility = [];
16
+ if (isDebugJsonPayload) {
17
+ const queryExtension = getQuery(e).extension || ctx.options.extension;
18
+ if (["jpeg", "jpg"].includes(queryExtension) && options.renderer === "satori")
19
+ compatibility.push("Converting PNGs to JPEGs requires Sharp which only runs on Node based systems.");
20
+ if (options.renderer === "chromium")
21
+ compatibility.push("Using Chromium to generate images is only supported in Node based environments. It's recommended to only use this if you're prerendering");
22
+ if (await applyInlineCss(ctx, await fetchIsland(ctx)))
23
+ compatibility.push("Inlining CSS is only supported in Node based environments.");
24
+ setHeader(e, "Content-Type", "application/json");
25
+ return {
26
+ compatibility,
27
+ ...ctx,
28
+ siteConfig: useSiteConfig(e),
29
+ ...options.renderer === "satori" ? await renderer.debug(ctx) : void 0
30
+ };
31
+ }
32
+ switch (extension) {
33
+ case "html":
34
+ setHeader(e, "Content-Type", `text/html`);
35
+ return devIframeTemplate(ctx);
36
+ case "svg":
37
+ if (!debug && !import.meta.dev) {
38
+ return createError({
39
+ statusCode: 404
40
+ });
41
+ }
42
+ if (ctx.renderer.name !== "satori") {
43
+ return createError({
44
+ statusCode: 400,
45
+ statusMessage: `Generating ${extension}'s with ${renderer.name} is not supported.`
46
+ });
47
+ }
48
+ setHeader(e, "Content-Type", `image/svg+xml`);
49
+ return (await ctx.renderer.debug(ctx)).svg;
50
+ case "png":
51
+ case "jpeg":
52
+ case "jpg":
53
+ if (!renderer.supportedFormats.includes(extension)) {
54
+ return createError({
55
+ statusCode: 400,
56
+ statusMessage: `Generating ${extension}'s with ${renderer.name} is not supported.`
57
+ });
58
+ }
59
+ setHeader(e, "Content-Type", `image/${extension === "jpg" ? "jpeg" : extension}`);
60
+ break;
61
+ default:
62
+ return createError({
63
+ statusCode: 400,
64
+ statusMessage: `Invalid request for og.${extension}.`
65
+ });
66
+ }
67
+ const cacheApi = await useOgImageBufferCache(ctx, {
68
+ cacheMaxAgeSeconds: ctx.options.cacheMaxAgeSeconds,
69
+ baseCacheKey
70
+ });
71
+ if (typeof cacheApi === "undefined")
72
+ return;
73
+ let image = cacheApi.cachedItem;
74
+ if (!image) {
75
+ image = await renderer.createImage(ctx);
76
+ if (image instanceof H3Error)
77
+ return image;
78
+ if (!image) {
79
+ return createError({
80
+ statusCode: 500,
81
+ statusMessage: `Failed to generate og.${extension}.`
82
+ });
83
+ }
84
+ await cacheApi.update(image);
85
+ }
86
+ return image;
87
+ });
@@ -1,15 +1,42 @@
1
- /// <reference types="node" />
2
- import type { Buffer } from 'node:buffer';
3
1
  import type { html } from 'satori-html';
4
2
  import type { H3Error, H3Event } from 'h3';
5
3
  import type { ResvgRenderOptions } from '@resvg/resvg-js';
6
4
  import type { SatoriOptions } from 'satori';
5
+ import type { AllowedComponentProps, Component, ComponentCustomProps, VNodeProps } from '@vue/runtime-core';
6
+ import type { SharpOptions } from 'sharp';
7
+ import type { NitroApp } from 'nitropack';
8
+ import type { OgImageComponents } from '#nuxt-og-image/components';
9
+ export interface OgImageRenderEventContext {
10
+ e: H3Event;
11
+ extension: 'png' | 'jpeg' | 'jpg' | 'svg' | 'html' | 'json';
12
+ key: string;
13
+ basePath: string;
14
+ renderer: Renderer;
15
+ options: OgImageOptions;
16
+ isDebugJsonPayload: boolean;
17
+ _nitro: NitroApp;
18
+ }
19
+ export type IconifyEmojiIconSets = 'twemoji' | 'noto' | 'fluent-emoji' | 'fluent-emoji-flat' | 'fluent-emoji-high-contrast' | 'noto-v1' | 'emojione' | 'emojione-monotone' | 'emojione-v1' | 'streamline-emojis' | 'openmoji';
20
+ export interface OgImageRuntimeConfig {
21
+ version: string;
22
+ satoriOptions: SatoriOptions;
23
+ resvgOptions: ResvgRenderOptions;
24
+ sharpOptions: SharpOptions;
25
+ runtimeSatori: boolean;
26
+ runtimeChromium: boolean;
27
+ defaults: OgImageOptions;
28
+ debug: boolean;
29
+ baseCacheKey: string;
30
+ fonts: FontConfig[];
31
+ hasNuxtIcon: boolean;
32
+ colorPreference: 'light' | 'dark';
33
+ }
7
34
  export interface OgImageComponent {
8
35
  path?: string;
9
36
  pascalName: string;
10
37
  kebabName: string;
11
38
  hash: string;
12
- category: 'app' | 'official' | 'community' | 'pro';
39
+ category: 'app' | 'community' | 'pro';
13
40
  credits?: string;
14
41
  }
15
42
  export interface ScreenshotOptions {
@@ -33,49 +60,74 @@ export interface ScreenshotOptions {
33
60
  */
34
61
  delay?: number;
35
62
  }
36
- export interface OgImageOptions extends Partial<ScreenshotOptions> {
37
- component?: string;
38
- renderer?: 'chromium' | 'satori';
39
- extension?: 'png' | 'jpeg' | 'jpg';
63
+ export type OgImagePrebuilt = {
64
+ url: string;
65
+ } & Pick<OgImageOptions, 'width' | 'height' | 'alt'>;
66
+ export type DefineOgImageInput = OgImageOptions | OgImagePrebuilt | false;
67
+ export interface OgImageOptions<T extends keyof OgImageComponents = 'NuxtSeo'> {
68
+ /**
69
+ * The width of the screenshot.
70
+ *
71
+ * @default 1200
72
+ */
73
+ width?: number;
74
+ /**
75
+ * The height of the screenshot.
76
+ *
77
+ * @default 630
78
+ */
79
+ height?: number;
80
+ /**
81
+ * The alt text for the image.
82
+ */
83
+ alt?: string;
40
84
  /**
41
- * @deprecated use renderer. Replace `browser` with `chromium`
85
+ * Use a prebuilt image instead of generating one.
86
+ *
87
+ * Should be an absolute URL.
42
88
  */
43
- provider?: 'browser' | 'satori';
89
+ url?: string;
90
+ /**
91
+ * The name of the component to render.
92
+ */
93
+ component?: T | string;
94
+ /**
95
+ * Props to pass to the component.
96
+ */
97
+ props?: OgImageComponents[T] | Record<string, any>;
98
+ renderer?: 'chromium' | 'satori';
99
+ extension?: 'png' | 'jpeg' | 'jpg';
100
+ emojis?: IconifyEmojiIconSets;
44
101
  /**
45
102
  * Provide a static HTML template to render the OG Image instead of a component.
46
103
  */
47
104
  html?: string;
48
- cache?: boolean;
49
- cacheKey?: string;
50
105
  resvg?: ResvgRenderOptions;
51
106
  satori?: SatoriOptions;
52
- /**
53
- * The time to live of the cache in milliseconds.
54
- */
55
- cacheTtl?: number;
56
- [key: string]: any;
57
- }
58
- export interface RuntimeOgImageOptions extends Omit<OgImageOptions, 'extension'> {
59
- extension: 'png' | 'jpeg' | 'jpg' | 'svg' | 'json' | 'html';
60
- path: string;
107
+ screenshot?: Partial<ScreenshotOptions>;
108
+ sharp?: SharpOptions;
109
+ cacheMaxAgeSeconds?: number;
61
110
  }
62
111
  export interface FontConfig {
63
112
  name: string;
64
113
  weight: string | number;
65
114
  path?: string;
115
+ key?: string;
66
116
  }
67
117
  export type InputFontConfig = (`${string}:${number}` | FontConfig);
68
- export type RendererOptions = Omit<RuntimeOgImageOptions, 'extension'> & {
69
- extension: Omit<RuntimeOgImageOptions['extension'], 'html'>;
118
+ export type RendererOptions = Omit<OgImageOptions, 'extension'> & {
119
+ extension: Omit<OgImageOptions['extension'], 'html'>;
70
120
  };
71
121
  export interface Renderer {
72
122
  name: 'chromium' | 'satori';
73
123
  supportedFormats: Partial<RendererOptions['extension']>[];
74
- createImage: (e: H3Event, options: RendererOptions) => Promise<H3Error | Buffer>;
124
+ createImage: (e: OgImageRenderEventContext) => Promise<H3Error | BufferSource | void>;
125
+ debug: (e: OgImageRenderEventContext) => Promise<Record<string, any>>;
75
126
  }
76
- export type OgImageScreenshotOptions = Omit<OgImageOptions, 'component'>;
127
+ export type ExtractComponentProps<T extends Component> = T extends new (...args: any) => any ? Omit<InstanceType<T>['$props'], keyof ComponentCustomProps | keyof VNodeProps | keyof AllowedComponentProps> : never;
128
+ export type OgImagePageScreenshotOptions = Omit<OgImageOptions, 'html' | 'renderer' | 'component' | 'satori' | 'resvg' | 'sharp'>;
77
129
  export type VNode = ReturnType<typeof html>;
78
130
  export interface SatoriTransformer {
79
131
  filter: (node: VNode) => boolean;
80
- transform: (node: VNode, e: H3Event) => Promise<void>;
132
+ transform: (node: VNode, e: OgImageRenderEventContext) => Promise<void>;
81
133
  }
@@ -0,0 +1,4 @@
1
+ import type { OgImageOptions, OgImageRuntimeConfig } from './types';
2
+ export * from './utils.pure';
3
+ export declare function getOgImagePath(pagePath: string, _options?: Partial<OgImageOptions>): string;
4
+ export declare function useOgImageRuntimeConfig(): OgImageRuntimeConfig;
@@ -0,0 +1,11 @@
1
+ import { joinURL } from "ufo";
2
+ import { defu } from "defu";
3
+ import { useRuntimeConfig } from "#imports";
4
+ export * from "./utils.pure.mjs";
5
+ export function getOgImagePath(pagePath, _options) {
6
+ const options = defu(_options, useOgImageRuntimeConfig().defaults);
7
+ return joinURL("/__og-image__/image", pagePath, `og.${options.extension}`);
8
+ }
9
+ export function useOgImageRuntimeConfig() {
10
+ return useRuntimeConfig()["nuxt-og-image"];
11
+ }
@@ -0,0 +1,5 @@
1
+ import type { OgImageOptions } from './types';
2
+ export declare function isInternalRoute(path: string): boolean;
3
+ export declare function separateProps(options: OgImageOptions | undefined, ignoreKeys?: string[]): {
4
+ props: Record<string, any>;
5
+ };
@@ -0,0 +1,43 @@
1
+ import { defu } from "defu";
2
+ export function isInternalRoute(path) {
3
+ const lastSegment = path.split("/").pop() || path;
4
+ return lastSegment.includes(".") || path.startsWith("/__") || path.startsWith("@");
5
+ }
6
+ function filterIsOgImageOption(key) {
7
+ const keys = [
8
+ "url",
9
+ "extension",
10
+ "width",
11
+ "height",
12
+ "alt",
13
+ "props",
14
+ "renderer",
15
+ "html",
16
+ "component",
17
+ "renderer",
18
+ "emojis",
19
+ "satori",
20
+ "resvg",
21
+ "sharp",
22
+ "screenshot",
23
+ "cacheMaxAgeSeconds",
24
+ "componentHash"
25
+ ];
26
+ return keys.includes(key);
27
+ }
28
+ export function separateProps(options, ignoreKeys = []) {
29
+ options = options || {};
30
+ const _props = defu(options.props, Object.fromEntries(
31
+ Object.entries({ ...options }).filter(([k]) => !filterIsOgImageOption(k) && !ignoreKeys.includes(k))
32
+ ));
33
+ const props = {};
34
+ Object.entries(_props).forEach(([key, val]) => {
35
+ props[key.replace(/-([a-z])/g, (g) => g[1].toUpperCase())] = val;
36
+ });
37
+ return {
38
+ ...Object.fromEntries(
39
+ Object.entries({ ...options }).filter(([k]) => filterIsOgImageOption(k) || ignoreKeys.includes(k))
40
+ ),
41
+ props
42
+ };
43
+ }
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "nuxt-og-image",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.4",
4
+ "version": "3.0.0-beta.41",
5
5
  "packageManager": "pnpm@8.11.0",
6
6
  "description": "Enlightened OG Image generation for Nuxt.",
7
+ "author": {
8
+ "website": "https://harlanzw.com",
9
+ "name": "Harlan Wilton",
10
+ "url": "harlan@harlanzw.com"
11
+ },
7
12
  "license": "MIT",
8
13
  "funding": "https://github.com/sponsors/harlan-zw",
9
14
  "homepage": "https://github.com/harlan-zw/nuxt-og-image#readme",
@@ -24,75 +29,68 @@
24
29
  "main": "./dist/module.cjs",
25
30
  "types": "./dist/types.d.ts",
26
31
  "files": [
27
- "dist"
32
+ "dist",
33
+ "virtual.d.ts"
28
34
  ],
29
35
  "dependencies": {
30
- "@img/sharp-libvips-dev": "^1.0.0",
31
- "@img/sharp-wasm32": "0.33.0-rc.2",
36
+ "@iconify-json/noto": "^1.1.17",
32
37
  "@nuxt/devtools-kit": "^1.0.4",
33
38
  "@nuxt/kit": "^3.8.2",
34
39
  "@resvg/resvg-js": "^2.6.0",
35
40
  "@resvg/resvg-wasm": "^2.6.0",
36
- "@twemoji/api": "^14.1.2",
37
- "@types/fs-extra": "^11.0.4",
38
- "birpc": "0.2.14",
39
- "chalk": "^5.3.0",
41
+ "@unocss/core": "^0.58.0",
42
+ "@unocss/preset-wind": "^0.58.0",
43
+ "@vueuse/core": "^10.7.0",
40
44
  "chrome-launcher": "^1.1.0",
41
45
  "css-inline": "^0.11.0",
42
46
  "defu": "^6.1.3",
43
47
  "execa": "^8.0.1",
44
- "fast-glob": "^3.3.2",
45
- "flatted": "^3.2.9",
46
48
  "floating-vue": "2.0.0-beta.24",
47
- "fs-extra": "^11.2.0",
48
- "globby": "^14.0.0",
49
49
  "image-size": "^1.0.2",
50
- "launch-editor": "^2.6.1",
51
50
  "nuxt-site-config": "^1.6.6",
52
51
  "nuxt-site-config-kit": "^1.6.6",
53
52
  "nypm": "^0.3.3",
54
53
  "ofetch": "^1.3.3",
55
54
  "ohash": "^1.1.3",
56
55
  "pathe": "^1.1.1",
57
- "playwright-core": "^1.40.0",
56
+ "playwright-core": "^1.40.1",
58
57
  "radix3": "^1.1.0",
59
58
  "satori": "0.10.11",
60
59
  "satori-html": "^0.3.2",
61
- "sharp": "0.33.0-rc.2",
60
+ "sharp": "0.33.0",
62
61
  "sirv": "^2.0.3",
63
- "std-env": "^3.5.0",
64
- "svg2png-wasm": "^1.4.1",
62
+ "std-env": "^3.6.0",
65
63
  "terminate": "^2.6.1",
66
- "tinyws": "^0.1.0",
67
- "twemoji": "^14.0.2",
68
64
  "ufo": "^1.3.2",
69
- "vue-component-meta": "^1.8.22",
70
- "ws": "^8.14.2",
71
65
  "yoga-wasm-web": "^0.3.3"
72
66
  },
73
67
  "devDependencies": {
74
- "@antfu/eslint-config": "2.1.1",
75
- "@img/sharp-linux-x64": "0.33.0-rc.2",
68
+ "@antfu/eslint-config": "2.3.4",
69
+ "@img/sharp-linux-x64": "0.33.0",
76
70
  "@nuxt/content": "^2.9.0",
77
71
  "@nuxt/devtools": "1.0.4",
78
72
  "@nuxt/module-builder": "^0.5.4",
79
73
  "@nuxt/test-utils": "3.8.1",
74
+ "@nuxt/ui": "^2.11.0",
80
75
  "@nuxtjs/eslint-config-typescript": "^12.1.0",
81
- "@nuxtjs/i18n": "8.0.0-rc.5",
82
- "@types/ws": "^8.5.10",
76
+ "@nuxtjs/i18n": "8.0.0-rc.7",
77
+ "@nuxtjs/tailwindcss": "^6.10.1",
78
+ "@unocss/nuxt": "^0.58.0",
83
79
  "bumpp": "^9.2.0",
84
- "eslint": "8.54.0",
85
- "jest-image-snapshot": "^6.2.0",
80
+ "eslint": "8.55.0",
81
+ "jest-image-snapshot": "^6.3.0",
86
82
  "nuxt": "^3.8.2",
87
83
  "nuxt-icon": "0.6.6",
88
- "playwright": "^1.40.0",
84
+ "playwright": "^1.40.1",
89
85
  "sass": "^1.69.5",
90
- "vitest": "^0.34.6"
86
+ "vitest": "^1.0.1"
91
87
  },
92
88
  "build": {
93
89
  "externals": [
94
90
  "h3",
95
- "nitropack"
91
+ "nitropack",
92
+ "@vue/runtime-core",
93
+ "#nuxt-og-image/components"
96
94
  ]
97
95
  },
98
96
  "scripts": {
package/virtual.d.ts ADDED
@@ -0,0 +1,49 @@
1
+ declare module '#nuxt-og-image/components' {
2
+ import type { Component } from 'vue'
3
+
4
+ const components: Record<string, Component>
5
+ export default components
6
+ }
7
+ declare module '#nuxt-og-image/renderers/satori' {
8
+ import type Renderer from './src/runtime/types'
9
+
10
+ const renderer: Renderer | { __unenv__: true } | undefined
11
+ export default renderer
12
+ }
13
+ declare module '#nuxt-og-image/renderers/chromium' {
14
+ import type Renderer from './src/runtime/types'
15
+
16
+ const renderer: Renderer | { __unenv__: true } | undefined
17
+ export default renderer
18
+ }
19
+
20
+ declare module '#nuxt-og-image/bindings/satori' {
21
+ const satori: typeof import('satori').satori
22
+ export default satori
23
+ }
24
+
25
+ declare module '#nuxt-og-image/bindings/resvg' {
26
+ interface WasmResvg {
27
+ initWasmPromise: Promise<void>
28
+ Resvg: import('resvg').Resvg
29
+ }
30
+ const instance: WasmResvg
31
+ export default instance
32
+ }
33
+ declare module '#nuxt-og-image/bindings/chromium' {
34
+ export const createBrowser: () => Promise<Browser | void>
35
+ }
36
+
37
+ declare module '#nuxt-og-image/bindings/css-inline' {
38
+ import type _CssInline from 'css-inline'
39
+
40
+ const cssInline: _CssInline
41
+ export default cssInline
42
+ }
43
+
44
+ declare module '#nuxt-og-image/bindings/sharp' {
45
+ import type _sharp from 'sharp'
46
+
47
+ const sharp: _sharp
48
+ export default sharp
49
+ }
@@ -1 +0,0 @@
1
- span[data-v-2408e4e8]{background-color:currentColor;display:inline-block;-webkit-mask-image:var(--f4b1dbd8);mask-image:var(--f4b1dbd8);-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;vertical-align:middle}
@@ -1 +0,0 @@
1
- {"id":"0ca67bfd-95de-4c16-8f0a-055751cdca51","timestamp":1701183443673,"matcher":{"static":{},"wildcard":{},"dynamic":{}},"prerendered":[]}