nuxt-og-image 2.0.0-beta.43 → 2.0.0-beta.46

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 (36) hide show
  1. package/README.md +5 -0
  2. package/dist/client/200.html +2 -2
  3. package/dist/client/404.html +2 -2
  4. package/dist/client/_nuxt/{IconCSS.b113975e.js → IconCSS.d8cd5733.js} +1 -1
  5. package/dist/client/_nuxt/{ImageLoader.b3f2fdfd.js → ImageLoader.3019a38e.js} +1 -1
  6. package/dist/client/_nuxt/{entry.c23ed2b6.js → entry.329bb907.js} +2 -2
  7. package/dist/client/_nuxt/{error-404.0002113d.js → error-404.ca83b642.js} +1 -1
  8. package/dist/client/_nuxt/{error-500.171ba3b2.js → error-500.bbb9f8d8.js} +1 -1
  9. package/dist/client/_nuxt/{error-component.bbb20371.js → error-component.ed0ea6d4.js} +2 -2
  10. package/dist/client/_nuxt/{index.b33d70ad.js → index.9dd699b9.js} +1 -1
  11. package/dist/client/_nuxt/{options.446a167e.js → options.406afdd7.js} +1 -1
  12. package/dist/client/_nuxt/{png.2c1d3085.js → png.0aee24aa.js} +1 -1
  13. package/dist/client/_nuxt/{shiki.caf1a928.js → shiki.faa60705.js} +1 -1
  14. package/dist/client/_nuxt/{svg.01d38cc1.js → svg.299f4cde.js} +1 -1
  15. package/dist/client/_nuxt/{vnodes.dbfaa416.js → vnodes.5ffe0cf0.js} +1 -1
  16. package/dist/client/index.html +2 -2
  17. package/dist/client/options/index.html +2 -2
  18. package/dist/client/png/index.html +2 -2
  19. package/dist/client/svg/index.html +2 -2
  20. package/dist/client/vnodes/index.html +2 -2
  21. package/dist/module.d.ts +5 -4
  22. package/dist/module.json +1 -1
  23. package/dist/module.mjs +15 -4
  24. package/dist/runtime/components/OgImageBasic.island.vue +5 -0
  25. package/dist/runtime/nitro/renderers/satori/index.mjs +1 -9
  26. package/dist/runtime/nitro/renderers/satori/plugins/emojis.d.ts +1 -1
  27. package/dist/runtime/nitro/renderers/satori/plugins/emojis.mjs +24 -9
  28. package/dist/runtime/nitro/renderers/satori/plugins/encoding.d.ts +1 -1
  29. package/dist/runtime/nitro/renderers/satori/plugins/flex.d.ts +1 -1
  30. package/dist/runtime/nitro/renderers/satori/plugins/imageSrc.d.ts +1 -1
  31. package/dist/runtime/nitro/renderers/satori/plugins/twClasses.d.ts +1 -1
  32. package/dist/runtime/nitro/renderers/satori/utils.d.ts +2 -2
  33. package/dist/runtime/nitro/renderers/satori/utils.mjs +2 -2
  34. package/dist/runtime/nitro/routes/html.mjs +49 -20
  35. package/dist/runtime/nitro/util-hostname.mjs +7 -2
  36. package/package.json +10 -8
@@ -1,13 +1,28 @@
1
1
  import { defineSatoriTransformer } from "../utils.mjs";
2
+ function isEmojiFilter(node) {
3
+ return node.type === "img" && node.props?.class?.includes("emoji");
4
+ }
2
5
  export default defineSatoriTransformer(() => {
3
- return {
4
- filter: (node) => node.type === "img" && node.props?.class?.includes("emoji"),
5
- transform: async (node) => {
6
- node.props.style = node.props.style || {};
7
- node.props.style.height = "1em";
8
- node.props.style.width = "1em";
9
- node.props.style.margin = "0 .05em 0 .1em";
10
- node.props.style.verticalAlign = "0.1em";
6
+ return [
7
+ // need to make sure parent div has flex for the emoji to render inline
8
+ {
9
+ filter: (node) => node.type === "div" && Array.isArray(node.props?.children) && node.props.children.some(isEmojiFilter),
10
+ transform: async (node) => {
11
+ node.props.style = node.props.style || {};
12
+ node.props.style.display = "flex";
13
+ node.props.style.alignItems = "center";
14
+ }
15
+ },
16
+ {
17
+ filter: isEmojiFilter,
18
+ transform: async (node) => {
19
+ node.props.style = node.props.style || {};
20
+ node.props.style.height = "1em";
21
+ node.props.style.width = "1em";
22
+ node.props.style.margin = "0 .3em 0 .3em";
23
+ node.props.style.verticalAlign = "0.1em";
24
+ node.props.class = "";
25
+ }
11
26
  }
12
- };
27
+ ];
13
28
  });
@@ -1,2 +1,2 @@
1
- declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer;
1
+ declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer | import("../../../../../types").SatoriTransformer[];
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer;
1
+ declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer | import("../../../../../types").SatoriTransformer[];
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer;
1
+ declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer | import("../../../../../types").SatoriTransformer[];
2
2
  export default _default;
@@ -1,2 +1,2 @@
1
- declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer;
1
+ declare const _default: (url: import("ufo").ParsedURL) => import("../../../../../types").SatoriTransformer | import("../../../../../types").SatoriTransformer[];
2
2
  export default _default;
@@ -1,5 +1,5 @@
1
1
  import type { ParsedURL } from 'ufo';
2
2
  import type { FontConfig, SatoriTransformer, VNode } from '../../../../types';
3
3
  export declare function loadFont(baseURL: string, font: FontConfig): Promise<any>;
4
- export declare function walkSatoriTree(url: ParsedURL, node: VNode, plugins: SatoriTransformer[]): Promise<void>;
5
- export declare function defineSatoriTransformer(transformer: (url: ParsedURL) => SatoriTransformer): (url: ParsedURL) => SatoriTransformer;
4
+ export declare function walkSatoriTree(url: ParsedURL, node: VNode, plugins: (SatoriTransformer | SatoriTransformer[])[]): Promise<void>;
5
+ export declare function defineSatoriTransformer(transformer: (url: ParsedURL) => SatoriTransformer | SatoriTransformer[]): (url: ParsedURL) => SatoriTransformer | SatoriTransformer[];
@@ -16,7 +16,7 @@ export async function loadFont(baseURL, font) {
16
16
  if (!data && name === "Inter" && ["400", "700"].includes(weight)) {
17
17
  data = await readPublicAsset(`/inter-latin-ext-${weight}-normal.woff`);
18
18
  }
19
- if (typeof font === "object") {
19
+ if (font.path) {
20
20
  data = await readPublicAsset(font.path);
21
21
  if (!data) {
22
22
  try {
@@ -49,7 +49,7 @@ export async function walkSatoriTree(url, node, plugins) {
49
49
  }
50
50
  for (const child of node.props.children || []) {
51
51
  if (child) {
52
- for (const plugin of plugins) {
52
+ for (const plugin of plugins.flat()) {
53
53
  if (plugin.filter(child))
54
54
  await plugin.transform(child);
55
55
  }
@@ -3,6 +3,8 @@ import { renderSSRHead } from "@unhead/ssr";
3
3
  import { createHeadCore } from "@unhead/vue";
4
4
  import { createError, defineEventHandler, getQuery, sendRedirect } from "h3";
5
5
  import { hash } from "ohash";
6
+ import twemoji from "twemoji";
7
+ import inlineCss from "inline-css";
6
8
  import { fetchOptions, useHostname } from "../utils.mjs";
7
9
  import { useRuntimeConfig } from "#imports";
8
10
  export default defineEventHandler(async (e) => {
@@ -40,11 +42,15 @@ export default defineEventHandler(async (e) => {
40
42
  head.push(island.head);
41
43
  let defaultFontFamily = "sans-serif";
42
44
  const firstFont = fonts[0];
43
- if (firstFont) {
44
- if (typeof firstFont === "string")
45
- defaultFontFamily = firstFont.split(":")[0];
46
- else
47
- defaultFontFamily = firstFont.name;
45
+ if (firstFont)
46
+ defaultFontFamily = firstFont.name;
47
+ let html = island.html;
48
+ try {
49
+ html = twemoji.parse(html, {
50
+ folder: "svg",
51
+ ext: ".svg"
52
+ });
53
+ } catch (e2) {
48
54
  }
49
55
  head.push({
50
56
  style: [
@@ -52,9 +58,9 @@ export default defineEventHandler(async (e) => {
52
58
  // default font is the first font family
53
59
  innerHTML: `body { font-family: '${defaultFontFamily.replace("+", " ")}', sans-serif; }`
54
60
  },
55
- scale ? {
61
+ {
56
62
  innerHTML: `body {
57
- transform: scale(${scale});
63
+ transform: scale(${scale || 1});
58
64
  transform-origin: top left;
59
65
  max-height: 100vh;
60
66
  position: relative;
@@ -68,17 +74,15 @@ img.emoji {
68
74
  width: 1em;
69
75
  margin: 0 .05em 0 .1em;
70
76
  vertical-align: -0.1em;
71
- }
72
- `
73
- } : {},
74
- ...fonts.filter((font) => typeof font === "object").map((font) => {
75
- const { name, weight, path: path2 } = font;
77
+ }`
78
+ },
79
+ ...fonts.filter((font) => font.path).map((font) => {
76
80
  return `
77
81
  @font-face {
78
- font-family: '${name}';
82
+ font-family: '${font.name}';
79
83
  font-style: normal;
80
- font-weight: ${weight};
81
- src: url('${path2}') format('truetype');
84
+ font-weight: ${font.weight};
85
+ src: url('${font.path}') format('truetype');
82
86
  }
83
87
  `;
84
88
  })
@@ -108,19 +112,44 @@ img.emoji {
108
112
  rel: "stylesheet"
109
113
  },
110
114
  // have to add each weight as their own stylesheet
111
- ...fonts.filter((font) => typeof font === "string").map((font) => {
112
- const [name, weight] = font.split(":");
115
+ ...fonts.filter((font) => !font.path).map((font) => {
113
116
  return {
114
- href: `https://fonts.googleapis.com/css2?family=${name}:wght@${weight}&display=swap`,
117
+ href: `https://fonts.googleapis.com/css2?family=${font.name}:wght@${font.weight}&display=swap`,
115
118
  rel: "stylesheet"
116
119
  };
117
120
  })
118
121
  ]
119
122
  });
120
123
  const headChunk = await renderSSRHead(head);
121
- return `<!DOCTYPE html>
124
+ let htmlTemplate = `<!DOCTYPE html>
122
125
  <html ${headChunk.htmlAttrs}>
123
126
  <head>${headChunk.headTags}</head>
124
- <body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="position: relative; display: flex; margin: 0 auto; width: 1200px; height: 630px;">${island.html}</div>${headChunk.bodyTags}</body>
127
+ <body ${headChunk.bodyAttrs}>${headChunk.bodyTagsOpen}<div style="position: relative; display: flex; margin: 0 auto; width: 1200px; height: 630px;">${html}</div>${headChunk.bodyTags}</body>
125
128
  </html>`;
129
+ const stylesheets = htmlTemplate.match(/<link rel="stylesheet" href=".*">/g);
130
+ if (stylesheets) {
131
+ for (const stylesheet of stylesheets) {
132
+ const href = stylesheet.match(/<link rel="stylesheet" href="(.*)">/)[1];
133
+ try {
134
+ if (stylesheet.includes("@nuxt/ui-templates")) {
135
+ htmlTemplate = htmlTemplate.replace(stylesheet, "");
136
+ } else {
137
+ const css = (await (await $fetch(href, {
138
+ baseURL: useHostname(e)
139
+ })).text()).replace(/\/\/# sourceMappingURL=.*/, "");
140
+ htmlTemplate = htmlTemplate.replace(stylesheet, `<style>${css}</style>`);
141
+ }
142
+ } catch {
143
+ }
144
+ }
145
+ }
146
+ try {
147
+ htmlTemplate = inlineCss(htmlTemplate, {
148
+ url: useHostname(e),
149
+ applyLinkTags: false,
150
+ removeLinkTags: false
151
+ });
152
+ } catch {
153
+ }
154
+ return htmlTemplate;
126
155
  });
@@ -1,12 +1,17 @@
1
1
  import { getRequestHost, getRequestProtocol } from "h3";
2
- import { withBase } from "ufo";
2
+ import { withBase, withoutProtocol } from "ufo";
3
3
  import { useRuntimeConfig } from "#imports";
4
4
  export function useHostname(e) {
5
5
  const base = useRuntimeConfig().app.baseURL;
6
6
  let host = getRequestHost(e);
7
7
  if (host === "localhost")
8
8
  host = process.env.NITRO_HOST || process.env.HOST || host;
9
- const protocol = getRequestProtocol(e);
9
+ let protocol = getRequestProtocol(e);
10
+ if (process.env.NUXT_VITE_NODE_OPTIONS) {
11
+ const envHost = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS).baseURL.replace("__nuxt_vite_node__", "");
12
+ host = withoutProtocol(envHost);
13
+ protocol = envHost.includes("https") ? "https" : "http";
14
+ }
10
15
  const useHttp = process.dev || host.includes("127.0.0.1") || host.includes("localhost") || protocol === "http";
11
16
  let port = host.includes(":") ? host.split(":").pop() : false;
12
17
  if ((process.dev || process.env.prerender || host.includes("localhost")) && !port)
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "nuxt-og-image",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.43",
4
+ "version": "2.0.0-beta.46",
5
5
  "packageManager": "pnpm@8.6.0",
6
6
  "license": "MIT",
7
7
  "funding": "https://github.com/sponsors/harlan-zw",
@@ -26,7 +26,7 @@
26
26
  "dist"
27
27
  ],
28
28
  "dependencies": {
29
- "@nuxt/kit": "^3.5.2",
29
+ "@nuxt/kit": "^3.5.3",
30
30
  "@resvg/resvg-js": "^2.4.1",
31
31
  "@resvg/resvg-wasm": "^2.4.1",
32
32
  "@types/fs-extra": "^11.0.1",
@@ -39,15 +39,17 @@
39
39
  "flatted": "^3.2.7",
40
40
  "fs-extra": "^11.1.1",
41
41
  "globby": "^13.1.4",
42
+ "inline-css": "^4.0.2",
42
43
  "launch-editor": "^2.6.0",
43
44
  "nuxt-icon": "^0.4.1",
45
+ "nuxt-site-config": "^0.2.1",
44
46
  "nypm": "^0.2.0",
45
47
  "ofetch": "^1.0.1",
46
48
  "ohash": "^1.1.2",
47
49
  "pathe": "^1.1.1",
48
50
  "playwright-core": "^1.34.3",
49
51
  "radix3": "^1.0.1",
50
- "satori": "0.9.1",
52
+ "satori": "0.10.1",
51
53
  "satori-html": "^0.3.2",
52
54
  "sirv": "^2.0.3",
53
55
  "std-env": "^3.3.3",
@@ -59,16 +61,16 @@
59
61
  "yoga-wasm-web": "^0.3.3"
60
62
  },
61
63
  "devDependencies": {
62
- "@antfu/eslint-config": "^0.39.4",
63
- "@nuxt/devtools-edge": "0.5.5-28092324.8333e19",
64
+ "@antfu/eslint-config": "^0.39.5",
65
+ "@nuxt/devtools-edge": "0.5.5-28099668.306c6a5",
64
66
  "@nuxt/module-builder": "^0.4.0",
65
- "@nuxt/test-utils": "3.5.2",
67
+ "@nuxt/test-utils": "3.5.3",
66
68
  "@nuxtjs/eslint-config-typescript": "^12.0.0",
67
69
  "@types/ws": "^8.5.4",
68
- "bumpp": "^9.1.0",
70
+ "bumpp": "^9.1.1",
69
71
  "eslint": "8.42.0",
70
72
  "jest-image-snapshot": "^6.1.0",
71
- "nuxt": "^3.5.2",
73
+ "nuxt": "^3.5.3",
72
74
  "vitest": "^0.31.4"
73
75
  },
74
76
  "resolutions": {