nuxt-og-image 1.0.0-beta.10 → 1.0.0-beta.12

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 CHANGED
@@ -34,17 +34,10 @@ Enlightened OG Image generation for Nuxt 3.
34
34
 
35
35
  ## Features
36
36
 
37
- ## 🎨 Designer - Satori & Browser
38
-
39
37
  - 🎨 Design your `og:image` in the Og Image Playground with full HMR
40
- - Dynamically serve on the edge using Satori
41
- - Prerender static images using Satori or the browser
42
-
43
- ## Screenshots - Browser
44
-
45
- - 📸 OR just generate screenshots
46
- - ⚙️ Screenshot options to hide elements, wait for animations, and more
47
-
38
+ - Blazing fast Satori provider: Tailwind classes, Google fonts, emojis
39
+ - 🤖 Alternative Browser provider for painless, complex templates OR just generate screenshots
40
+ - 📸 Feeling lazy? Just generate screenshots, hide elements, wait for animations, and more
48
41
 
49
42
  ## Install
50
43
 
package/dist/module.d.ts CHANGED
@@ -39,9 +39,7 @@ interface ModuleOptions {
39
39
  host: string;
40
40
  defaults: OgImageOptions;
41
41
  experimentalNitroBrowser: boolean;
42
- satoriFonts: Array<Partial<SatoriOptions['fonts'][number]> & {
43
- publicPath: string;
44
- }>;
42
+ fonts: `${string}:${number}`[];
45
43
  satoriOptions: Partial<SatoriOptions>;
46
44
  forcePrerender: boolean;
47
45
  }
package/dist/module.json CHANGED
@@ -5,5 +5,5 @@
5
5
  "bridge": false
6
6
  },
7
7
  "configKey": "ogImage",
8
- "version": "1.0.0-beta.10"
8
+ "version": "1.0.0-beta.12"
9
9
  }
package/dist/module.mjs CHANGED
@@ -179,25 +179,14 @@ const module = defineNuxtModule({
179
179
  width: 1200,
180
180
  height: 630
181
181
  },
182
- satoriFonts: [
183
- {
184
- name: "Inter",
185
- weight: 400,
186
- style: "normal",
187
- publicPath: "/inter-latin-ext-400-normal.woff"
188
- },
189
- {
190
- name: "Inter",
191
- weight: 700,
192
- style: "normal",
193
- publicPath: "/inter-latin-ext-700-normal.woff"
194
- }
195
- ],
182
+ fonts: [],
196
183
  satoriOptions: {}
197
184
  };
198
185
  },
199
186
  async setup(config, nuxt) {
200
187
  const { resolve } = createResolver(import.meta.url);
188
+ if (!config.fonts.length)
189
+ config.fonts = ["Inter:400", "Inter:700"];
201
190
  const distResolve = (p) => {
202
191
  const cwd = resolve(".");
203
192
  if (cwd.endsWith("/dist"))
@@ -233,6 +222,10 @@ export {}
233
222
  handler: resolve(`./runtime/nitro/routes/__og_image__/${type}`)
234
223
  });
235
224
  });
225
+ addServerHandler({
226
+ route: "/api/og-image-font",
227
+ handler: resolve("./runtime/nitro/routes/__og_image__/font")
228
+ });
236
229
  if (nuxt.options.dev) {
237
230
  const playgroundDir = distResolve("./client");
238
231
  const {
@@ -274,8 +267,6 @@ export {}
274
267
  nitroConfig.externals = defu(nitroConfig.externals || {}, {
275
268
  inline: [runtimeDir]
276
269
  });
277
- nitroConfig.publicAssets = nitroConfig.publicAssets || [];
278
- nitroConfig.publicAssets.push({ dir: resolve("./runtime/public"), maxAge: 31536e3 });
279
270
  nitroConfig.virtual["#nuxt-og-image/browser"] = `export { createBrowser } from '${runtimeDir}/nitro/browsers/${isEdge ? "lambda" : "default"}'`;
280
271
  nitroConfig.virtual["#nuxt-og-image/provider"] = `
281
272
  import satori from '${runtimeDir}/nitro/providers/satori'
@@ -3,12 +3,12 @@ import satori from "satori";
3
3
  import { parseURL } from "ufo";
4
4
  import { Resvg } from "@resvg/resvg-js";
5
5
  import twemoji from "twemoji";
6
- import { parseFont, walkSatoriTree } from "./utils.mjs";
6
+ import { loadFont, walkSatoriTree } from "./utils.mjs";
7
7
  import imageSrc from "./plugins/imageSrc.mjs";
8
8
  import twClasses from "./plugins/twClasses.mjs";
9
9
  import flex from "./plugins/flex.mjs";
10
10
  import emojis from "./plugins/emojis.mjs";
11
- import { satoriFonts, satoriOptions } from "#nuxt-og-image/config";
11
+ import { fonts, satoriOptions } from "#nuxt-og-image/config";
12
12
  export default {
13
13
  name: "satori",
14
14
  createPng: async function createPng(baseUrl, options) {
@@ -26,8 +26,8 @@ export default {
26
26
  ext: ".svg"
27
27
  });
28
28
  satoriOptions.fonts = satoriOptions.fonts || [];
29
- for (const font of satoriFonts)
30
- satoriOptions.fonts.push(await parseFont(url, font));
29
+ for (const font of fonts)
30
+ satoriOptions.fonts.push(await loadFont(url, font));
31
31
  const satoriTree = convertHtmlToSatori(emojiedFont);
32
32
  await walkSatoriTree(url, satoriTree, [
33
33
  emojis(url),
@@ -1,10 +1,5 @@
1
- import type { SatoriOptions } from 'satori';
2
1
  import type { ParsedURL } from 'ufo';
3
2
  import type { SatoriTransformer, VNode } from '../../../../types';
4
- export declare function parseFont(url: ParsedURL, font: SatoriOptions['fonts'][number] & {
5
- publicPath?: string;
6
- }): Promise<import("satori").Font & {
7
- publicPath?: string | undefined;
8
- }>;
3
+ export declare function loadFont(url: ParsedURL, font: string): Promise<any>;
9
4
  export declare function walkSatoriTree(url: ParsedURL, node: VNode, plugins: SatoriTransformer[]): Promise<void>;
10
5
  export declare function defineSatoriTransformer(transformer: (url: ParsedURL) => SatoriTransformer): (url: ParsedURL) => SatoriTransformer;
@@ -1,19 +1,24 @@
1
- import { fileURLToPath } from "node:url";
2
- import { promises as fsp } from "node:fs";
3
- import { dirname, resolve } from "pathe";
4
- import { withBase } from "ufo";
5
- import { getAsset } from "#internal/nitro/virtual/public-assets";
6
- export async function parseFont(url, font) {
7
- if (typeof font.publicPath === "string") {
8
- const file = getAsset(font.publicPath);
9
- if (file) {
10
- const serverDir = dirname(fileURLToPath(import.meta.url));
11
- font.data = await fsp.readFile(resolve(serverDir, file.path));
12
- }
13
- if (!font.data)
14
- font.data = await (await $fetch(withBase(font.publicPath, `${url.protocol}//${url.host}`))).arrayBuffer();
1
+ import { useStorage } from "#internal/nitro";
2
+ const cachedFonts = {};
3
+ export async function loadFont(url, font) {
4
+ if (cachedFonts[font])
5
+ return cachedFonts[font];
6
+ const [name, weight] = font.split(":");
7
+ const fontUrl = await $fetch("/api/og-image-font", {
8
+ query: { name, weight }
9
+ });
10
+ let data;
11
+ const storageKey = `nuxt-og-image:font:${font}`;
12
+ const hasStoredFont = await useStorage().hasItem(storageKey);
13
+ if (!hasStoredFont) {
14
+ data = await $fetch(fontUrl, {
15
+ responseType: "arrayBuffer"
16
+ });
17
+ await useStorage().setItem(storageKey, data);
18
+ } else {
19
+ data = await useStorage().getItem(storageKey);
15
20
  }
16
- return font;
21
+ return cachedFonts[font] = { name, weight, data, style: "normal" };
17
22
  }
18
23
  export async function walkSatoriTree(url, node, plugins) {
19
24
  if (!node.props?.children)
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,14 @@
1
+ import { getQuery } from "h3";
2
+ import { defineCachedEventHandler } from "#internal/nitro";
3
+ export default defineCachedEventHandler(async (e) => {
4
+ const { name, weight } = getQuery(e);
5
+ const css = await await $fetch(`https://fonts.googleapis.com/css2?family=${name || "Inter"}:wght@${weight || 400}`, {
6
+ headers: {
7
+ "User-Agent": "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; de-at) AppleWebKit/533.21.1 (KHTML, like Gecko) Version/5.0.5 Safari/533.21.1"
8
+ }
9
+ });
10
+ const resource = css.match(/src: url\((.+)\) format\('(opentype|truetype)'\)/);
11
+ if (!resource)
12
+ return;
13
+ return resource[1];
14
+ });
@@ -3,7 +3,7 @@ import { renderSSRHead } from "@unhead/ssr";
3
3
  import { createHeadCore } from "@unhead/vue";
4
4
  import { defineEventHandler, getQuery, sendRedirect } from "h3";
5
5
  import { fetchOptions, renderIsland, useHostname } from "../../utils.mjs";
6
- import { defaults } from "#nuxt-og-image/config";
6
+ import { defaults, fonts } 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"))
@@ -19,7 +19,7 @@ export default defineEventHandler(async (e) => {
19
19
  head.push({
20
20
  style: [
21
21
  {
22
- innerHTML: "body { font-family: 'Inter', sans-serif; }"
22
+ innerHTML: `body { font-family: '${fonts[0].split(":")[0].replace("+", " ")}', sans-serif; }`
23
23
  },
24
24
  scale ? {
25
25
  innerHTML: `body {
@@ -58,10 +58,13 @@ img.emoji {
58
58
  href: "https://cdn.jsdelivr.net/npm/gardevoir",
59
59
  rel: "stylesheet"
60
60
  },
61
- {
62
- href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap",
63
- rel: "stylesheet"
64
- }
61
+ ...fonts.map((font) => {
62
+ const [name, weight] = font.split(":");
63
+ return {
64
+ href: `https://fonts.googleapis.com/css2?family=${name}:wght@${weight}&display=swap`,
65
+ rel: "stylesheet"
66
+ };
67
+ })
65
68
  ]
66
69
  });
67
70
  const headChunk = await renderSSRHead(head);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-og-image",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.10",
4
+ "version": "1.0.0-beta.12",
5
5
  "packageManager": "pnpm@7.8.0",
6
6
  "license": "MIT",
7
7
  "funding": "https://github.com/sponsors/harlan-zw",