fix: package og runtime assets during vite build (#2895)

This commit is contained in:
Jesse Merhi
2026-06-26 18:36:04 +10:00
committed by GitHub
parent 637a30c103
commit a6a2f56fbf
3 changed files with 81 additions and 124 deletions
+68 -124
View File
@@ -1,5 +1,7 @@
import { copyFile, mkdir, stat } from "node:fs/promises";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { OG_FONT_PATHS } from "../server/og/ogAssets";
async function resolveExistingPath(candidates: string[]) {
for (const candidate of candidates) {
@@ -21,131 +23,73 @@ function nodeModuleCandidates(relativePath: string) {
];
}
const resvgWasmSource = await resolveExistingPath(
nodeModuleCandidates("@resvg/resvg-wasm/index_bg.wasm"),
);
const bricolage800Source = await resolveExistingPath(
nodeModuleCandidates(
"@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-800-normal.woff2",
),
);
const bricolage500Source = await resolveExistingPath(
nodeModuleCandidates(
"@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-500-normal.woff2",
),
);
const ibmPlex500Source = await resolveExistingPath(
nodeModuleCandidates("@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-500-normal.woff2"),
);
const notoSansSc800Source = await resolveExistingPath(
nodeModuleCandidates(
"@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-800-normal.woff2",
),
);
const notoSansSc500Source = await resolveExistingPath(
nodeModuleCandidates(
"@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-500-normal.woff2",
),
);
export async function copyOgAssets() {
const resvgWasmSource = await resolveExistingPath(
nodeModuleCandidates("@resvg/resvg-wasm/index_bg.wasm"),
);
const fontCopies = await Promise.all(
OG_FONT_PATHS.map(async (runtimePath) => {
const modulePath = runtimePath.replace(/^node_modules\//, "");
const source = await resolveExistingPath(nodeModuleCandidates(modulePath));
return {
source,
targets: [
path.resolve(".output/server", runtimePath),
path.resolve(".vercel/output/functions/__server.func", runtimePath),
],
};
}),
);
const copies = [
{
source: path.resolve("public/clawd-logo.png"),
targets: [
path.resolve(".output/server/clawd-logo.png"),
path.resolve(".output/server/public/clawd-logo.png"),
path.resolve(".vercel/output/functions/__server.func/clawd-logo.png"),
path.resolve(".vercel/output/functions/__server.func/public/clawd-logo.png"),
],
},
{
source: path.resolve("public/og-clawhub-watermark.png"),
targets: [
path.resolve(".output/server/og-clawhub-watermark.png"),
path.resolve(".output/server/public/og-clawhub-watermark.png"),
path.resolve(".vercel/output/functions/__server.func/og-clawhub-watermark.png"),
path.resolve(".vercel/output/functions/__server.func/public/og-clawhub-watermark.png"),
],
},
{
source: path.resolve("public/clawd-mark.png"),
targets: [
path.resolve(".output/server/clawd-mark.png"),
path.resolve(".output/server/public/clawd-mark.png"),
path.resolve(".vercel/output/functions/__server.func/clawd-mark.png"),
path.resolve(".vercel/output/functions/__server.func/public/clawd-mark.png"),
],
},
{
source: resvgWasmSource,
targets: [
path.resolve(".output/server/node_modules/@resvg/resvg-wasm/index_bg.wasm"),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@resvg/resvg-wasm/index_bg.wasm",
),
],
},
{
source: bricolage800Source,
targets: [
path.resolve(
".output/server/node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-800-normal.woff2",
),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-800-normal.woff2",
),
],
},
{
source: bricolage500Source,
targets: [
path.resolve(
".output/server/node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-500-normal.woff2",
),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-500-normal.woff2",
),
],
},
{
source: ibmPlex500Source,
targets: [
path.resolve(
".output/server/node_modules/@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-500-normal.woff2",
),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-500-normal.woff2",
),
],
},
{
source: notoSansSc800Source,
targets: [
path.resolve(
".output/server/node_modules/@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-800-normal.woff2",
),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-800-normal.woff2",
),
],
},
{
source: notoSansSc500Source,
targets: [
path.resolve(
".output/server/node_modules/@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-500-normal.woff2",
),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@fontsource/noto-sans-sc/files/noto-sans-sc-chinese-simplified-500-normal.woff2",
),
],
},
];
const copies = [
{
source: path.resolve("public/clawd-logo.png"),
targets: [
path.resolve(".output/server/clawd-logo.png"),
path.resolve(".output/server/public/clawd-logo.png"),
path.resolve(".vercel/output/functions/__server.func/clawd-logo.png"),
path.resolve(".vercel/output/functions/__server.func/public/clawd-logo.png"),
],
},
{
source: path.resolve("public/og-clawhub-watermark.png"),
targets: [
path.resolve(".output/server/og-clawhub-watermark.png"),
path.resolve(".output/server/public/og-clawhub-watermark.png"),
path.resolve(".vercel/output/functions/__server.func/og-clawhub-watermark.png"),
path.resolve(".vercel/output/functions/__server.func/public/og-clawhub-watermark.png"),
],
},
{
source: path.resolve("public/clawd-mark.png"),
targets: [
path.resolve(".output/server/clawd-mark.png"),
path.resolve(".output/server/public/clawd-mark.png"),
path.resolve(".vercel/output/functions/__server.func/clawd-mark.png"),
path.resolve(".vercel/output/functions/__server.func/public/clawd-mark.png"),
],
},
{
source: resvgWasmSource,
targets: [
path.resolve(".output/server/node_modules/@resvg/resvg-wasm/index_bg.wasm"),
path.resolve(
".vercel/output/functions/__server.func/node_modules/@resvg/resvg-wasm/index_bg.wasm",
),
],
},
...fontCopies,
];
for (const { source, targets } of copies) {
for (const target of targets) {
const parent = path.dirname(target);
await mkdir(parent, { recursive: true });
await copyFile(source, target);
for (const { source, targets } of copies) {
for (const target of targets) {
const parent = path.dirname(target);
await mkdir(parent, { recursive: true });
await copyFile(source, target);
}
}
}
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
await copyOgAssets();
}
+1
View File
@@ -33,6 +33,7 @@ const PUBLISHER_FONT_PATHS = [
"node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-800-normal.woff2",
...SHARED_FONT_PATHS,
];
export const OG_FONT_PATHS = Array.from(new Set([...DEFAULT_FONT_PATHS, ...PUBLISHER_FONT_PATHS]));
function getServerRootUrl() {
const nitroMain = (globalThis as unknown as GlobalNitroMain).__nitro_main__;
+12
View File
@@ -6,6 +6,7 @@ import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import viteReact from "@vitejs/plugin-react";
import { nitro } from "nitro/vite";
import { defineConfig, type Plugin } from "vite";
import { copyOgAssets } from "./scripts/copy-og-assets";
const require = createRequire(import.meta.url);
@@ -167,6 +168,16 @@ function patchArkSafariInOperator(): Plugin {
};
}
function copyOgAssetsPlugin(): Plugin {
return {
name: "copy-og-assets",
apply: "build",
async closeBundle() {
await copyOgAssets();
},
};
}
const config = defineConfig({
resolve: {
dedupe: ["convex", "@convex-dev/auth", "react", "react-dom"],
@@ -197,6 +208,7 @@ const config = defineConfig({
tailwindcss(),
tanstackStart(),
viteReact(),
copyOgAssetsPlugin(),
],
build: {
// Keep the shipped client bundle parseable in Safari/WebKit.