-
Notifications
You must be signed in to change notification settings - Fork 119
Expand file tree
/
Copy pathpatch-vercel-og-library.ts
More file actions
95 lines (74 loc) · 3.48 KB
/
patch-vercel-og-library.ts
File metadata and controls
95 lines (74 loc) · 3.48 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import { copyFileSync, existsSync, globSync, readFileSync, renameSync, writeFileSync } from "node:fs";
import path from "node:path";
import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
import { parseFile } from "@opennextjs/aws/build/patch/astCodePatcher.js";
import { patchVercelOgFallbackFont, patchVercelOgImport } from "./vercel-og.js";
type TraceInfo = { version: number; files: string[] };
/**
* Patches the usage of @vercel/og to be compatible with Cloudflare Workers.
*
* @param buildOpts Build options.
* @returns Whether the @vercel/og library is used.
*/
export function patchVercelOgLibrary(buildOpts: BuildOptions): boolean {
const { appBuildOutputPath, outputDir } = buildOpts;
const functionsPath = path.join(outputDir, "server-functions/default");
const packagePath = path.join(functionsPath, getPackagePath(buildOpts));
let useOg = false;
for (const traceInfoPath of globSync(".next/server/**/*.nft.json", { cwd: appBuildOutputPath })) {
const fullTraceInfoPath = path.join(appBuildOutputPath, traceInfoPath);
// Look for the Node version of the traced @vercel/og files
const traceInfo: TraceInfo = JSON.parse(readFileSync(fullTraceInfoPath, { encoding: "utf8" }));
const tracedNodePath = traceInfo.files.find((p) => p.endsWith("@vercel/og/index.node.js"));
if (!tracedNodePath) continue;
// If we are here, it means the application is using the @vercel/og library
// and there is an `index.edge.js` colocated file that we need to copy and patch.
useOg = true;
const outputDir = getOutputDir({ functionsPath, packagePath });
const outputEdgePath = path.join(outputDir, "index.edge.js");
// Ensure the edge version is available in the OpenNext node_modules.
if (!existsSync(outputEdgePath)) {
const tracedEdgePath = path.join(
path.dirname(fullTraceInfoPath),
tracedNodePath.replace("index.node.js", "index.edge.js")
);
copyFileSync(tracedEdgePath, outputEdgePath);
// On Next 16.2 and above, we also need to copy the yoga.wasm file used by the library.
const tracedWasmPath = path.join(
path.dirname(fullTraceInfoPath),
tracedNodePath.replace("index.node.js", "yoga.wasm")
);
if (existsSync(tracedWasmPath)) {
copyFileSync(tracedWasmPath, path.join(outputDir, "yoga.wasm"));
}
}
// Change font fetches in the library to use imports.
{
const ast = parseFile(outputEdgePath);
const { edits, matches } = patchVercelOgFallbackFont(ast);
writeFileSync(outputEdgePath, ast.commitEdits(edits));
if (matches.length > 0) {
const fontFileName = matches[0]!.getMatch("PATH")!.text();
renameSync(path.join(outputDir, fontFileName), path.join(outputDir, `${fontFileName}.bin`));
}
}
// Change node imports for the library to edge imports.
// This is only useful when turbopack is not used to bundle the function.
{
const routeFilePath = path.join(packagePath, traceInfoPath.replace(".nft.json", ""));
const ast = parseFile(routeFilePath);
const { edits } = patchVercelOgImport(ast);
writeFileSync(routeFilePath, ast.commitEdits(edits));
}
}
return useOg;
}
function getOutputDir(opts: { functionsPath: string; packagePath: string }) {
const vercelOgNodeModulePath = "node_modules/next/dist/compiled/@vercel/og";
const packageOutputPath = path.join(opts.packagePath, vercelOgNodeModulePath);
if (existsSync(packageOutputPath)) {
return packageOutputPath;
}
return path.join(opts.functionsPath, vercelOgNodeModulePath);
}