nuxt-og-image 6.7.2 → 6.7.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/dist/chunks/tw4.cjs +7 -7
- package/dist/chunks/tw4.mjs +7 -7
- package/dist/chunks/uno.cjs +6 -6
- package/dist/chunks/uno.mjs +6 -6
- package/dist/cli.cjs +5 -12
- package/dist/cli.mjs +3 -10
- package/dist/devtools/lib/og-image/shared/urlEncoding.ts +5 -4
- package/dist/module.cjs +5 -5
- package/dist/module.json +1 -1
- package/dist/module.mjs +5 -5
- package/dist/runtime/app/plugins/__zero-runtime/og-image-canonical-urls.server.js +4 -6
- package/dist/runtime/app/plugins/__zero-runtime/route-rule-og-image.server.js +4 -6
- package/dist/runtime/app/plugins/og-image-canonical-urls.server.d.ts +1 -2
- package/dist/runtime/app/plugins/og-image-canonical-urls.server.js +1 -7
- package/dist/runtime/app/plugins/route-rule-og-image.server.d.ts +1 -2
- package/dist/runtime/app/plugins/route-rule-og-image.server.js +1 -7
- package/dist/runtime/app/utils/plugins.d.ts +2 -3
- package/dist/runtime/app/utils/plugins.js +5 -5
- package/dist/runtime/server/og-image/context.js +6 -5
- package/dist/runtime/server/routes/resolve.js +3 -2
- package/dist/runtime/server/util/cache.js +5 -4
- package/dist/runtime/server/util/kit.js +2 -2
- package/dist/runtime/server/util/query.d.ts +7 -0
- package/dist/runtime/server/util/query.js +4 -0
- package/dist/runtime/shared/hash.d.ts +10 -0
- package/dist/runtime/shared/hash.js +5 -0
- package/dist/runtime/shared/urlEncoding.d.ts +3 -2
- package/dist/runtime/shared/urlEncoding.js +9 -9
- package/dist/shared/{nuxt-og-image.BCK8Adm4.cjs → nuxt-og-image.BRBtdkUp.cjs} +570 -81
- package/dist/shared/{nuxt-og-image.Pfj5JkJd.mjs → nuxt-og-image.Bv8VSGTj.mjs} +499 -10
- package/dist/shared/nuxt-og-image.CJa2KCie.mjs +189 -0
- package/dist/shared/nuxt-og-image.CMYbz66P.cjs +193 -0
- package/package.json +46 -44
- package/types/virtual.d.ts +9 -0
- package/dist/shared/nuxt-og-image.DQkJQHaN.cjs +0 -689
- package/dist/shared/nuxt-og-image.LgUGeaz-.mjs +0 -660
|
@@ -6,17 +6,19 @@ const promises = require('node:fs/promises');
|
|
|
6
6
|
const node_url = require('node:url');
|
|
7
7
|
const kit = require('@nuxt/kit');
|
|
8
8
|
const defu = require('defu');
|
|
9
|
-
const
|
|
10
|
-
const
|
|
9
|
+
const fnv1a64 = require('fnv1a-64');
|
|
10
|
+
const kit$2 = require('nuxt-site-config/kit');
|
|
11
11
|
const pathe = require('pathe');
|
|
12
12
|
const pkgTypes = require('pkg-types');
|
|
13
13
|
const stdEnv = require('std-env');
|
|
14
14
|
const oxcWalker = require('oxc-walker');
|
|
15
|
-
const
|
|
15
|
+
const kit$1 = require('nuxtseo-shared/kit');
|
|
16
|
+
const logger_js = require('../../dist/runtime/logger.js');
|
|
17
|
+
const chromeLauncher = require('chrome-launcher');
|
|
18
|
+
const nypm = require('nypm');
|
|
16
19
|
const devtools = require('nuxtseo-shared/devtools');
|
|
17
20
|
const unstorage = require('unstorage');
|
|
18
21
|
const fsDriver = require('unstorage/drivers/fs-lite');
|
|
19
|
-
const logger_js = require('../../dist/runtime/logger.js');
|
|
20
22
|
const css_js = require('../../dist/runtime/server/og-image/utils/css.js');
|
|
21
23
|
const MagicString = require('magic-string');
|
|
22
24
|
const stripLiteral = require('strip-literal');
|
|
@@ -27,7 +29,7 @@ const ofetch = require('ofetch');
|
|
|
27
29
|
const ultrahtml = require('ultrahtml');
|
|
28
30
|
const emojiUtils_js = require('../../dist/runtime/server/og-image/core/transforms/emojis/emoji-utils.js');
|
|
29
31
|
const exsolve = require('exsolve');
|
|
30
|
-
const
|
|
32
|
+
const fonts = require('./nuxt-og-image.CMYbz66P.cjs');
|
|
31
33
|
|
|
32
34
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
33
35
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
|
|
@@ -48,6 +50,276 @@ const fs__namespace = /*#__PURE__*/_interopNamespaceCompat(fs);
|
|
|
48
50
|
const fsDriver__default = /*#__PURE__*/_interopDefaultCompat(fsDriver);
|
|
49
51
|
const MagicString__default = /*#__PURE__*/_interopDefaultCompat(MagicString);
|
|
50
52
|
|
|
53
|
+
const isUndefinedOrTruthy = (v) => typeof v === "undefined" || v !== false;
|
|
54
|
+
function checkLocalChrome() {
|
|
55
|
+
if (stdEnv.isCI)
|
|
56
|
+
return false;
|
|
57
|
+
let hasChromeLocally = false;
|
|
58
|
+
try {
|
|
59
|
+
hasChromeLocally = !!chromeLauncher.Launcher.getFirstInstallation();
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
return hasChromeLocally;
|
|
63
|
+
}
|
|
64
|
+
async function hasResolvableDependency(dep) {
|
|
65
|
+
return await kit.resolvePath(dep, { fallbackToOriginal: true }).catch(() => null).then((r) => r && r !== dep);
|
|
66
|
+
}
|
|
67
|
+
const VALID_RENDERER_SUFFIXES = ["satori", "browser", "takumi"];
|
|
68
|
+
const RE_RENDERER_SUFFIX_CI = /\.?(satori|browser|takumi)$/i;
|
|
69
|
+
const RE_RENDERER_SUFFIX = /(Satori|Browser|Takumi)$/;
|
|
70
|
+
const RE_LEGACY_SUFFIX = /-legacy$/;
|
|
71
|
+
const RE_WHITESPACE = /\s+/;
|
|
72
|
+
function getRendererFromFilename(filepath) {
|
|
73
|
+
const filename = pathe.basename(filepath).replace(".vue", "");
|
|
74
|
+
for (const suffix of VALID_RENDERER_SUFFIXES) {
|
|
75
|
+
if (filename.endsWith(`.${suffix}`))
|
|
76
|
+
return suffix;
|
|
77
|
+
}
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const OGIMAGE_PREFIXES = [
|
|
81
|
+
{ prefix: "OgImageCommunity", overlapWord: "Community" },
|
|
82
|
+
{ prefix: "OgImageTemplate", overlapWord: "Template" },
|
|
83
|
+
{ prefix: "OgImage", overlapWord: "Image" }
|
|
84
|
+
];
|
|
85
|
+
function getRegisteredBaseNames(registeredPascalName) {
|
|
86
|
+
const stripped = registeredPascalName.replace(RE_RENDERER_SUFFIX_CI, "").replace(RE_RENDERER_SUFFIX, "");
|
|
87
|
+
const names = [];
|
|
88
|
+
for (const { prefix, overlapWord } of OGIMAGE_PREFIXES) {
|
|
89
|
+
if (!stripped.startsWith(prefix))
|
|
90
|
+
continue;
|
|
91
|
+
const withoutPrefix = stripped.slice(prefix.length);
|
|
92
|
+
if (withoutPrefix) {
|
|
93
|
+
names.push(withoutPrefix);
|
|
94
|
+
if (withoutPrefix !== overlapWord)
|
|
95
|
+
names.push(overlapWord + withoutPrefix);
|
|
96
|
+
} else {
|
|
97
|
+
names.push(overlapWord);
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
if (names.length === 0)
|
|
102
|
+
names.push(stripped);
|
|
103
|
+
return names;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const NodeRuntime = {
|
|
107
|
+
// node-server runtime
|
|
108
|
+
browser: "on-demand",
|
|
109
|
+
// this gets changed build start
|
|
110
|
+
resvg: "node",
|
|
111
|
+
satori: "node",
|
|
112
|
+
takumi: "node",
|
|
113
|
+
sharp: "node",
|
|
114
|
+
// will be disabled if they're missing the dependency
|
|
115
|
+
emoji: "local"
|
|
116
|
+
// can bundle icons, no size constraints
|
|
117
|
+
};
|
|
118
|
+
const NodeDevRuntime = {
|
|
119
|
+
...NodeRuntime,
|
|
120
|
+
resvg: "node-dev",
|
|
121
|
+
// use worker to prevent crashes from killing process
|
|
122
|
+
takumi: "node-dev"
|
|
123
|
+
// use worker to prevent crashes from killing process
|
|
124
|
+
};
|
|
125
|
+
const NodePrerenderRuntime = {
|
|
126
|
+
...NodeRuntime,
|
|
127
|
+
resvg: "node-dev",
|
|
128
|
+
// use worker to prevent crashes from killing prerender process
|
|
129
|
+
takumi: "node-dev"
|
|
130
|
+
// use worker to prevent crashes from killing prerender process
|
|
131
|
+
};
|
|
132
|
+
const cloudflare = {
|
|
133
|
+
browser: "cloudflare",
|
|
134
|
+
resvg: "wasm",
|
|
135
|
+
satori: "wasm",
|
|
136
|
+
takumi: "wasm",
|
|
137
|
+
sharp: false,
|
|
138
|
+
emoji: "fetch",
|
|
139
|
+
// edge size limits - use API instead of bundling 24MB icons
|
|
140
|
+
wasm: {
|
|
141
|
+
esmImport: true
|
|
142
|
+
// Do NOT set lazy here — Nitro's cloudflare preset uses lazy: false because
|
|
143
|
+
// CF Workers require WASM modules to be imported eagerly via top-level await
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
const awsLambda = {
|
|
147
|
+
browser: false,
|
|
148
|
+
resvg: "node",
|
|
149
|
+
satori: "node",
|
|
150
|
+
takumi: "node",
|
|
151
|
+
sharp: false,
|
|
152
|
+
// 0.33.x has issues
|
|
153
|
+
emoji: "local"
|
|
154
|
+
// serverless has larger size limits
|
|
155
|
+
};
|
|
156
|
+
const WebContainer = {
|
|
157
|
+
browser: false,
|
|
158
|
+
resvg: "wasm-fs",
|
|
159
|
+
satori: "wasm-fs",
|
|
160
|
+
takumi: "wasm",
|
|
161
|
+
sharp: false,
|
|
162
|
+
emoji: "fetch"
|
|
163
|
+
// webcontainer has size constraints
|
|
164
|
+
};
|
|
165
|
+
const RuntimeCompatibility = {
|
|
166
|
+
"nitro-dev": NodeDevRuntime,
|
|
167
|
+
"nitro-prerender": NodePrerenderRuntime,
|
|
168
|
+
"node-server": NodeRuntime,
|
|
169
|
+
"node-cluster": NodeRuntime,
|
|
170
|
+
"node-listener": NodeRuntime,
|
|
171
|
+
"bun": NodeRuntime,
|
|
172
|
+
"deno-server": NodeRuntime,
|
|
173
|
+
"deno-deploy": NodeRuntime,
|
|
174
|
+
// node-server extending presets
|
|
175
|
+
"alwaysdata": NodeRuntime,
|
|
176
|
+
"cleavr": NodeRuntime,
|
|
177
|
+
"digital-ocean": NodeRuntime,
|
|
178
|
+
"edgio": NodeRuntime,
|
|
179
|
+
"flight-control": NodeRuntime,
|
|
180
|
+
"heroku": NodeRuntime,
|
|
181
|
+
"iis-handler": NodeRuntime,
|
|
182
|
+
"iis-node": NodeRuntime,
|
|
183
|
+
"koyeb": NodeRuntime,
|
|
184
|
+
"platform-sh": NodeRuntime,
|
|
185
|
+
"render-com": NodeRuntime,
|
|
186
|
+
"zeabur": NodeRuntime,
|
|
187
|
+
"zerops": NodeRuntime,
|
|
188
|
+
"stackblitz": WebContainer,
|
|
189
|
+
"codesandbox": WebContainer,
|
|
190
|
+
"aws-amplify": awsLambda,
|
|
191
|
+
"aws-lambda": awsLambda,
|
|
192
|
+
"azure": awsLambda,
|
|
193
|
+
"azure-functions": awsLambda,
|
|
194
|
+
"azure-swa": awsLambda,
|
|
195
|
+
"netlify": awsLambda,
|
|
196
|
+
"netlify-edge": {
|
|
197
|
+
browser: false,
|
|
198
|
+
resvg: "wasm",
|
|
199
|
+
satori: "node",
|
|
200
|
+
takumi: "wasm",
|
|
201
|
+
sharp: false,
|
|
202
|
+
emoji: "fetch",
|
|
203
|
+
// edge size limits
|
|
204
|
+
wasm: {
|
|
205
|
+
rollup: {
|
|
206
|
+
targetEnv: "auto-inline",
|
|
207
|
+
sync: ["@resvg/resvg-wasm/index_bg.wasm"]
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
"firebase": awsLambda,
|
|
212
|
+
"firebase-app-hosting": awsLambda,
|
|
213
|
+
"genezio": awsLambda,
|
|
214
|
+
"stormkit": awsLambda,
|
|
215
|
+
"vercel": awsLambda,
|
|
216
|
+
"vercel-edge": {
|
|
217
|
+
browser: false,
|
|
218
|
+
resvg: "wasm",
|
|
219
|
+
satori: "wasm",
|
|
220
|
+
takumi: "wasm",
|
|
221
|
+
sharp: false,
|
|
222
|
+
emoji: "fetch",
|
|
223
|
+
// edge size limits - bundling 24MB icons not viable
|
|
224
|
+
wasm: {
|
|
225
|
+
// lowers workers kb size
|
|
226
|
+
esmImport: true,
|
|
227
|
+
lazy: true
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
"cloudflare-pages": cloudflare,
|
|
231
|
+
"cloudflare-pages-static": cloudflare,
|
|
232
|
+
"cloudflare": cloudflare,
|
|
233
|
+
"cloudflare-module": cloudflare,
|
|
234
|
+
"cloudflare-durable": cloudflare
|
|
235
|
+
};
|
|
236
|
+
function resolveOgImagePreset(nitroConfig) {
|
|
237
|
+
const nuxt = kit.useNuxt();
|
|
238
|
+
if (nuxt.options.dev)
|
|
239
|
+
return "nitro-dev";
|
|
240
|
+
if (nuxt.options.nitro.static)
|
|
241
|
+
return "nitro-prerender";
|
|
242
|
+
return kit$1.resolveNitroPreset(nitroConfig);
|
|
243
|
+
}
|
|
244
|
+
function getPresetNitroPresetCompatibility(target) {
|
|
245
|
+
const normalizedTarget = target.replace(RE_LEGACY_SUFFIX, "");
|
|
246
|
+
let compatibility = RuntimeCompatibility[normalizedTarget];
|
|
247
|
+
if (!compatibility) {
|
|
248
|
+
logger_js.logger.warn(`Unknown Nitro preset "${target}" \u2014 falling back to node-server compatibility. Set ogImage.compatibility.runtime to override.`);
|
|
249
|
+
compatibility = NodeRuntime;
|
|
250
|
+
}
|
|
251
|
+
return compatibility;
|
|
252
|
+
}
|
|
253
|
+
async function applyNitroPresetCompatibility(nitroConfig, options) {
|
|
254
|
+
const target = resolveOgImagePreset(nitroConfig);
|
|
255
|
+
const compatibility = getPresetNitroPresetCompatibility(target);
|
|
256
|
+
const { resolve, detectedRenderers } = options;
|
|
257
|
+
const satoriEnabled = detectedRenderers.has("satori");
|
|
258
|
+
const browserEnabled = detectedRenderers.has("browser");
|
|
259
|
+
const takumiEnabled = detectedRenderers.has("takumi");
|
|
260
|
+
for (const renderer of detectedRenderers) {
|
|
261
|
+
if (!compatibility[renderer]) {
|
|
262
|
+
logger_js.logger.warn(`Renderer "${renderer}" detected but not supported on "${target}" preset. OG images using .${renderer}.vue components may fail.`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const emptyMock = await resolve.resolvePath("./runtime/mock/empty");
|
|
266
|
+
nitroConfig.alias["#og-image/renderers/satori"] = satoriEnabled ? await resolve.resolvePath("./runtime/server/og-image/satori/renderer") : emptyMock;
|
|
267
|
+
nitroConfig.alias["#og-image/renderers/browser"] = browserEnabled ? await resolve.resolvePath("./runtime/server/og-image/browser/renderer") : emptyMock;
|
|
268
|
+
nitroConfig.alias["#og-image/renderers/takumi"] = takumiEnabled ? await resolve.resolvePath("./runtime/server/og-image/takumi/renderer") : emptyMock;
|
|
269
|
+
const resolvedCompatibility = { ...options.metadata || {} };
|
|
270
|
+
async function applyBinding(key) {
|
|
271
|
+
let binding = options.compatibility?.[key];
|
|
272
|
+
if (typeof binding === "undefined")
|
|
273
|
+
binding = compatibility[key];
|
|
274
|
+
const isRendererBinding = key === "browser" || key === "satori" || key === "takumi";
|
|
275
|
+
if (isRendererBinding && !detectedRenderers.has(key)) {
|
|
276
|
+
binding = false;
|
|
277
|
+
}
|
|
278
|
+
resolvedCompatibility[key] = binding;
|
|
279
|
+
if (!binding && isRendererBinding) {
|
|
280
|
+
nitroConfig.alias[`#og-image/renderers/${key}`] = emptyMock;
|
|
281
|
+
}
|
|
282
|
+
return {
|
|
283
|
+
[`#og-image/bindings/${key}`]: !binding ? emptyMock : await resolve.resolvePath(`./runtime/server/og-image/bindings/${key}/${binding}`)
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const satoriPkgDir = await resolve.resolvePath("satori/package.json").then((p) => p.replace("/package.json", ""));
|
|
287
|
+
const yogaWasmPath = `${satoriPkgDir}/yoga.wasm`;
|
|
288
|
+
nitroConfig.alias = defu.defu(
|
|
289
|
+
{ "#og-image/yoga-wasm": `${yogaWasmPath}?module` },
|
|
290
|
+
await applyBinding("browser"),
|
|
291
|
+
await applyBinding("satori"),
|
|
292
|
+
await applyBinding("takumi"),
|
|
293
|
+
await applyBinding("resvg"),
|
|
294
|
+
await applyBinding("sharp"),
|
|
295
|
+
nitroConfig.alias || {}
|
|
296
|
+
);
|
|
297
|
+
if (Object.values(resolvedCompatibility).includes("wasm")) {
|
|
298
|
+
nitroConfig.experimental = nitroConfig.experimental || {};
|
|
299
|
+
nitroConfig.experimental.wasm = true;
|
|
300
|
+
}
|
|
301
|
+
nitroConfig.rollupConfig = nitroConfig.rollupConfig || {};
|
|
302
|
+
nitroConfig.wasm = defu.defu(compatibility.wasm, nitroConfig.wasm);
|
|
303
|
+
nitroConfig.virtual["#og-image/compatibility"] = () => `export default ${JSON.stringify(resolvedCompatibility)}`;
|
|
304
|
+
kit.addTemplate({
|
|
305
|
+
filename: "nuxt-og-image/compatibility.mjs",
|
|
306
|
+
getContents() {
|
|
307
|
+
return `export default ${JSON.stringify(resolvedCompatibility)}`;
|
|
308
|
+
},
|
|
309
|
+
options: { mode: "server" }
|
|
310
|
+
});
|
|
311
|
+
return resolvedCompatibility;
|
|
312
|
+
}
|
|
313
|
+
async function ensureDependencies(dep, nuxt = kit.useNuxt()) {
|
|
314
|
+
const { ensureDependencyInstalled } = await import('nypm');
|
|
315
|
+
return Promise.all(dep.map((d) => {
|
|
316
|
+
return ensureDependencyInstalled(d, {
|
|
317
|
+
cwd: nuxt.options.rootDir,
|
|
318
|
+
dev: true
|
|
319
|
+
});
|
|
320
|
+
}));
|
|
321
|
+
}
|
|
322
|
+
|
|
51
323
|
const RE_REFLECT_HAS_MINIFIED = /Reflect\.has\(([\w$]+),([\w$]+)\)\?Reflect\.get\(\1,\2,([\w$]+)\):Reflect\.get\(([\w$]+),\2,\3\)/g;
|
|
52
324
|
const RE_WASM_IMPORT = /import\("(\.\/wasm\/[^"]+\.wasm)"\)/g;
|
|
53
325
|
async function setupBuildHandler(config, resolve, getDetectedRenderers, getCompatibilityMeta = () => ({}), nuxt = kit.useNuxt()) {
|
|
@@ -70,9 +342,9 @@ async function setupBuildHandler(config, resolve, getDetectedRenderers, getCompa
|
|
|
70
342
|
});
|
|
71
343
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
72
344
|
const renderers = getDetectedRenderers();
|
|
73
|
-
await
|
|
74
|
-
const target =
|
|
75
|
-
const normalizedTarget = target.replace(
|
|
345
|
+
await applyNitroPresetCompatibility(nitro.options, { compatibility: config.compatibility?.runtime, resolve, detectedRenderers: renderers, metadata: getCompatibilityMeta() });
|
|
346
|
+
const target = resolveOgImagePreset(nitro.options);
|
|
347
|
+
const normalizedTarget = target.replace(RE_LEGACY_SUFFIX, "");
|
|
76
348
|
const isEdgePreset = ["cloudflare", "cloudflare-pages", "cloudflare-pages-static", "cloudflare-module", "cloudflare-durable", "vercel-edge", "netlify-edge"].includes(normalizedTarget);
|
|
77
349
|
const isCloudflarePreset = normalizedTarget.startsWith("cloudflare");
|
|
78
350
|
const isCloudflarePagesOrModule = ["cloudflare-pages", "cloudflare-pages-static", "cloudflare-module", "cloudflare-durable"].includes(normalizedTarget);
|
|
@@ -84,7 +356,7 @@ async function setupBuildHandler(config, resolve, getDetectedRenderers, getCompa
|
|
|
84
356
|
nitro.options.cloudflare.pages.routes.exclude.push("/_og/s/*");
|
|
85
357
|
}
|
|
86
358
|
nitro.hooks.hook("compiled", async (_nitro) => {
|
|
87
|
-
const compatibility =
|
|
359
|
+
const compatibility = getPresetNitroPresetCompatibility(target);
|
|
88
360
|
if (!isEdgePreset)
|
|
89
361
|
return;
|
|
90
362
|
const configuredEntry = nitro.options.rollupConfig?.output.entryFileNames;
|
|
@@ -203,19 +475,211 @@ function patchWebAssemblyInstantiate(code) {
|
|
|
203
475
|
return code;
|
|
204
476
|
}
|
|
205
477
|
|
|
478
|
+
const TAKUMI_CORE_PACKAGE = "@takumi-rs/core";
|
|
479
|
+
const TAKUMI_WASM_PACKAGE = "@takumi-rs/wasm";
|
|
480
|
+
const PROVIDER_DEPENDENCIES = [
|
|
481
|
+
{
|
|
482
|
+
name: "satori",
|
|
483
|
+
description: "SVG-based renderer using Satori",
|
|
484
|
+
bindings: {
|
|
485
|
+
"node": [
|
|
486
|
+
{ name: "satori", description: "HTML to SVG renderer" },
|
|
487
|
+
{ name: "@resvg/resvg-js", description: "SVG to PNG converter (native)" }
|
|
488
|
+
],
|
|
489
|
+
"wasm": [
|
|
490
|
+
{ name: "satori", description: "HTML to SVG renderer" },
|
|
491
|
+
{ name: "@resvg/resvg-wasm", description: "SVG to PNG converter (WASM)" }
|
|
492
|
+
],
|
|
493
|
+
"wasm-fs": [
|
|
494
|
+
{ name: "satori", description: "HTML to SVG renderer" },
|
|
495
|
+
{ name: "@resvg/resvg-wasm", description: "SVG to PNG converter (WASM)" }
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
},
|
|
499
|
+
{
|
|
500
|
+
name: "takumi",
|
|
501
|
+
description: "Rust-based high-performance renderer (recommended)",
|
|
502
|
+
bindings: {
|
|
503
|
+
"node": [
|
|
504
|
+
{ name: TAKUMI_CORE_PACKAGE, description: "Native Takumi renderer" }
|
|
505
|
+
],
|
|
506
|
+
"wasm": [
|
|
507
|
+
{ name: TAKUMI_WASM_PACKAGE, description: "WASM Takumi renderer" }
|
|
508
|
+
],
|
|
509
|
+
"wasm-fs": [
|
|
510
|
+
{ name: TAKUMI_WASM_PACKAGE, description: "WASM Takumi renderer" }
|
|
511
|
+
]
|
|
512
|
+
}
|
|
513
|
+
},
|
|
514
|
+
{
|
|
515
|
+
name: "browser",
|
|
516
|
+
description: "Browser-based screenshot renderer",
|
|
517
|
+
bindings: {
|
|
518
|
+
node: [
|
|
519
|
+
{ name: "playwright-core", description: "Headless browser automation" }
|
|
520
|
+
]
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
];
|
|
524
|
+
async function getInstalledProviders() {
|
|
525
|
+
const installed = [];
|
|
526
|
+
for (const provider of PROVIDER_DEPENDENCIES) {
|
|
527
|
+
if (provider.bindings.node) {
|
|
528
|
+
const allNodeInstalled = await Promise.all(
|
|
529
|
+
provider.bindings.node.map((dep) => hasResolvableDependency(dep.name))
|
|
530
|
+
);
|
|
531
|
+
if (allNodeInstalled.every(Boolean)) {
|
|
532
|
+
installed.push({ provider: provider.name, binding: "node" });
|
|
533
|
+
continue;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
if (provider.bindings.wasm) {
|
|
537
|
+
const allWasmInstalled = await Promise.all(
|
|
538
|
+
provider.bindings.wasm.map((dep) => hasResolvableDependency(dep.name))
|
|
539
|
+
);
|
|
540
|
+
if (allWasmInstalled.every(Boolean)) {
|
|
541
|
+
installed.push({ provider: provider.name, binding: "wasm" });
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return installed;
|
|
546
|
+
}
|
|
547
|
+
async function getMissingDependencies(provider, binding = "node") {
|
|
548
|
+
const missing = await getMissingProviderDependencyDefinitions(provider, binding);
|
|
549
|
+
return missing.map((d) => d.name);
|
|
550
|
+
}
|
|
551
|
+
async function getMissingProviderDependencyDefinitions(provider, binding = "node") {
|
|
552
|
+
const providerDef = PROVIDER_DEPENDENCIES.find((p) => p.name === provider);
|
|
553
|
+
if (!providerDef)
|
|
554
|
+
return [];
|
|
555
|
+
const deps = providerDef.bindings[binding] || providerDef.bindings.node || [];
|
|
556
|
+
const missing = [];
|
|
557
|
+
for (const dep of deps) {
|
|
558
|
+
if (!await hasResolvableDependency(dep.name))
|
|
559
|
+
missing.push(dep);
|
|
560
|
+
}
|
|
561
|
+
return missing;
|
|
562
|
+
}
|
|
563
|
+
function getDependencyDefinitions(provider, binding = "node") {
|
|
564
|
+
const providerDef = PROVIDER_DEPENDENCIES.find((p) => p.name === provider);
|
|
565
|
+
if (!providerDef)
|
|
566
|
+
return [];
|
|
567
|
+
return providerDef.bindings[binding] || providerDef.bindings.node || [];
|
|
568
|
+
}
|
|
569
|
+
function getDependencyInstallSpec(dep) {
|
|
570
|
+
return dep.installSpec || dep.name;
|
|
571
|
+
}
|
|
572
|
+
async function getMissingDependencyInstallSpecs(provider, binding = "node") {
|
|
573
|
+
const missing = await getMissingProviderDependencyDefinitions(provider, binding);
|
|
574
|
+
return missing.map(getDependencyInstallSpec);
|
|
575
|
+
}
|
|
576
|
+
function getProviderDependencyInstallSpecs(provider, binding = "node") {
|
|
577
|
+
return getDependencyDefinitions(provider, binding).map(getDependencyInstallSpec);
|
|
578
|
+
}
|
|
579
|
+
function getRecommendedBindingFromPreset(provider) {
|
|
580
|
+
const preset = resolveOgImagePreset();
|
|
581
|
+
const compatibility = getPresetNitroPresetCompatibility(preset);
|
|
582
|
+
return getRecommendedBinding(provider, compatibility);
|
|
583
|
+
}
|
|
584
|
+
function getRecommendedBinding(provider, compatibility) {
|
|
585
|
+
if (provider === "satori") {
|
|
586
|
+
const resvgBinding = compatibility.resvg;
|
|
587
|
+
if (resvgBinding === "wasm-fs")
|
|
588
|
+
return "wasm-fs";
|
|
589
|
+
if (resvgBinding === "wasm")
|
|
590
|
+
return "wasm";
|
|
591
|
+
return "node";
|
|
592
|
+
}
|
|
593
|
+
if (provider === "takumi") {
|
|
594
|
+
const takumiBinding = compatibility.takumi;
|
|
595
|
+
if (takumiBinding === "wasm")
|
|
596
|
+
return "wasm";
|
|
597
|
+
return "node";
|
|
598
|
+
}
|
|
599
|
+
if (provider === "browser") {
|
|
600
|
+
return "node";
|
|
601
|
+
}
|
|
602
|
+
return "node";
|
|
603
|
+
}
|
|
604
|
+
async function ensureProviderDependencies(provider, binding, nuxt) {
|
|
605
|
+
const missingDeps = await getMissingProviderDependencyDefinitions(provider, binding);
|
|
606
|
+
if (missingDeps.length === 0)
|
|
607
|
+
return { success: true, installed: [] };
|
|
608
|
+
const missingInstallSpecs = missingDeps.map(getDependencyInstallSpec);
|
|
609
|
+
const pm = await nypm.detectPackageManager(nuxt.options.rootDir);
|
|
610
|
+
const pmName = pm?.name || "npm";
|
|
611
|
+
logger_js.logger.info(`Installing ${provider} dependencies: ${missingInstallSpecs.join(", ")}`);
|
|
612
|
+
const installed = [];
|
|
613
|
+
for (const dep of missingDeps) {
|
|
614
|
+
const installSpec = getDependencyInstallSpec(dep);
|
|
615
|
+
const success = await nypm.addDependency(installSpec, {
|
|
616
|
+
cwd: nuxt.options.rootDir,
|
|
617
|
+
dev: false
|
|
618
|
+
}).then(() => {
|
|
619
|
+
installed.push(installSpec);
|
|
620
|
+
return true;
|
|
621
|
+
}).catch(() => {
|
|
622
|
+
logger_js.logger.error(`Failed to install ${installSpec}. Run manually: ${pmName} add ${installSpec}`);
|
|
623
|
+
return false;
|
|
624
|
+
});
|
|
625
|
+
if (!success)
|
|
626
|
+
return { success: false, installed };
|
|
627
|
+
}
|
|
628
|
+
return { success: true, installed };
|
|
629
|
+
}
|
|
630
|
+
function canPromptInteractively(env = {
|
|
631
|
+
hasTTY: stdEnv.hasTTY,
|
|
632
|
+
hasStdinTTY: Boolean(process.stdin?.isTTY),
|
|
633
|
+
isAgent: stdEnv.isAgent,
|
|
634
|
+
isCI: stdEnv.isCI
|
|
635
|
+
}) {
|
|
636
|
+
return env.hasTTY && env.hasStdinTTY && !env.isAgent && !env.isCI;
|
|
637
|
+
}
|
|
638
|
+
async function promptForRendererSelection() {
|
|
639
|
+
logger_js.logger.info("Welcome to Nuxt OG Image! No renderer dependencies detected.");
|
|
640
|
+
const renderer = await logger_js.logger.prompt("Which renderer would you like to use?", {
|
|
641
|
+
type: "select",
|
|
642
|
+
options: PROVIDER_DEPENDENCIES.map((p) => p.name),
|
|
643
|
+
initial: "takumi"
|
|
644
|
+
});
|
|
645
|
+
return renderer || "takumi";
|
|
646
|
+
}
|
|
647
|
+
async function validateProviderSetup(renderer, compatibility) {
|
|
648
|
+
const issues = [];
|
|
649
|
+
const binding = getRecommendedBinding(renderer, compatibility);
|
|
650
|
+
const missing = await getMissingDependencyInstallSpecs(renderer, binding);
|
|
651
|
+
if (missing.length > 0) {
|
|
652
|
+
issues.push(`Missing ${renderer} dependencies: ${missing.join(", ")}`);
|
|
653
|
+
}
|
|
654
|
+
if (renderer === "satori") {
|
|
655
|
+
const hasResvgNode = await hasResolvableDependency("@resvg/resvg-js");
|
|
656
|
+
const hasResvgWasm = await hasResolvableDependency("@resvg/resvg-wasm");
|
|
657
|
+
if (!hasResvgNode && !hasResvgWasm) {
|
|
658
|
+
issues.push("Satori requires either @resvg/resvg-js (node) or @resvg/resvg-wasm to render PNGs");
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
if (renderer === "browser") {
|
|
662
|
+
const hasPlaywright = await hasResolvableDependency("playwright-core");
|
|
663
|
+
if (!hasPlaywright && binding === "node") {
|
|
664
|
+
issues.push("Browser renderer requires playwright-core");
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
return { valid: issues.length === 0, issues };
|
|
668
|
+
}
|
|
669
|
+
|
|
206
670
|
function setupDevHandler(options, resolve, getDetectedRenderers, getCompatibilityMeta = () => ({}), nuxt = kit.useNuxt()) {
|
|
207
671
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
208
672
|
const detectedRenderers = new Set(getDetectedRenderers());
|
|
209
|
-
const targetCompatibility =
|
|
673
|
+
const targetCompatibility = getPresetNitroPresetCompatibility(resolveOgImagePreset(nitro.options));
|
|
210
674
|
for (const renderer of ["satori", "takumi", "browser"]) {
|
|
211
675
|
if (!detectedRenderers.has(renderer)) {
|
|
212
|
-
const binding =
|
|
213
|
-
const missing = await
|
|
676
|
+
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
677
|
+
const missing = await getMissingDependencies(renderer, binding);
|
|
214
678
|
if (missing.length === 0)
|
|
215
679
|
detectedRenderers.add(renderer);
|
|
216
680
|
}
|
|
217
681
|
}
|
|
218
|
-
await
|
|
682
|
+
await applyNitroPresetCompatibility(nitro.options, { compatibility: options.compatibility?.dev, resolve, detectedRenderers, metadata: getCompatibilityMeta() });
|
|
219
683
|
});
|
|
220
684
|
}
|
|
221
685
|
|
|
@@ -341,9 +805,9 @@ ${content}`, "utf-8");
|
|
|
341
805
|
if (nameWithoutExt.includes(".")) {
|
|
342
806
|
dotNotationName = `${nameWithoutExt}.vue`;
|
|
343
807
|
} else {
|
|
344
|
-
const rendererMatch = nameWithoutExt.match(
|
|
808
|
+
const rendererMatch = nameWithoutExt.match(RE_RENDERER_SUFFIX);
|
|
345
809
|
const renderer = rendererMatch?.[1]?.toLowerCase() || "satori";
|
|
346
|
-
const baseName = nameWithoutExt.replace(
|
|
810
|
+
const baseName = nameWithoutExt.replace(RE_RENDERER_SUFFIX, "");
|
|
347
811
|
dotNotationName = `${baseName}.${renderer}.vue`;
|
|
348
812
|
}
|
|
349
813
|
const dir = pathe.join(nuxt.options.srcDir, "components", dirName || "");
|
|
@@ -1024,7 +1488,7 @@ async function downlevelColor(prop, value) {
|
|
|
1024
1488
|
function convertIndividualTransforms(styles) {
|
|
1025
1489
|
const parts = [];
|
|
1026
1490
|
if (styles.translate) {
|
|
1027
|
-
const vals = styles.translate.trim().split(
|
|
1491
|
+
const vals = styles.translate.trim().split(RE_WHITESPACE);
|
|
1028
1492
|
parts.push(vals.length === 2 ? `translate(${vals[0]}, ${vals[1]})` : `translateX(${vals[0]})`);
|
|
1029
1493
|
delete styles.translate;
|
|
1030
1494
|
}
|
|
@@ -1033,7 +1497,7 @@ function convertIndividualTransforms(styles) {
|
|
|
1033
1497
|
delete styles.rotate;
|
|
1034
1498
|
}
|
|
1035
1499
|
if (styles.scale) {
|
|
1036
|
-
const vals = styles.scale.trim().split(
|
|
1500
|
+
const vals = styles.scale.trim().split(RE_WHITESPACE).filter(Boolean);
|
|
1037
1501
|
parts.push(`scale(${vals.join(", ")})`);
|
|
1038
1502
|
delete styles.scale;
|
|
1039
1503
|
}
|
|
@@ -1666,7 +2130,7 @@ function resolveWeightsFromFontEntry(fontWeight, requestedWeights) {
|
|
|
1666
2130
|
min = Number(fontWeight[0]);
|
|
1667
2131
|
max = Number(fontWeight[1]);
|
|
1668
2132
|
} else if (typeof fontWeight === "string") {
|
|
1669
|
-
const parts = fontWeight.split(
|
|
2133
|
+
const parts = fontWeight.split(RE_WHITESPACE).map(Number);
|
|
1670
2134
|
if (parts.length >= 2 && !Number.isNaN(parts[0]) && !Number.isNaN(parts[1])) {
|
|
1671
2135
|
min = parts[0];
|
|
1672
2136
|
max = parts[1];
|
|
@@ -2005,7 +2469,7 @@ ${familyBreakdown}`);
|
|
|
2005
2469
|
|
|
2006
2470
|
function setupGenerateHandler(_options, resolve, _getDetectedRenderers, nuxt = kit.useNuxt()) {
|
|
2007
2471
|
nuxt.hooks.hook("nitro:config", async (nitroConfig) => {
|
|
2008
|
-
await
|
|
2472
|
+
await applyNitroPresetCompatibility(nitroConfig, {
|
|
2009
2473
|
compatibility: {
|
|
2010
2474
|
browser: false,
|
|
2011
2475
|
satori: false,
|
|
@@ -2022,7 +2486,7 @@ const ONE_WEEK_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
|
2022
2486
|
function setupPrerenderHandler(options, resolve, getDetectedRenderers, getCompatibilityMeta = () => ({}), nuxt = kit.useNuxt()) {
|
|
2023
2487
|
nuxt.hooks.hook("nitro:init", async (nitro) => {
|
|
2024
2488
|
nitro.hooks.hook("prerender:config", async (nitroConfig) => {
|
|
2025
|
-
await
|
|
2489
|
+
await applyNitroPresetCompatibility(nitroConfig, { compatibility: options.compatibility?.prerender, resolve, detectedRenderers: getDetectedRenderers(), metadata: getCompatibilityMeta() });
|
|
2026
2490
|
nitroConfig.wasm = nitroConfig.wasm || {};
|
|
2027
2491
|
nitroConfig.wasm.esmImport = false;
|
|
2028
2492
|
nitroConfig.prerender = nitroConfig.prerender || {};
|
|
@@ -2233,7 +2697,7 @@ async function extractFontRequirementsFromVue(code) {
|
|
|
2233
2697
|
const el = node;
|
|
2234
2698
|
for (const prop of el.props) {
|
|
2235
2699
|
if (prop.type === ATTRIBUTE_NODE$1 && prop.name === "class" && prop.value) {
|
|
2236
|
-
for (const cls of prop.value.content.split(
|
|
2700
|
+
for (const cls of prop.value.content.split(RE_WHITESPACE)) {
|
|
2237
2701
|
extractFontWeightFromClass(cls, weights, styles);
|
|
2238
2702
|
extractFontFamilyFromClass(cls, familyClasses, familyNames);
|
|
2239
2703
|
}
|
|
@@ -2560,7 +3024,7 @@ async function transformVueTemplate(code, options) {
|
|
|
2560
3024
|
};
|
|
2561
3025
|
for (const prop of el.props) {
|
|
2562
3026
|
if (prop.type === ATTRIBUTE_NODE && prop.name === "class" && prop.value) {
|
|
2563
|
-
collector.classes = prop.value.content.split(
|
|
3027
|
+
collector.classes = prop.value.content.split(RE_WHITESPACE).filter(Boolean);
|
|
2564
3028
|
collector.classLoc = {
|
|
2565
3029
|
start: prop.loc.start.offset,
|
|
2566
3030
|
end: prop.loc.end.offset
|
|
@@ -3053,7 +3517,7 @@ const AssetTransformPlugin = unplugin.createUnplugin((options) => {
|
|
|
3053
3517
|
const [fullMatch, , attrsStr, classValue] = elMatch;
|
|
3054
3518
|
if (!classValue)
|
|
3055
3519
|
continue;
|
|
3056
|
-
const classes = classValue.split(
|
|
3520
|
+
const classes = classValue.split(RE_WHITESPACE).filter(Boolean);
|
|
3057
3521
|
let iconPrefix;
|
|
3058
3522
|
let iconName;
|
|
3059
3523
|
for (const cls of classes) {
|
|
@@ -3272,7 +3736,7 @@ const AssetTransformPlugin = unplugin.createUnplugin((options) => {
|
|
|
3272
3736
|
const classAttr = el.attributes?.class;
|
|
3273
3737
|
if (!classAttr)
|
|
3274
3738
|
return;
|
|
3275
|
-
const elClasses = classAttr.split(
|
|
3739
|
+
const elClasses = classAttr.split(RE_WHITESPACE).filter(Boolean);
|
|
3276
3740
|
const matchedStyles = {};
|
|
3277
3741
|
const consumedClasses = /* @__PURE__ */ new Set();
|
|
3278
3742
|
for (const cls of elClasses) {
|
|
@@ -3776,11 +4240,11 @@ async function onInstall(nuxt) {
|
|
|
3776
4240
|
if (nuxt.options._prepare)
|
|
3777
4241
|
return;
|
|
3778
4242
|
if (stdEnv.isCI) {
|
|
3779
|
-
const installedProviders2 = await
|
|
4243
|
+
const installedProviders2 = await getInstalledProviders();
|
|
3780
4244
|
if (installedProviders2.length === 0) {
|
|
3781
4245
|
throw new Error(
|
|
3782
4246
|
`[nuxt-og-image] No OG image provider dependencies found. Install a provider before running in CI:
|
|
3783
|
-
npm add ${
|
|
4247
|
+
npm add ${TAKUMI_CORE_PACKAGE} # for takumi
|
|
3784
4248
|
npm add @resvg/resvg-js satori yoga-wasm-web # for satori
|
|
3785
4249
|
npm add playwright-core # for browser
|
|
3786
4250
|
See: https://nuxtseo.com/og-image/getting-started`
|
|
@@ -3788,7 +4252,7 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3788
4252
|
}
|
|
3789
4253
|
return;
|
|
3790
4254
|
}
|
|
3791
|
-
if (!
|
|
4255
|
+
if (!canPromptInteractively()) {
|
|
3792
4256
|
logger_js.logger.info("Skipping interactive onboarding (non-interactive environment). Defaulting to the takumi renderer.");
|
|
3793
4257
|
return;
|
|
3794
4258
|
}
|
|
@@ -3798,7 +4262,7 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3798
4262
|
logger_js.logger.info("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518");
|
|
3799
4263
|
logger_js.logger.info("");
|
|
3800
4264
|
const state = {};
|
|
3801
|
-
const installedProviders = await
|
|
4265
|
+
const installedProviders = await getInstalledProviders();
|
|
3802
4266
|
if (installedProviders.length > 0) {
|
|
3803
4267
|
logger_js.logger.info("Detected installed providers:");
|
|
3804
4268
|
for (const { provider, binding } of installedProviders) {
|
|
@@ -3816,7 +4280,7 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3816
4280
|
if (!state.selectedRenderer) {
|
|
3817
4281
|
const rendererChoice = await logger_js.logger.prompt("Select a renderer:", {
|
|
3818
4282
|
type: "select",
|
|
3819
|
-
options:
|
|
4283
|
+
options: PROVIDER_DEPENDENCIES.map((p) => ({
|
|
3820
4284
|
label: p.name,
|
|
3821
4285
|
value: p.name,
|
|
3822
4286
|
hint: p.description
|
|
@@ -3829,8 +4293,8 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3829
4293
|
state.selectedRenderer = rendererChoice;
|
|
3830
4294
|
}
|
|
3831
4295
|
if (!state.selectedBinding) {
|
|
3832
|
-
const recommendedBinding =
|
|
3833
|
-
const providerDef =
|
|
4296
|
+
const recommendedBinding = getRecommendedBindingFromPreset(state.selectedRenderer);
|
|
4297
|
+
const providerDef = PROVIDER_DEPENDENCIES.find((p) => p.name === state.selectedRenderer);
|
|
3834
4298
|
const hasNodeBinding = !!providerDef?.bindings.node;
|
|
3835
4299
|
const hasWasmBinding = !!providerDef?.bindings.wasm || !!providerDef?.bindings["wasm-fs"];
|
|
3836
4300
|
if (hasNodeBinding && hasWasmBinding) {
|
|
@@ -3855,7 +4319,7 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3855
4319
|
state.selectedBinding = hasNodeBinding ? "node" : "wasm";
|
|
3856
4320
|
}
|
|
3857
4321
|
}
|
|
3858
|
-
const missingInstallSpecs = await
|
|
4322
|
+
const missingInstallSpecs = await getMissingDependencyInstallSpecs(state.selectedRenderer, state.selectedBinding);
|
|
3859
4323
|
if (missingInstallSpecs.length > 0) {
|
|
3860
4324
|
logger_js.logger.info(`Required dependencies for ${state.selectedRenderer} (${state.selectedBinding}):`);
|
|
3861
4325
|
for (const pkg of missingInstallSpecs) {
|
|
@@ -3866,7 +4330,7 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3866
4330
|
initial: true
|
|
3867
4331
|
});
|
|
3868
4332
|
if (installDeps) {
|
|
3869
|
-
const result = await
|
|
4333
|
+
const result = await ensureProviderDependencies(
|
|
3870
4334
|
state.selectedRenderer,
|
|
3871
4335
|
state.selectedBinding,
|
|
3872
4336
|
nuxt
|
|
@@ -3875,11 +4339,11 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3875
4339
|
logger_js.logger.success(`Installed: ${result.installed.join(", ")}`);
|
|
3876
4340
|
} else {
|
|
3877
4341
|
logger_js.logger.error("Failed to install some dependencies. Install manually:");
|
|
3878
|
-
const allDeps =
|
|
4342
|
+
const allDeps = getProviderDependencyInstallSpecs(state.selectedRenderer, state.selectedBinding);
|
|
3879
4343
|
logger_js.logger.info(` npm add ${allDeps.join(" ")}`);
|
|
3880
4344
|
}
|
|
3881
4345
|
} else {
|
|
3882
|
-
const allDeps =
|
|
4346
|
+
const allDeps = getProviderDependencyInstallSpecs(state.selectedRenderer, state.selectedBinding);
|
|
3883
4347
|
logger_js.logger.warn("Dependencies required. Install manually:");
|
|
3884
4348
|
logger_js.logger.info(` npm add ${allDeps.join(" ")}`);
|
|
3885
4349
|
}
|
|
@@ -3893,14 +4357,14 @@ See: https://nuxtseo.com/og-image/getting-started`
|
|
|
3893
4357
|
if (createComponent) {
|
|
3894
4358
|
await createStarterComponent(nuxt);
|
|
3895
4359
|
}
|
|
3896
|
-
const hasSharp = await
|
|
4360
|
+
const hasSharp = await hasResolvableDependency("sharp");
|
|
3897
4361
|
if (!hasSharp && state.selectedRenderer === "satori") {
|
|
3898
4362
|
const wantJpeg = await logger_js.logger.prompt("Install sharp for JPEG output support?", {
|
|
3899
4363
|
type: "confirm",
|
|
3900
4364
|
initial: false
|
|
3901
4365
|
});
|
|
3902
4366
|
if (wantJpeg) {
|
|
3903
|
-
await
|
|
4367
|
+
await ensureProviderDependencies("satori", "node", nuxt).catch(() => logger_js.logger.warn("Failed to install sharp, JPEG output unavailable"));
|
|
3904
4368
|
}
|
|
3905
4369
|
}
|
|
3906
4370
|
logger_js.logger.info("");
|
|
@@ -3935,7 +4399,7 @@ async function onUpgrade(nuxt, _options, previousVersion) {
|
|
|
3935
4399
|
issues.push(`Config \`defaults.component\` is deprecated: Removed \u2014 rename component to OgImage/Default.{renderer}.vue`);
|
|
3936
4400
|
}
|
|
3937
4401
|
if ("fonts" in ogImageConfig && !nuxt.options._prepare && !stdEnv.isCI) {
|
|
3938
|
-
await
|
|
4402
|
+
await fonts.promptFontsMigration(nuxt.options.rootDir);
|
|
3939
4403
|
}
|
|
3940
4404
|
}
|
|
3941
4405
|
if (issues.length > 0) {
|
|
@@ -3952,17 +4416,17 @@ async function onUpgrade(nuxt, _options, previousVersion) {
|
|
|
3952
4416
|
const ogComponentDir = pathe.join(nuxt.options.srcDir, "components", "OgImage");
|
|
3953
4417
|
if (fs.existsSync(ogComponentDir)) {
|
|
3954
4418
|
for (const file of fs.readdirSync(ogComponentDir).filter((f) => f.endsWith(".vue"))) {
|
|
3955
|
-
const renderer =
|
|
4419
|
+
const renderer = getRendererFromFilename(file);
|
|
3956
4420
|
if (renderer)
|
|
3957
4421
|
detectedRenderers.add(renderer);
|
|
3958
4422
|
}
|
|
3959
4423
|
}
|
|
3960
4424
|
if (detectedRenderers.size === 0)
|
|
3961
4425
|
detectedRenderers.add("satori");
|
|
3962
|
-
const preset =
|
|
3963
|
-
const compatibility =
|
|
4426
|
+
const preset = resolveOgImagePreset();
|
|
4427
|
+
const compatibility = getPresetNitroPresetCompatibility(preset);
|
|
3964
4428
|
for (const renderer of detectedRenderers) {
|
|
3965
|
-
const validation = await
|
|
4429
|
+
const validation = await validateProviderSetup(renderer, compatibility);
|
|
3966
4430
|
if (!validation.valid) {
|
|
3967
4431
|
logger_js.logger.warn(`Provider setup issues for ${renderer}:`);
|
|
3968
4432
|
for (const issue of validation.issues) {
|
|
@@ -4021,7 +4485,7 @@ function registerTypeTemplates(ctx) {
|
|
|
4021
4485
|
const sortedDirs = config.componentDirs.sort((a, b) => b.length - a.length);
|
|
4022
4486
|
const baseNameRenderers = /* @__PURE__ */ new Map();
|
|
4023
4487
|
for (const component of componentCtx.components) {
|
|
4024
|
-
for (const baseName of
|
|
4488
|
+
for (const baseName of getRegisteredBaseNames(component.pascalName)) {
|
|
4025
4489
|
const renderers = baseNameRenderers.get(baseName) || [];
|
|
4026
4490
|
renderers.push(component.renderer);
|
|
4027
4491
|
baseNameRenderers.set(baseName, renderers);
|
|
@@ -4032,7 +4496,7 @@ function registerTypeTemplates(ctx) {
|
|
|
4032
4496
|
const importType = getComponentTypeExpression(component, nuxt);
|
|
4033
4497
|
const strippedName = sortedDirs.reduce((n, dir) => n.replace(new RegExp(`^${dir}`), ""), component.pascalName);
|
|
4034
4498
|
const renderer = component.renderer;
|
|
4035
|
-
const baseNames =
|
|
4499
|
+
const baseNames = getRegisteredBaseNames(component.pascalName);
|
|
4036
4500
|
lines.push(` '${strippedName}': ${importType}`);
|
|
4037
4501
|
const seen = /* @__PURE__ */ new Set([strippedName]);
|
|
4038
4502
|
for (const baseName of baseNames) {
|
|
@@ -4094,6 +4558,15 @@ declare module '#og-image/font-requirements' {
|
|
|
4094
4558
|
export const hasNuxtFonts: boolean
|
|
4095
4559
|
}
|
|
4096
4560
|
|
|
4561
|
+
declare module '#og-image/island-hash' {
|
|
4562
|
+
export function getIslandHash(input: {
|
|
4563
|
+
name: string
|
|
4564
|
+
props?: Record<string, any> | string | null
|
|
4565
|
+
context?: Record<string, any>
|
|
4566
|
+
source?: string
|
|
4567
|
+
}): string
|
|
4568
|
+
}
|
|
4569
|
+
|
|
4097
4570
|
declare module '#og-image-virtual/unocss-config.mjs' {
|
|
4098
4571
|
export const theme: Record<string, any>
|
|
4099
4572
|
}
|
|
@@ -4317,7 +4790,7 @@ const module$1 = kit.defineNuxtModule({
|
|
|
4317
4790
|
await onUpgrade(nuxt, options, previousVersion);
|
|
4318
4791
|
},
|
|
4319
4792
|
async setup(config, nuxt) {
|
|
4320
|
-
const _resolver = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/nuxt-og-image.
|
|
4793
|
+
const _resolver = kit.createResolver((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('shared/nuxt-og-image.BRBtdkUp.cjs', document.baseURI).href)));
|
|
4321
4794
|
const fixSharedPath = (p) => {
|
|
4322
4795
|
return p.replace(/\/shared\/runtime(\/|$)/, "/runtime$1").replace(/\/shared\/client(\/|$)/, "/client$1").replace(/\/shared\/devtools(\/|$)/, "/devtools$1");
|
|
4323
4796
|
};
|
|
@@ -4409,10 +4882,10 @@ Or pin to a specific version in package.json:
|
|
|
4409
4882
|
}
|
|
4410
4883
|
nuxt.options.alias["#og-image"] = resolve("./runtime");
|
|
4411
4884
|
nuxt.options.alias["#og-image-cache"] = resolve("./runtime/server/og-image/cache/lru");
|
|
4412
|
-
const preset =
|
|
4413
|
-
const targetCompatibility =
|
|
4885
|
+
const preset = resolveOgImagePreset(nuxt.options.nitro);
|
|
4886
|
+
const targetCompatibility = getPresetNitroPresetCompatibility(preset);
|
|
4414
4887
|
const runtimeCompatibilityMeta = {};
|
|
4415
|
-
const normalizedPreset = preset.replace(
|
|
4888
|
+
const normalizedPreset = preset.replace(RE_LEGACY_SUFFIX, "");
|
|
4416
4889
|
const isCloudflareWorkers = ["cloudflare", "cloudflare-module", "cloudflare-durable"].includes(normalizedPreset);
|
|
4417
4890
|
if (isCloudflareWorkers) {
|
|
4418
4891
|
nuxt.hooks.hook("nitro:init", (nitro) => {
|
|
@@ -4683,7 +5156,7 @@ ${familyInfo}`);
|
|
|
4683
5156
|
}
|
|
4684
5157
|
} else if (hasConfiguredJpegs) {
|
|
4685
5158
|
logger_js.logger.warn("You have enabled `JPEG` images. These require the `sharp` dependency which is missing, installing it for you.");
|
|
4686
|
-
await
|
|
5159
|
+
await ensureDependencies(["sharp"]);
|
|
4687
5160
|
logger_js.logger.warn("Support for `sharp` is limited so check the compatibility guide.");
|
|
4688
5161
|
attemptSharpUsage = true;
|
|
4689
5162
|
}
|
|
@@ -4697,8 +5170,8 @@ ${familyInfo}`);
|
|
|
4697
5170
|
}
|
|
4698
5171
|
}
|
|
4699
5172
|
if (isProviderEnabledForEnv("browser", nuxt, config)) {
|
|
4700
|
-
const hasChromeLocally =
|
|
4701
|
-
const hasPlaywrightDependency = await
|
|
5173
|
+
const hasChromeLocally = checkLocalChrome();
|
|
5174
|
+
const hasPlaywrightDependency = await hasResolvableDependency("playwright");
|
|
4702
5175
|
const browserCompatibilityFlags = {
|
|
4703
5176
|
prerender: config.compatibility?.prerender?.browser,
|
|
4704
5177
|
dev: config.compatibility?.dev?.browser,
|
|
@@ -4715,7 +5188,7 @@ ${familyInfo}`);
|
|
|
4715
5188
|
if (!browserConfig.binding) {
|
|
4716
5189
|
throw new Error("[nuxt-og-image] `ogImage.browser.binding` is required when provider is cloudflare");
|
|
4717
5190
|
}
|
|
4718
|
-
const hasCloudfarePuppeteer = await
|
|
5191
|
+
const hasCloudfarePuppeteer = await hasResolvableDependency("@cloudflare/puppeteer");
|
|
4719
5192
|
if (!hasCloudfarePuppeteer) {
|
|
4720
5193
|
throw new Error(
|
|
4721
5194
|
"[nuxt-og-image] Missing @cloudflare/puppeteer dependency. Install it with: pnpm add @cloudflare/puppeteer"
|
|
@@ -4725,12 +5198,12 @@ ${familyInfo}`);
|
|
|
4725
5198
|
browserBinding.prerender = hasPlaywrightDependency ? "playwright" : hasChromeLocally ? "chrome-launcher" : "on-demand";
|
|
4726
5199
|
browserBinding.runtime = "cloudflare";
|
|
4727
5200
|
} else if (nuxt.options.dev) {
|
|
4728
|
-
if (
|
|
5201
|
+
if (isUndefinedOrTruthy(browserCompatibilityFlags.dev))
|
|
4729
5202
|
browserBinding.dev = hasChromeLocally ? "chrome-launcher" : hasPlaywrightDependency ? "playwright" : "on-demand";
|
|
4730
5203
|
} else {
|
|
4731
|
-
if (
|
|
5204
|
+
if (isUndefinedOrTruthy(browserCompatibilityFlags.prerender))
|
|
4732
5205
|
browserBinding.prerender = hasChromeLocally ? "chrome-launcher" : hasPlaywrightDependency ? "playwright" : "on-demand";
|
|
4733
|
-
if (
|
|
5206
|
+
if (isUndefinedOrTruthy(browserCompatibilityFlags.runtime))
|
|
4734
5207
|
browserBinding.runtime = hasPlaywrightDependency ? "playwright" : null;
|
|
4735
5208
|
}
|
|
4736
5209
|
config.compatibility = defu.defu(config.compatibility, {
|
|
@@ -4739,7 +5212,7 @@ ${familyInfo}`);
|
|
|
4739
5212
|
prerender: { browser: browserBinding.prerender }
|
|
4740
5213
|
});
|
|
4741
5214
|
}
|
|
4742
|
-
await kit$
|
|
5215
|
+
await kit$2.installNuxtSiteConfig();
|
|
4743
5216
|
nuxt.options.experimental.componentIslands ||= true;
|
|
4744
5217
|
if (config.debug || nuxt.options.dev) {
|
|
4745
5218
|
kit.addServerHandler({
|
|
@@ -4852,7 +5325,7 @@ ${familyInfo}`);
|
|
|
4852
5325
|
if (isUserDir && fs__namespace.existsSync(resolvedPath)) {
|
|
4853
5326
|
const files = fs__namespace.readdirSync(resolvedPath).filter((f) => f.endsWith(".vue"));
|
|
4854
5327
|
for (const file of files) {
|
|
4855
|
-
const renderer =
|
|
5328
|
+
const renderer = getRendererFromFilename(file);
|
|
4856
5329
|
if (renderer) {
|
|
4857
5330
|
ogImageComponentCtx.detectedRenderers.add(renderer);
|
|
4858
5331
|
hasUserComponents = true;
|
|
@@ -4861,32 +5334,32 @@ ${familyInfo}`);
|
|
|
4861
5334
|
}
|
|
4862
5335
|
}
|
|
4863
5336
|
if (!nuxt.options._prepare && !hasUserComponents) {
|
|
4864
|
-
const installedProviders = await
|
|
5337
|
+
const installedProviders = await getInstalledProviders();
|
|
4865
5338
|
const preferred = installedProviders.find((p) => p.provider === "takumi") || installedProviders[0];
|
|
4866
5339
|
if (preferred) {
|
|
4867
5340
|
ogImageComponentCtx.detectedRenderers.add(preferred.provider);
|
|
4868
5341
|
logger_js.logger.debug(`Using ${preferred.provider} renderer`);
|
|
4869
|
-
} else if (nuxt.options.dev && !nuxt.options._prepare &&
|
|
4870
|
-
const renderer = await
|
|
5342
|
+
} else if (nuxt.options.dev && !nuxt.options._prepare && canPromptInteractively()) {
|
|
5343
|
+
const renderer = await promptForRendererSelection();
|
|
4871
5344
|
ogImageComponentCtx.detectedRenderers.add(renderer);
|
|
4872
5345
|
logger_js.logger.debug(`Using ${renderer} renderer`);
|
|
4873
5346
|
} else {
|
|
4874
5347
|
ogImageComponentCtx.detectedRenderers.add("takumi");
|
|
4875
|
-
logger_js.logger.warn(`No OG image renderer dependency detected. Defaulting to \`takumi\` (non-interactive environment). Install \`${
|
|
5348
|
+
logger_js.logger.warn(`No OG image renderer dependency detected. Defaulting to \`takumi\` (non-interactive environment). Install \`${TAKUMI_CORE_PACKAGE}\`, or add a renderer component (e.g. components/OgImage/Default.satori.vue) to choose explicitly.`);
|
|
4876
5349
|
}
|
|
4877
5350
|
}
|
|
4878
5351
|
const availableRenderers = /* @__PURE__ */ new Set();
|
|
4879
5352
|
if (!nuxt.options._prepare) {
|
|
4880
5353
|
if (!config.zeroRuntime) {
|
|
4881
5354
|
for (const renderer of ogImageComponentCtx.detectedRenderers) {
|
|
4882
|
-
const binding =
|
|
4883
|
-
const missing = await
|
|
5355
|
+
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
5356
|
+
const missing = await getMissingDependencies(renderer, binding);
|
|
4884
5357
|
if (missing.length === 0) {
|
|
4885
5358
|
availableRenderers.add(renderer);
|
|
4886
5359
|
} else if (nuxt.options.dev && !nuxt.options._prepare) {
|
|
4887
|
-
const installSpecs = await
|
|
5360
|
+
const installSpecs = await getMissingDependencyInstallSpecs(renderer, binding);
|
|
4888
5361
|
logger_js.logger.warn(`${renderer} renderer requires: ${installSpecs.join(", ")}`);
|
|
4889
|
-
const { success } = await
|
|
5362
|
+
const { success } = await ensureProviderDependencies(renderer, binding, nuxt);
|
|
4890
5363
|
if (success) {
|
|
4891
5364
|
availableRenderers.add(renderer);
|
|
4892
5365
|
} else if (stdEnv.isAgent) {
|
|
@@ -4895,10 +5368,10 @@ ${familyInfo}`);
|
|
|
4895
5368
|
logger_js.logger.error(`Failed to install ${renderer} dependencies. Templates using this renderer won't work.`);
|
|
4896
5369
|
}
|
|
4897
5370
|
} else if (stdEnv.isAgent) {
|
|
4898
|
-
const installSpecs = await
|
|
5371
|
+
const installSpecs = await getMissingDependencyInstallSpecs(renderer, binding);
|
|
4899
5372
|
throw new Error(`[nuxt-og-image] ${renderer} renderer missing dependencies: ${missing.join(", ")}. Install with: npx nypm add ${installSpecs.join(" ")}`);
|
|
4900
5373
|
} else {
|
|
4901
|
-
const installSpecs = await
|
|
5374
|
+
const installSpecs = await getMissingDependencyInstallSpecs(renderer, binding);
|
|
4902
5375
|
logger_js.logger.error(`${renderer} renderer missing dependencies: ${missing.join(", ")}. Install with: npx nypm add ${installSpecs.join(" ")}`);
|
|
4903
5376
|
}
|
|
4904
5377
|
if (renderer === "satori" && availableRenderers.has(renderer) && binding !== "node") {
|
|
@@ -4921,7 +5394,7 @@ ${familyInfo}`);
|
|
|
4921
5394
|
}
|
|
4922
5395
|
runtimeCompatibilityMeta.takumiVersion = await detectTakumiVersion(
|
|
4923
5396
|
resolver,
|
|
4924
|
-
|
|
5397
|
+
getRecommendedBinding("takumi", targetCompatibility)
|
|
4925
5398
|
);
|
|
4926
5399
|
if (ogImageComponentCtx.detectedRenderers.has("takumi") && !runtimeCompatibilityMeta.takumiVersion) {
|
|
4927
5400
|
logger_js.logger.warn("Unable to detect @takumi-rs version. Falling back to Takumi v1 renderer compatibility.");
|
|
@@ -4930,8 +5403,8 @@ ${familyInfo}`);
|
|
|
4930
5403
|
if (nuxt.options.dev) {
|
|
4931
5404
|
const communityRenderers = /* @__PURE__ */ new Set();
|
|
4932
5405
|
for (const renderer of ["satori", "takumi", "browser"]) {
|
|
4933
|
-
const binding =
|
|
4934
|
-
const missing = await
|
|
5406
|
+
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
5407
|
+
const missing = await getMissingDependencies(renderer, binding);
|
|
4935
5408
|
if (missing.length === 0)
|
|
4936
5409
|
communityRenderers.add(renderer);
|
|
4937
5410
|
}
|
|
@@ -4962,7 +5435,7 @@ ${familyInfo}`);
|
|
|
4962
5435
|
if (valid && fs__namespace.existsSync(component.filePath)) {
|
|
4963
5436
|
if (!component.filePath.endsWith(".vue"))
|
|
4964
5437
|
return;
|
|
4965
|
-
const renderer =
|
|
5438
|
+
const renderer = getRendererFromFilename(component.filePath);
|
|
4966
5439
|
if (!renderer) {
|
|
4967
5440
|
invalidComponents.push(component.filePath);
|
|
4968
5441
|
return;
|
|
@@ -4978,7 +5451,7 @@ ${familyInfo}`);
|
|
|
4978
5451
|
const credits = componentFile.split("\n").find((line) => line.startsWith(" * @credits"))?.replace("* @credits", "").trim();
|
|
4979
5452
|
const propNames = extractPropNamesFromVue(componentFile);
|
|
4980
5453
|
ogImageComponentCtx.components.push({
|
|
4981
|
-
hash:
|
|
5454
|
+
hash: fnv1a64.fnv1a64Base36(componentFile),
|
|
4982
5455
|
pascalName: component.pascalName,
|
|
4983
5456
|
kebabName: component.kebabName,
|
|
4984
5457
|
path: component.filePath,
|
|
@@ -4993,18 +5466,18 @@ ${familyInfo}`);
|
|
|
4993
5466
|
const communityDir = resolve("./runtime/app/components/Templates/Community");
|
|
4994
5467
|
if (fs__namespace.existsSync(communityDir)) {
|
|
4995
5468
|
fs__namespace.readdirSync(communityDir).filter((f) => f.endsWith(".vue")).forEach((file) => {
|
|
4996
|
-
const renderer =
|
|
5469
|
+
const renderer = getRendererFromFilename(file);
|
|
4997
5470
|
if (!renderer)
|
|
4998
5471
|
return;
|
|
4999
5472
|
const pascalName = file.replace(".vue", "").split(".").map((s, i) => i === 0 ? s : s.charAt(0).toUpperCase() + s.slice(1)).join("");
|
|
5000
5473
|
const filePath = resolve(communityDir);
|
|
5001
|
-
const communityBaseNames =
|
|
5474
|
+
const communityBaseNames = getRegisteredBaseNames(pascalName);
|
|
5002
5475
|
if (ogImageComponentCtx.components.some((c) => {
|
|
5003
5476
|
if (c.pascalName === pascalName)
|
|
5004
5477
|
return true;
|
|
5005
5478
|
if (c.renderer !== renderer)
|
|
5006
5479
|
return false;
|
|
5007
|
-
const existingBaseNames =
|
|
5480
|
+
const existingBaseNames = getRegisteredBaseNames(c.pascalName);
|
|
5008
5481
|
return communityBaseNames.some((cb) => existingBaseNames.includes(cb));
|
|
5009
5482
|
})) {
|
|
5010
5483
|
return;
|
|
@@ -5025,10 +5498,10 @@ ${familyInfo}`);
|
|
|
5025
5498
|
if (nuxt.options.dev) {
|
|
5026
5499
|
for (const renderer of ogImageComponentCtx.detectedRenderers) {
|
|
5027
5500
|
if (!availableRenderers.has(renderer)) {
|
|
5028
|
-
const binding =
|
|
5029
|
-
|
|
5501
|
+
const binding = getRecommendedBinding(renderer, targetCompatibility);
|
|
5502
|
+
getMissingDependencies(renderer, binding).then(async (missing) => {
|
|
5030
5503
|
if (missing.length > 0) {
|
|
5031
|
-
const installSpecs = await
|
|
5504
|
+
const installSpecs = await getMissingDependencyInstallSpecs(renderer, binding);
|
|
5032
5505
|
logger_js.logger.warn(`New ${renderer} component detected but dependencies missing: ${missing.join(", ")}. Install with: npx nypm add ${installSpecs.join(" ")}`);
|
|
5033
5506
|
}
|
|
5034
5507
|
});
|
|
@@ -5063,6 +5536,22 @@ Run: npx nuxt-og-image migrate v6`;
|
|
|
5063
5536
|
nuxt.options.nitro.virtual["#og-image-virtual/component-names.mjs"] = () => {
|
|
5064
5537
|
return `export const componentNames = ${JSON.stringify(ogImageComponentCtx.components)}`;
|
|
5065
5538
|
};
|
|
5539
|
+
nuxt.options.nitro.virtual["#og-image/island-hash"] = () => {
|
|
5540
|
+
const islandHashFile = pathe.join(nuxt.options.appDir, "island-hash.js");
|
|
5541
|
+
const [nuxtMajor = 0, nuxtMinor = 0] = kit.getNuxtVersion(nuxt).split(".").map((v) => Number.parseInt(v));
|
|
5542
|
+
if (nuxtMajor > 4 || nuxtMajor === 4 && nuxtMinor >= 5)
|
|
5543
|
+
return `export { getIslandHash } from '${islandHashFile}'`;
|
|
5544
|
+
if (fs.existsSync(islandHashFile)) {
|
|
5545
|
+
return `import { computeIslandHash } from '${islandHashFile}'
|
|
5546
|
+
export function getIslandHash({ name, props, context, source }) {
|
|
5547
|
+
return computeIslandHash(name, props ?? {}, context ?? {}, source)
|
|
5548
|
+
}`;
|
|
5549
|
+
}
|
|
5550
|
+
return `import { hash } from 'ohash'
|
|
5551
|
+
export function getIslandHash({ name, props, context, source }) {
|
|
5552
|
+
return hash([name, props ?? {}, context ?? {}, source]).replace(/[-_]/g, '')
|
|
5553
|
+
}`;
|
|
5554
|
+
};
|
|
5066
5555
|
nuxt.options.nitro.publicAssets ||= [];
|
|
5067
5556
|
const staticFontsTtfDir = pathe.join(nuxt.options.buildDir, "cache", "og-image", "fonts-ttf");
|
|
5068
5557
|
nuxt.options.nitro.publicAssets.push({
|
|
@@ -5076,7 +5565,7 @@ Run: npx nuxt-og-image migrate v6`;
|
|
|
5076
5565
|
maxAge: 60 * 60 * 24 * 365
|
|
5077
5566
|
});
|
|
5078
5567
|
nuxt.options.nitro.virtual["#og-image-virtual/public-assets.mjs"] = async () => {
|
|
5079
|
-
const normalizedPreset2 = preset.replace(
|
|
5568
|
+
const normalizedPreset2 = preset.replace(RE_LEGACY_SUFFIX, "");
|
|
5080
5569
|
const isCloudflare = normalizedPreset2 === "cloudflare" || normalizedPreset2.startsWith("cloudflare-");
|
|
5081
5570
|
if (isCloudflare) {
|
|
5082
5571
|
const devBinding2 = resolver.resolve("./runtime/server/og-image/bindings/font-assets/dev-prerender");
|
|
@@ -5232,7 +5721,7 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5232
5721
|
const buildCacheDir = config.buildCache ? pathe.join(nuxt.options.rootDir, buildCachePath) : void 0;
|
|
5233
5722
|
nuxt.hooks.hook("modules:done", async () => {
|
|
5234
5723
|
const hasColorModeModule = kit.hasNuxtModule("@nuxtjs/color-mode");
|
|
5235
|
-
const colorModeOptions = hasColorModeModule ? await kit$
|
|
5724
|
+
const colorModeOptions = hasColorModeModule ? await kit$1.getNuxtModuleOptions("@nuxtjs/color-mode") : {};
|
|
5236
5725
|
let colorPreference = colorModeOptions.preference;
|
|
5237
5726
|
if (!colorPreference || colorPreference === "system")
|
|
5238
5727
|
colorPreference = colorModeOptions.fallback;
|
|
@@ -5336,7 +5825,7 @@ export const rootDir = ${JSON.stringify(nuxt.options.rootDir)}`;
|
|
|
5336
5825
|
await nitro.hooks.callHook("rollup:reload");
|
|
5337
5826
|
}
|
|
5338
5827
|
});
|
|
5339
|
-
} else if (kit$
|
|
5828
|
+
} else if (kit$1.isNuxtGenerate()) {
|
|
5340
5829
|
setupGenerateHandler(config, resolver);
|
|
5341
5830
|
} else if (nuxt.options.build) {
|
|
5342
5831
|
await setupBuildHandler(config, resolver, getDetectedRenderers, getCompatibilityMeta);
|