@opennextjs/cloudflare 0.3.10 → 0.4.1
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 +1 -64
- package/dist/api/{get-cloudflare-context.d.ts → cloudflare-context.d.ts} +8 -1
- package/dist/api/cloudflare-context.js +114 -0
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +1 -1
- package/dist/api/kvCache.d.ts +0 -5
- package/dist/api/kvCache.js +15 -28
- package/dist/cli/build/build.d.ts +1 -1
- package/dist/cli/build/build.js +2 -12
- package/dist/cli/build/bundle-server.d.ts +4 -5
- package/dist/cli/build/bundle-server.js +44 -37
- package/dist/cli/build/open-next/compile-env-files.d.ts +1 -1
- package/dist/cli/build/open-next/compile-env-files.js +2 -2
- package/dist/cli/build/patches/ast/optional-deps.d.ts +6 -3
- package/dist/cli/build/patches/ast/optional-deps.js +4 -4
- package/dist/cli/build/patches/ast/util.d.ts +15 -4
- package/dist/cli/build/patches/ast/util.js +16 -5
- package/dist/cli/build/patches/ast/vercel-og.d.ts +23 -0
- package/dist/cli/build/patches/ast/vercel-og.js +58 -0
- package/dist/cli/build/patches/ast/vercel-og.spec.d.ts +1 -0
- package/dist/cli/build/patches/ast/vercel-og.spec.js +22 -0
- package/dist/cli/build/patches/investigated/copy-package-cli-files.d.ts +4 -3
- package/dist/cli/build/patches/investigated/copy-package-cli-files.js +8 -5
- package/dist/cli/build/patches/investigated/index.d.ts +1 -0
- package/dist/cli/build/patches/investigated/index.js +1 -0
- package/dist/cli/build/patches/investigated/patch-cache.d.ts +2 -2
- package/dist/cli/build/patches/investigated/patch-cache.js +7 -6
- package/dist/cli/build/patches/investigated/patch-require.d.ts +1 -4
- package/dist/cli/build/patches/investigated/patch-require.js +1 -4
- package/dist/cli/build/patches/investigated/patch-vercel-og-library.d.ts +7 -0
- package/dist/cli/build/patches/investigated/patch-vercel-og-library.js +39 -0
- package/dist/cli/build/patches/investigated/patch-vercel-og-library.spec.d.ts +1 -0
- package/dist/cli/build/patches/investigated/patch-vercel-og-library.spec.js +50 -0
- package/dist/cli/build/patches/investigated/update-webpack-chunks-file/index.d.ts +2 -5
- package/dist/cli/build/patches/investigated/update-webpack-chunks-file/index.js +6 -6
- package/dist/cli/build/patches/plugins/require-page.d.ts +6 -0
- package/dist/cli/build/patches/plugins/require-page.js +70 -0
- package/dist/cli/build/patches/plugins/wrangler-external.d.ts +20 -0
- package/dist/cli/build/patches/plugins/wrangler-external.js +36 -0
- package/dist/cli/build/patches/to-investigate/index.d.ts +0 -1
- package/dist/cli/build/patches/to-investigate/index.js +0 -1
- package/dist/cli/build/patches/to-investigate/inline-eval-manifest.d.ts +2 -2
- package/dist/cli/build/patches/to-investigate/inline-eval-manifest.js +21 -17
- package/dist/cli/build/patches/to-investigate/inline-middleware-manifest-require.d.ts +2 -2
- package/dist/cli/build/patches/to-investigate/inline-middleware-manifest-require.js +4 -2
- package/dist/cli/build/patches/to-investigate/patch-find-dir.d.ts +3 -6
- package/dist/cli/build/patches/to-investigate/patch-find-dir.js +11 -11
- package/dist/cli/build/patches/to-investigate/patch-read-file.d.ts +3 -3
- package/dist/cli/build/patches/to-investigate/patch-read-file.js +15 -16
- package/dist/cli/build/patches/to-investigate/wrangler-deps.d.ts +2 -2
- package/dist/cli/build/patches/to-investigate/wrangler-deps.js +36 -67
- package/dist/cli/build/utils/create-config-files.d.ts +1 -1
- package/dist/cli/project-options.d.ts +7 -0
- package/dist/cli/project-options.js +1 -0
- package/package.json +4 -4
- package/dist/api/get-cloudflare-context.js +0 -42
- package/dist/cli/build/patches/to-investigate/inline-next-require.d.ts +0 -6
- package/dist/cli/build/patches/to-investigate/inline-next-require.js +0 -36
- package/dist/cli/config.d.ts +0 -42
- package/dist/cli/config.js +0 -92
|
@@ -7,7 +7,7 @@ export type RuleConfig = NapiConfig & {
|
|
|
7
7
|
fix?: string;
|
|
8
8
|
};
|
|
9
9
|
/**
|
|
10
|
-
* Returns the `Edit`s for an ast-grep rule in yaml format
|
|
10
|
+
* Returns the `Edit`s and `Match`es for an ast-grep rule in yaml format
|
|
11
11
|
*
|
|
12
12
|
* The rule must have a `fix` to rewrite the matched node.
|
|
13
13
|
*
|
|
@@ -16,11 +16,22 @@ export type RuleConfig = NapiConfig & {
|
|
|
16
16
|
* @param rule The rule. Either a yaml string or an instance of `RuleConfig`
|
|
17
17
|
* @param root The root node
|
|
18
18
|
* @param once only apply once
|
|
19
|
-
* @returns A list of edits.
|
|
19
|
+
* @returns A list of edits and a list of matches.
|
|
20
20
|
*/
|
|
21
|
-
export declare function
|
|
21
|
+
export declare function applyRule(rule: string | RuleConfig, root: SgNode, { once }?: {
|
|
22
22
|
once?: boolean | undefined;
|
|
23
|
-
}):
|
|
23
|
+
}): {
|
|
24
|
+
edits: Edit[];
|
|
25
|
+
matches: SgNode<import("@ast-grep/napi/types/staticTypes").TypesMap, import("@ast-grep/napi/types/staticTypes").Kinds<import("@ast-grep/napi/types/staticTypes").TypesMap>>[];
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Parse a file and obtain its root.
|
|
29
|
+
*
|
|
30
|
+
* @param path The file path
|
|
31
|
+
* @param lang The language to parse. Defaults to TypeScript.
|
|
32
|
+
* @returns The root for the file.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseFile(path: string, lang?: Lang): SgNode<import("@ast-grep/napi/types/staticTypes").TypesMap, import("@ast-grep/napi/types/staticTypes").Kinds<import("@ast-grep/napi/types/staticTypes").TypesMap>>;
|
|
24
35
|
/**
|
|
25
36
|
* Patches the code from by applying the rule.
|
|
26
37
|
*
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { Lang, parse } from "@ast-grep/napi";
|
|
2
3
|
import yaml from "yaml";
|
|
3
4
|
/**
|
|
4
|
-
* Returns the `Edit`s for an ast-grep rule in yaml format
|
|
5
|
+
* Returns the `Edit`s and `Match`es for an ast-grep rule in yaml format
|
|
5
6
|
*
|
|
6
7
|
* The rule must have a `fix` to rewrite the matched node.
|
|
7
8
|
*
|
|
@@ -10,9 +11,9 @@ import yaml from "yaml";
|
|
|
10
11
|
* @param rule The rule. Either a yaml string or an instance of `RuleConfig`
|
|
11
12
|
* @param root The root node
|
|
12
13
|
* @param once only apply once
|
|
13
|
-
* @returns A list of edits.
|
|
14
|
+
* @returns A list of edits and a list of matches.
|
|
14
15
|
*/
|
|
15
|
-
export function
|
|
16
|
+
export function applyRule(rule, root, { once = false } = {}) {
|
|
16
17
|
const ruleConfig = typeof rule === "string" ? yaml.parse(rule) : rule;
|
|
17
18
|
if (ruleConfig.transform) {
|
|
18
19
|
throw new Error("transform is not supported");
|
|
@@ -33,7 +34,17 @@ export function getRuleEdits(rule, root, { once = false } = {}) {
|
|
|
33
34
|
.join(""))
|
|
34
35
|
.replace(/\$([A-Z0-9_]+)/g, (m, name) => match.getMatch(name)?.text() ?? m)));
|
|
35
36
|
});
|
|
36
|
-
return edits;
|
|
37
|
+
return { edits, matches };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Parse a file and obtain its root.
|
|
41
|
+
*
|
|
42
|
+
* @param path The file path
|
|
43
|
+
* @param lang The language to parse. Defaults to TypeScript.
|
|
44
|
+
* @returns The root for the file.
|
|
45
|
+
*/
|
|
46
|
+
export function parseFile(path, lang = Lang.TypeScript) {
|
|
47
|
+
return parse(lang, readFileSync(path, { encoding: "utf-8" })).root();
|
|
37
48
|
}
|
|
38
49
|
/**
|
|
39
50
|
* Patches the code from by applying the rule.
|
|
@@ -49,6 +60,6 @@ export function getRuleEdits(rule, root, { once = false } = {}) {
|
|
|
49
60
|
*/
|
|
50
61
|
export function patchCode(code, rule, { lang = Lang.TypeScript, once = false } = {}) {
|
|
51
62
|
const node = parse(lang, code).root();
|
|
52
|
-
const edits =
|
|
63
|
+
const { edits } = applyRule(rule, node, { once });
|
|
53
64
|
return node.commitEdits(edits);
|
|
54
65
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SgNode } from "@ast-grep/napi";
|
|
2
|
+
export declare const vercelOgImportRule = "\nrule:\n pattern: $NODE\n kind: string\n regex: \"next/dist/compiled/@vercel/og/index\\\\.node\\\\.js\"\ninside:\n kind: arguments\n inside:\n kind: call_expression\n stopBy: end\n has:\n field: function\n regex: \"import\"\n\nfix: |-\n \"next/dist/compiled/@vercel/og/index.edge.js\"\n";
|
|
3
|
+
/**
|
|
4
|
+
* Patches Node.js imports for the library to be Edge imports.
|
|
5
|
+
*
|
|
6
|
+
* @param root Root node.
|
|
7
|
+
* @returns Results of applying the rule.
|
|
8
|
+
*/
|
|
9
|
+
export declare function patchVercelOgImport(root: SgNode): {
|
|
10
|
+
edits: import("@ast-grep/napi").Edit[];
|
|
11
|
+
matches: SgNode<import("@ast-grep/napi/types/staticTypes.js").TypesMap, import("@ast-grep/napi/types/staticTypes.js").Kinds<import("@ast-grep/napi/types/staticTypes.js").TypesMap>>[];
|
|
12
|
+
};
|
|
13
|
+
export declare const vercelOgFallbackFontRule = "\nrule:\n kind: variable_declaration\n all:\n - has:\n kind: variable_declarator\n has:\n kind: identifier\n regex: ^fallbackFont$\n - has:\n kind: call_expression\n pattern: fetch(new URL(\"$PATH\", $$$REST))\n stopBy: end\n\nfix: |-\n async function getFallbackFont() {\n // .bin is used so that a loader does not need to be configured for .ttf files\n return (await import(\"$PATH.bin\")).default;\n }\n\n var fallbackFont = getFallbackFont();\n";
|
|
14
|
+
/**
|
|
15
|
+
* Patches the default font fetching to use a .bin import.
|
|
16
|
+
*
|
|
17
|
+
* @param root Root node.
|
|
18
|
+
* @returns Results of applying the rule.
|
|
19
|
+
*/
|
|
20
|
+
export declare function patchVercelOgFallbackFont(root: SgNode): {
|
|
21
|
+
edits: import("@ast-grep/napi").Edit[];
|
|
22
|
+
matches: SgNode<import("@ast-grep/napi/types/staticTypes.js").TypesMap, import("@ast-grep/napi/types/staticTypes.js").Kinds<import("@ast-grep/napi/types/staticTypes.js").TypesMap>>[];
|
|
23
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { applyRule } from "./util.js";
|
|
2
|
+
export const vercelOgImportRule = `
|
|
3
|
+
rule:
|
|
4
|
+
pattern: $NODE
|
|
5
|
+
kind: string
|
|
6
|
+
regex: "next/dist/compiled/@vercel/og/index\\\\.node\\\\.js"
|
|
7
|
+
inside:
|
|
8
|
+
kind: arguments
|
|
9
|
+
inside:
|
|
10
|
+
kind: call_expression
|
|
11
|
+
stopBy: end
|
|
12
|
+
has:
|
|
13
|
+
field: function
|
|
14
|
+
regex: "import"
|
|
15
|
+
|
|
16
|
+
fix: |-
|
|
17
|
+
"next/dist/compiled/@vercel/og/index.edge.js"
|
|
18
|
+
`;
|
|
19
|
+
/**
|
|
20
|
+
* Patches Node.js imports for the library to be Edge imports.
|
|
21
|
+
*
|
|
22
|
+
* @param root Root node.
|
|
23
|
+
* @returns Results of applying the rule.
|
|
24
|
+
*/
|
|
25
|
+
export function patchVercelOgImport(root) {
|
|
26
|
+
return applyRule(vercelOgImportRule, root);
|
|
27
|
+
}
|
|
28
|
+
export const vercelOgFallbackFontRule = `
|
|
29
|
+
rule:
|
|
30
|
+
kind: variable_declaration
|
|
31
|
+
all:
|
|
32
|
+
- has:
|
|
33
|
+
kind: variable_declarator
|
|
34
|
+
has:
|
|
35
|
+
kind: identifier
|
|
36
|
+
regex: ^fallbackFont$
|
|
37
|
+
- has:
|
|
38
|
+
kind: call_expression
|
|
39
|
+
pattern: fetch(new URL("$PATH", $$$REST))
|
|
40
|
+
stopBy: end
|
|
41
|
+
|
|
42
|
+
fix: |-
|
|
43
|
+
async function getFallbackFont() {
|
|
44
|
+
// .bin is used so that a loader does not need to be configured for .ttf files
|
|
45
|
+
return (await import("$PATH.bin")).default;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
var fallbackFont = getFallbackFont();
|
|
49
|
+
`;
|
|
50
|
+
/**
|
|
51
|
+
* Patches the default font fetching to use a .bin import.
|
|
52
|
+
*
|
|
53
|
+
* @param root Root node.
|
|
54
|
+
* @returns Results of applying the rule.
|
|
55
|
+
*/
|
|
56
|
+
export function patchVercelOgFallbackFont(root) {
|
|
57
|
+
return applyRule(vercelOgFallbackFontRule, root);
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { patchCode } from "./util";
|
|
3
|
+
import { vercelOgFallbackFontRule, vercelOgImportRule } from "./vercel-og";
|
|
4
|
+
describe("vercelOgImportRule", () => {
|
|
5
|
+
it("should rewrite a node import to an edge import", () => {
|
|
6
|
+
const code = `e.exports=import("next/dist/compiled/@vercel/og/index.node.js")`;
|
|
7
|
+
expect(patchCode(code, vercelOgImportRule)).toMatchInlineSnapshot(`"e.exports=import("next/dist/compiled/@vercel/og/index.edge.js")"`);
|
|
8
|
+
});
|
|
9
|
+
});
|
|
10
|
+
describe("vercelOgFallbackFontRule", () => {
|
|
11
|
+
it("should replace a fetch call for a font with an import", () => {
|
|
12
|
+
const code = `var fallbackFont = fetch(new URL("./noto-sans-v27-latin-regular.ttf", import.meta.url)).then((res) => res.arrayBuffer());`;
|
|
13
|
+
expect(patchCode(code, vercelOgFallbackFontRule)).toMatchInlineSnapshot(`
|
|
14
|
+
"async function getFallbackFont() {
|
|
15
|
+
// .bin is used so that a loader does not need to be configured for .ttf files
|
|
16
|
+
return (await import("./noto-sans-v27-latin-regular.ttf.bin")).default;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var fallbackFont = getFallbackFont();"
|
|
20
|
+
`);
|
|
21
|
+
});
|
|
22
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
|
-
import { Config } from "../../../config.js";
|
|
3
2
|
/**
|
|
4
|
-
* Copies
|
|
3
|
+
* Copies
|
|
4
|
+
* - the template files present in the cloudflare adapter package to `.open-next/cloudflare-templates`
|
|
5
|
+
* - `worker.js` to `.open-next/`
|
|
5
6
|
*/
|
|
6
|
-
export declare function copyPackageCliFiles(packageDistDir: string,
|
|
7
|
+
export declare function copyPackageCliFiles(packageDistDir: string, buildOpts: BuildOptions): void;
|
|
@@ -2,12 +2,15 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { getOutputWorkerPath } from "../../bundle-server.js";
|
|
4
4
|
/**
|
|
5
|
-
* Copies
|
|
5
|
+
* Copies
|
|
6
|
+
* - the template files present in the cloudflare adapter package to `.open-next/cloudflare-templates`
|
|
7
|
+
* - `worker.js` to `.open-next/`
|
|
6
8
|
*/
|
|
7
|
-
export function copyPackageCliFiles(packageDistDir,
|
|
9
|
+
export function copyPackageCliFiles(packageDistDir, buildOpts) {
|
|
8
10
|
console.log("# copyPackageTemplateFiles");
|
|
9
|
-
const sourceDir = path.join(packageDistDir, "cli");
|
|
10
|
-
const destinationDir = path.join(
|
|
11
|
+
const sourceDir = path.join(packageDistDir, "cli/templates");
|
|
12
|
+
const destinationDir = path.join(buildOpts.outputDir, "cloudflare-templates");
|
|
13
|
+
fs.mkdirSync(destinationDir, { recursive: true });
|
|
11
14
|
fs.cpSync(sourceDir, destinationDir, { recursive: true });
|
|
12
|
-
fs.copyFileSync(path.join(packageDistDir, "cli
|
|
15
|
+
fs.copyFileSync(path.join(packageDistDir, "cli/templates/worker.js"), getOutputWorkerPath(buildOpts));
|
|
13
16
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
2
|
/**
|
|
3
3
|
* Sets up the OpenNext cache handler in a Next.js build.
|
|
4
4
|
*
|
|
@@ -10,4 +10,4 @@ import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
|
10
10
|
* build-time. Therefore, we have to manually override the default way that the cache handler is
|
|
11
11
|
* instantiated with a dynamic require that uses a string literal for the path.
|
|
12
12
|
*/
|
|
13
|
-
export declare function patchCache(code: string,
|
|
13
|
+
export declare function patchCache(code: string, buildOpts: BuildOptions): Promise<string>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
2
3
|
import { normalizePath } from "../../utils/index.js";
|
|
3
4
|
/**
|
|
4
5
|
* Sets up the OpenNext cache handler in a Next.js build.
|
|
@@ -11,13 +12,13 @@ import { normalizePath } from "../../utils/index.js";
|
|
|
11
12
|
* build-time. Therefore, we have to manually override the default way that the cache handler is
|
|
12
13
|
* instantiated with a dynamic require that uses a string literal for the path.
|
|
13
14
|
*/
|
|
14
|
-
export async function patchCache(code,
|
|
15
|
-
const {
|
|
15
|
+
export async function patchCache(code, buildOpts) {
|
|
16
|
+
const { outputDir } = buildOpts;
|
|
16
17
|
// TODO: switch to cache.mjs
|
|
17
|
-
const outputPath = path.join(outputDir, "server-functions
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
|
|
18
|
+
const outputPath = path.join(outputDir, "server-functions/default");
|
|
19
|
+
const cacheFile = path.join(outputPath, getPackagePath(buildOpts), "cache.cjs");
|
|
20
|
+
return code.replace("const { cacheHandler } = this.nextConfig;", `
|
|
21
|
+
const cacheHandler = null;
|
|
21
22
|
CacheHandler = require('${normalizePath(cacheFile)}').default;
|
|
22
23
|
`);
|
|
23
24
|
}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* See https://github.com/evanw/esbuild/issues/1921 and linked issues
|
|
4
|
-
* Some of the solutions are based on `module.createRequire()` not implemented in workerd.
|
|
5
|
-
* James on Aug 29: `module.createRequire()` is planned.
|
|
2
|
+
* Replaces webpack `__require` with actual `require`
|
|
6
3
|
*/
|
|
7
4
|
export declare function patchRequire(code: string): string;
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* See https://github.com/evanw/esbuild/issues/1921 and linked issues
|
|
4
|
-
* Some of the solutions are based on `module.createRequire()` not implemented in workerd.
|
|
5
|
-
* James on Aug 29: `module.createRequire()` is planned.
|
|
2
|
+
* Replaces webpack `__require` with actual `require`
|
|
6
3
|
*/
|
|
7
4
|
export function patchRequire(code) {
|
|
8
5
|
return code.replace(/__require\d?\(/g, "require(").replace(/__require\d?\./g, "require.");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
|
+
/**
|
|
3
|
+
* Patches the usage of @vercel/og to be compatible with Cloudflare Workers.
|
|
4
|
+
*
|
|
5
|
+
* @param buildOpts Build options.
|
|
6
|
+
*/
|
|
7
|
+
export declare function patchVercelOgLibrary(buildOpts: BuildOptions): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
4
|
+
import { globSync } from "glob";
|
|
5
|
+
import { parseFile } from "../ast/util.js";
|
|
6
|
+
import { patchVercelOgFallbackFont, patchVercelOgImport } from "../ast/vercel-og.js";
|
|
7
|
+
/**
|
|
8
|
+
* Patches the usage of @vercel/og to be compatible with Cloudflare Workers.
|
|
9
|
+
*
|
|
10
|
+
* @param buildOpts Build options.
|
|
11
|
+
*/
|
|
12
|
+
export function patchVercelOgLibrary(buildOpts) {
|
|
13
|
+
const { appBuildOutputPath, outputDir } = buildOpts;
|
|
14
|
+
const packagePath = path.join(outputDir, "server-functions/default", getPackagePath(buildOpts));
|
|
15
|
+
for (const traceInfoPath of globSync(path.join(appBuildOutputPath, ".next/server/**/*.nft.json"))) {
|
|
16
|
+
const traceInfo = JSON.parse(readFileSync(traceInfoPath, { encoding: "utf8" }));
|
|
17
|
+
const tracedNodePath = traceInfo.files.find((p) => p.endsWith("@vercel/og/index.node.js"));
|
|
18
|
+
if (!tracedNodePath)
|
|
19
|
+
continue;
|
|
20
|
+
const outputDir = path.join(packagePath, "node_modules/next/dist/compiled/@vercel/og");
|
|
21
|
+
const outputEdgePath = path.join(outputDir, "index.edge.js");
|
|
22
|
+
// Ensure the edge version is available in the OpenNext node_modules.
|
|
23
|
+
if (!existsSync(outputEdgePath)) {
|
|
24
|
+
const tracedEdgePath = path.join(path.dirname(traceInfoPath), tracedNodePath.replace("index.node.js", "index.edge.js"));
|
|
25
|
+
copyFileSync(tracedEdgePath, outputEdgePath);
|
|
26
|
+
// Change font fetches in the library to use imports.
|
|
27
|
+
const node = parseFile(outputEdgePath);
|
|
28
|
+
const { edits, matches } = patchVercelOgFallbackFont(node);
|
|
29
|
+
writeFileSync(outputEdgePath, node.commitEdits(edits));
|
|
30
|
+
const fontFileName = matches[0].getMatch("PATH").text();
|
|
31
|
+
renameSync(path.join(outputDir, fontFileName), path.join(outputDir, `${fontFileName}.bin`));
|
|
32
|
+
}
|
|
33
|
+
// Change node imports for the library to edge imports.
|
|
34
|
+
const routeFilePath = traceInfoPath.replace(appBuildOutputPath, packagePath).replace(".nft.json", "");
|
|
35
|
+
const node = parseFile(routeFilePath);
|
|
36
|
+
const { edits } = patchVercelOgImport(node);
|
|
37
|
+
writeFileSync(routeFilePath, node.commitEdits(edits));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import mockFs from "mock-fs";
|
|
4
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
5
|
+
import { patchVercelOgLibrary } from "./patch-vercel-og-library";
|
|
6
|
+
const nodeModulesVercelOgDir = "node_modules/.pnpm/next@14.2.11/node_modules/next/dist/compiled/@vercel/og";
|
|
7
|
+
const nextServerOgNftPath = "examples/api/.next/server/app/og/route.js.nft.json";
|
|
8
|
+
const openNextFunctionDir = "examples/api/.open-next/server-functions/default/examples/api";
|
|
9
|
+
const openNextOgRoutePath = path.join(openNextFunctionDir, ".next/server/app/og/route.js");
|
|
10
|
+
const openNextVercelOgDir = path.join(openNextFunctionDir, "node_modules/next/dist/compiled/@vercel/og");
|
|
11
|
+
const buildOpts = {
|
|
12
|
+
appBuildOutputPath: "examples/api",
|
|
13
|
+
monorepoRoot: "",
|
|
14
|
+
outputDir: "examples/api/.open-next",
|
|
15
|
+
};
|
|
16
|
+
describe("patchVercelOgLibrary", () => {
|
|
17
|
+
beforeAll(() => {
|
|
18
|
+
mockFs();
|
|
19
|
+
mkdirSync(nodeModulesVercelOgDir, { recursive: true });
|
|
20
|
+
mkdirSync(path.dirname(nextServerOgNftPath), { recursive: true });
|
|
21
|
+
mkdirSync(path.dirname(openNextOgRoutePath), { recursive: true });
|
|
22
|
+
mkdirSync(openNextVercelOgDir, { recursive: true });
|
|
23
|
+
writeFileSync(nextServerOgNftPath, JSON.stringify({ version: 1, files: [`../../../../../../${nodeModulesVercelOgDir}/index.node.js`] }));
|
|
24
|
+
writeFileSync(path.join(nodeModulesVercelOgDir, "index.edge.js"), `var fallbackFont = fetch(new URL("./noto-sans-v27-latin-regular.ttf", import.meta.url)).then((res) => res.arrayBuffer());`);
|
|
25
|
+
writeFileSync(openNextOgRoutePath, `e.exports=import("next/dist/compiled/@vercel/og/index.node.js")`);
|
|
26
|
+
writeFileSync(path.join(openNextVercelOgDir, "index.node.js"), "");
|
|
27
|
+
writeFileSync(path.join(openNextVercelOgDir, "noto-sans-v27-latin-regular.ttf"), "");
|
|
28
|
+
});
|
|
29
|
+
afterAll(() => mockFs.restore());
|
|
30
|
+
it("should patch the open-next files correctly", () => {
|
|
31
|
+
patchVercelOgLibrary(buildOpts);
|
|
32
|
+
expect(readdirSync(openNextVercelOgDir)).toMatchInlineSnapshot(`
|
|
33
|
+
[
|
|
34
|
+
"index.edge.js",
|
|
35
|
+
"index.node.js",
|
|
36
|
+
"noto-sans-v27-latin-regular.ttf.bin",
|
|
37
|
+
]
|
|
38
|
+
`);
|
|
39
|
+
expect(readFileSync(path.join(openNextVercelOgDir, "index.edge.js"), { encoding: "utf-8" }))
|
|
40
|
+
.toMatchInlineSnapshot(`
|
|
41
|
+
"async function getFallbackFont() {
|
|
42
|
+
// .bin is used so that a loader does not need to be configured for .ttf files
|
|
43
|
+
return (await import("./noto-sans-v27-latin-regular.ttf.bin")).default;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
var fallbackFont = getFallbackFont();"
|
|
47
|
+
`);
|
|
48
|
+
expect(readFileSync(openNextOgRoutePath, { encoding: "utf-8" })).toMatchInlineSnapshot(`"e.exports=import("next/dist/compiled/@vercel/og/index.edge.js")"`);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
2
|
/**
|
|
3
3
|
* Fixes the webpack-runtime.js file by removing its webpack dynamic requires.
|
|
4
|
-
*
|
|
5
|
-
* This hack is particularly bad as it indicates that files inside the output directory still get a hold of files from the outside: `${nextjsAppPaths.standaloneAppServerDir}/webpack-runtime.js`
|
|
6
|
-
* so this shows that not everything that's needed to deploy the application is in the output directory...
|
|
7
4
|
*/
|
|
8
|
-
export declare function updateWebpackChunksFile(
|
|
5
|
+
export declare function updateWebpackChunksFile(buildOpts: BuildOptions): Promise<void>;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
3
4
|
import { getUpdatedWebpackChunksFileContent } from "./get-updated-webpack-chunks-file-content.js";
|
|
4
5
|
/**
|
|
5
6
|
* Fixes the webpack-runtime.js file by removing its webpack dynamic requires.
|
|
6
|
-
*
|
|
7
|
-
* This hack is particularly bad as it indicates that files inside the output directory still get a hold of files from the outside: `${nextjsAppPaths.standaloneAppServerDir}/webpack-runtime.js`
|
|
8
|
-
* so this shows that not everything that's needed to deploy the application is in the output directory...
|
|
9
7
|
*/
|
|
10
|
-
export async function updateWebpackChunksFile(
|
|
8
|
+
export async function updateWebpackChunksFile(buildOpts) {
|
|
11
9
|
console.log("# updateWebpackChunksFile");
|
|
12
|
-
const
|
|
10
|
+
const { outputDir } = buildOpts;
|
|
11
|
+
const dotNextServerDir = join(outputDir, "server-functions/default", getPackagePath(buildOpts), ".next/server");
|
|
12
|
+
const webpackRuntimeFile = join(dotNextServerDir, "webpack-runtime.js");
|
|
13
13
|
const fileContent = readFileSync(webpackRuntimeFile, "utf-8");
|
|
14
|
-
const chunks = readdirSync(join(
|
|
14
|
+
const chunks = readdirSync(join(dotNextServerDir, "chunks"))
|
|
15
15
|
.filter((chunk) => /^\d+\.js$/.test(chunk))
|
|
16
16
|
.map((chunk) => {
|
|
17
17
|
console.log(` - chunk ${chunk}`);
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { getPackagePath } from "@opennextjs/aws/build/helper.js";
|
|
5
|
+
import { getCrossPlatformPathRegex } from "@opennextjs/aws/utils/regex.js";
|
|
6
|
+
import { patchCode } from "../ast/util.js";
|
|
7
|
+
export default function inlineRequirePagePlugin(buildOpts) {
|
|
8
|
+
return {
|
|
9
|
+
name: "inline-require-page",
|
|
10
|
+
setup: async (build) => {
|
|
11
|
+
build.onLoad({
|
|
12
|
+
filter: getCrossPlatformPathRegex(String.raw `/next/dist/server/require\.js$`, { escape: false }),
|
|
13
|
+
}, async ({ path }) => {
|
|
14
|
+
const jsCode = await readFile(path, "utf8");
|
|
15
|
+
if (/function requirePage\(/.test(jsCode)) {
|
|
16
|
+
return { contents: patchCode(jsCode, getRule(buildOpts)) };
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function getRule(buildOpts) {
|
|
23
|
+
const { outputDir } = buildOpts;
|
|
24
|
+
const serverDir = join(outputDir, "server-functions/default", getPackagePath(buildOpts), ".next/server");
|
|
25
|
+
const pagesManifestFile = join(serverDir, "pages-manifest.json");
|
|
26
|
+
const appPathsManifestFile = join(serverDir, "app-paths-manifest.json");
|
|
27
|
+
const pagesManifests = existsSync(pagesManifestFile)
|
|
28
|
+
? Object.values(JSON.parse(readFileSync(pagesManifestFile, "utf-8")))
|
|
29
|
+
: [];
|
|
30
|
+
const appPathsManifests = existsSync(appPathsManifestFile)
|
|
31
|
+
? Object.values(JSON.parse(readFileSync(appPathsManifestFile, "utf-8")))
|
|
32
|
+
: [];
|
|
33
|
+
const manifests = pagesManifests.concat(appPathsManifests);
|
|
34
|
+
const htmlFiles = manifests.filter((file) => file.endsWith(".html"));
|
|
35
|
+
const jsFiles = manifests.filter((file) => file.endsWith(".js"));
|
|
36
|
+
// Inline fs access and dynamic require that are not supported by workerd.
|
|
37
|
+
const fnBody = `
|
|
38
|
+
// html
|
|
39
|
+
${htmlFiles
|
|
40
|
+
.map((file) => `if (pagePath.endsWith("${file}")) {
|
|
41
|
+
return ${JSON.stringify(readFileSync(join(serverDir, file), "utf-8"))};
|
|
42
|
+
}`)
|
|
43
|
+
.join("\n")}
|
|
44
|
+
// js
|
|
45
|
+
process.env.__NEXT_PRIVATE_RUNTIME_TYPE = isAppPath ? 'app' : 'pages';
|
|
46
|
+
try {
|
|
47
|
+
${jsFiles
|
|
48
|
+
.map((file) => `if (pagePath.endsWith("${file}")) {
|
|
49
|
+
return require(${JSON.stringify(join(serverDir, file))});
|
|
50
|
+
}`)
|
|
51
|
+
.join("\n")}
|
|
52
|
+
} finally {
|
|
53
|
+
process.env.__NEXT_PRIVATE_RUNTIME_TYPE = '';
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
return {
|
|
57
|
+
rule: {
|
|
58
|
+
pattern: `
|
|
59
|
+
function requirePage($PAGE, $DIST_DIR, $IS_APPP_ATH) {
|
|
60
|
+
const $_ = getPagePath($$$ARGS);
|
|
61
|
+
$$$_BODY
|
|
62
|
+
}`,
|
|
63
|
+
},
|
|
64
|
+
fix: `
|
|
65
|
+
function requirePage($PAGE, $DIST_DIR, $IS_APPP_ATH) {
|
|
66
|
+
const pagePath = getPagePath($$$ARGS);
|
|
67
|
+
${fnBody}
|
|
68
|
+
}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESBuild plugin to mark files bundled by wrangler as external.
|
|
3
|
+
*
|
|
4
|
+
* `.wasm` and `.bin` will ultimately be bundled by wrangler.
|
|
5
|
+
* We should only mark them as external in the adapter.
|
|
6
|
+
*
|
|
7
|
+
* However simply marking them as external would copy the import path to the bundle,
|
|
8
|
+
* i.e. `import("./file.wasm?module")` and given than the bundle is generated in a
|
|
9
|
+
* different location than the input files, the relative path would not be valid.
|
|
10
|
+
*
|
|
11
|
+
* This ESBuild plugin convert relative paths to absolute paths so that they are
|
|
12
|
+
* still valid from inside the bundle.
|
|
13
|
+
*
|
|
14
|
+
* ref: https://developers.cloudflare.com/workers/wrangler/bundling/
|
|
15
|
+
*/
|
|
16
|
+
import type { PluginBuild } from "esbuild";
|
|
17
|
+
export default function setWranglerExternal(): {
|
|
18
|
+
name: string;
|
|
19
|
+
setup: (build: PluginBuild) => Promise<void>;
|
|
20
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ESBuild plugin to mark files bundled by wrangler as external.
|
|
3
|
+
*
|
|
4
|
+
* `.wasm` and `.bin` will ultimately be bundled by wrangler.
|
|
5
|
+
* We should only mark them as external in the adapter.
|
|
6
|
+
*
|
|
7
|
+
* However simply marking them as external would copy the import path to the bundle,
|
|
8
|
+
* i.e. `import("./file.wasm?module")` and given than the bundle is generated in a
|
|
9
|
+
* different location than the input files, the relative path would not be valid.
|
|
10
|
+
*
|
|
11
|
+
* This ESBuild plugin convert relative paths to absolute paths so that they are
|
|
12
|
+
* still valid from inside the bundle.
|
|
13
|
+
*
|
|
14
|
+
* ref: https://developers.cloudflare.com/workers/wrangler/bundling/
|
|
15
|
+
*/
|
|
16
|
+
import { dirname, resolve } from "node:path";
|
|
17
|
+
export default function setWranglerExternal() {
|
|
18
|
+
return {
|
|
19
|
+
name: "wrangler-externals",
|
|
20
|
+
setup: async (build) => {
|
|
21
|
+
const namespace = "wrangler-externals-plugin";
|
|
22
|
+
build.onResolve({ filter: /(\.bin|\.wasm\?module)$/ }, ({ path, importer }) => {
|
|
23
|
+
return {
|
|
24
|
+
path: resolve(dirname(importer), path),
|
|
25
|
+
namespace,
|
|
26
|
+
external: true,
|
|
27
|
+
};
|
|
28
|
+
});
|
|
29
|
+
build.onLoad({ filter: /.*/, namespace }, async ({ path }) => {
|
|
30
|
+
return {
|
|
31
|
+
contents: `export * from '${path}';`,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from "./inline-eval-manifest.js";
|
|
2
2
|
export * from "./inline-middleware-manifest-require.js";
|
|
3
|
-
export * from "./inline-next-require.js";
|
|
4
3
|
export * from "./patch-exception-bubbling.js";
|
|
5
4
|
export * from "./patch-find-dir.js";
|
|
6
5
|
export * from "./patch-load-instrumentation-module.js";
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export * from "./inline-eval-manifest.js";
|
|
2
2
|
export * from "./inline-middleware-manifest-require.js";
|
|
3
|
-
export * from "./inline-next-require.js";
|
|
4
3
|
export * from "./patch-exception-bubbling.js";
|
|
5
4
|
export * from "./patch-find-dir.js";
|
|
6
5
|
export * from "./patch-load-instrumentation-module.js";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type BuildOptions } from "@opennextjs/aws/build/helper.js";
|
|
2
2
|
/**
|
|
3
3
|
* `evalManifest` relies on readFileSync so we need to patch the function so that it instead returns the content of the manifest files
|
|
4
4
|
* which are known at build time
|
|
@@ -6,4 +6,4 @@ import { Config } from "../../../config.js";
|
|
|
6
6
|
* Note: we could/should probably just patch readFileSync here or something, but here the issue is that after the readFileSync call
|
|
7
7
|
* there is a vm `runInNewContext` call which we also don't support (source: https://github.com/vercel/next.js/blob/b1e32c5d1f/packages/next/src/server/load-manifest.ts#L88)
|
|
8
8
|
*/
|
|
9
|
-
export declare function inlineEvalManifest(code: string,
|
|
9
|
+
export declare function inlineEvalManifest(code: string, buildOpts: BuildOptions): string;
|