Skip to content

Commit c48ac95

Browse files
authored
refactor the code patcher (opennextjs#931)
1 parent 37e8553 commit c48ac95

File tree

9 files changed

+168
-226
lines changed

9 files changed

+168
-226
lines changed

.changeset/forty-paws-nail.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@opennextjs/aws": patch
3+
---
4+
5+
refactor the CodePatcher

packages/open-next/src/build/patch/codePatcher.ts

Lines changed: 38 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,18 @@ import logger from "../../logger.js";
33
import type { getManifests } from "../copyTracedFiles.js";
44
import * as buildHelper from "../helper.js";
55

6-
type Versions =
6+
/**
7+
* Accepted formats:
8+
* - `">=16.0.0"`
9+
* - `"<=16.0.0"`
10+
* - `">=16.0.0 <=17.0.0"`
11+
*
12+
* **Be careful with spaces**
13+
*/
14+
export type Versions =
715
| `>=${number}.${number}.${number} <=${number}.${number}.${number}`
816
| `>=${number}.${number}.${number}`
917
| `<=${number}.${number}.${number}`;
10-
export interface VersionedField<T> {
11-
/**
12-
* The versions of Next.js that this field should be used for
13-
* Should be in the format `">=16.0.0 <=17.0.0"` or `">=16.0.0"` or `"<=17.0.0"`
14-
* **Be careful with spaces**
15-
*/
16-
versions?: Versions;
17-
field: T;
18-
}
1918

2019
export type PatchCodeFn = (args: {
2120
/**
@@ -40,11 +39,13 @@ interface IndividualPatch {
4039
pathFilter: RegExp;
4140
contentFilter?: RegExp;
4241
patchCode: PatchCodeFn;
42+
// Only apply the patch to specific versions of Next.js
43+
versions?: Versions;
4344
}
4445

4546
export interface CodePatcher {
4647
name: string;
47-
patches: IndividualPatch | VersionedField<IndividualPatch>[];
48+
patches: IndividualPatch[];
4849
}
4950

5051
export function parseVersions(versions?: Versions): {
@@ -92,48 +93,30 @@ export function parseVersions(versions?: Versions): {
9293
};
9394
}
9495

95-
export function extractVersionedField<T>(
96-
fields: VersionedField<T>[],
96+
/**
97+
* Check whether the version is in the range
98+
*
99+
* @param version A semver version
100+
* @param versionRange A version range
101+
* @returns whether the version satisfies the range
102+
*/
103+
export function isVersionInRange(
97104
version: string,
98-
): T[] {
99-
const result: T[] = [];
105+
versionRange?: Versions,
106+
): boolean {
107+
const { before, after } = parseVersions(versionRange);
100108

101-
for (const field of fields) {
102-
// No versions specified, the patch always apply
103-
if (!field.versions) {
104-
result.push(field.field);
105-
continue;
106-
}
107-
108-
const { before, after } = parseVersions(field.versions);
109+
let inRange = true;
109110

110-
// range
111-
if (before && after) {
112-
if (
113-
buildHelper.compareSemver(version, "<=", before) &&
114-
buildHelper.compareSemver(version, ">=", after)
115-
) {
116-
result.push(field.field);
117-
}
118-
continue;
119-
}
120-
121-
// before only
122-
if (before) {
123-
if (buildHelper.compareSemver(version, "<=", before)) {
124-
result.push(field.field);
125-
}
126-
continue;
127-
}
111+
if (before) {
112+
inRange &&= buildHelper.compareSemver(version, "<=", before);
113+
}
128114

129-
// after only
130-
if (after) {
131-
if (buildHelper.compareSemver(version, ">=", after)) {
132-
result.push(field.field);
133-
}
134-
}
115+
if (after) {
116+
inRange &&= buildHelper.compareSemver(version, ">=", after);
135117
}
136-
return result;
118+
119+
return inRange;
137120
}
138121

139122
export async function applyCodePatches(
@@ -142,19 +125,17 @@ export async function applyCodePatches(
142125
manifests: ReturnType<typeof getManifests>,
143126
codePatcher: CodePatcher[],
144127
) {
145-
const nextVersion = buildOptions.nextVersion;
146128
logger.time("Applying code patches");
147129

148130
// We first filter against the version
149131
// We also flatten the array of patches so that we get both the name and all the necessary patches
150-
const patchesToApply = codePatcher.flatMap(({ name, patches }) =>
151-
Array.isArray(patches)
152-
? extractVersionedField(patches, nextVersion).map((patch) => ({
153-
name,
154-
patch,
155-
}))
156-
: [{ name, patch: patches }],
157-
);
132+
const patchesToApply = codePatcher.flatMap(({ name, patches }) => {
133+
return patches
134+
.filter(({ versions }) =>
135+
isVersionInRange(buildOptions.nextVersion, versions),
136+
)
137+
.map((patch) => ({ patch, name }));
138+
});
158139

159140
await Promise.all(
160141
tracedFiles.map(async (filePath) => {

packages/open-next/src/build/patch/patches/patchBackgroundRevalidation.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,8 @@ export const patchBackgroundRevalidation = {
2121
{
2222
// TODO: test for earlier versions of Next
2323
versions: ">=14.1.0",
24-
field: {
25-
pathFilter: getCrossPlatformPathRegex("server/response-cache/index.js"),
26-
patchCode: createPatchCode(rule),
27-
},
24+
pathFilter: getCrossPlatformPathRegex("server/response-cache/index.js"),
25+
patchCode: createPatchCode(rule),
2826
},
2927
],
3028
} satisfies CodePatcher;

packages/open-next/src/build/patch/patches/patchEnvVar.ts

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,24 @@ export const patchEnvVars: CodePatcher = {
2727
// This patch will set the `NEXT_RUNTIME` env var to "node" to avoid loading unnecessary edge deps at runtime
2828
{
2929
versions: ">=15.0.0",
30-
field: {
31-
pathFilter: /module\.compiled\.js$/,
32-
contentFilter: /process\.env\.NEXT_RUNTIME/,
33-
patchCode: createPatchCode(envVarRuleCreator("NEXT_RUNTIME", '"node"')),
34-
},
30+
pathFilter: /module\.compiled\.js$/,
31+
contentFilter: /process\.env\.NEXT_RUNTIME/,
32+
patchCode: createPatchCode(envVarRuleCreator("NEXT_RUNTIME", '"node"')),
3533
},
3634
// This patch will set `NODE_ENV` to production to avoid loading unnecessary dev deps at runtime
3735
{
3836
versions: ">=15.0.0",
39-
field: {
40-
pathFilter:
41-
/(module\.compiled|react\/index|react\/jsx-runtime|react-dom\/index)\.js$/,
42-
contentFilter: /process\.env\.NODE_ENV/,
43-
patchCode: createPatchCode(
44-
envVarRuleCreator("NODE_ENV", '"production"'),
45-
),
46-
},
37+
pathFilter:
38+
/(module\.compiled|react\/index|react\/jsx-runtime|react-dom\/index)\.js$/,
39+
contentFilter: /process\.env\.NODE_ENV/,
40+
patchCode: createPatchCode(envVarRuleCreator("NODE_ENV", '"production"')),
4741
},
4842
// This patch will set `TURBOPACK` env to false to avoid loading turbopack related deps at runtime
4943
{
5044
versions: ">=15.0.0",
51-
field: {
52-
pathFilter: /module\.compiled\.js$/,
53-
contentFilter: /process\.env\.TURBOPACK/,
54-
patchCode: createPatchCode(envVarRuleCreator("TURBOPACK", "false")),
55-
},
45+
pathFilter: /module\.compiled\.js$/,
46+
contentFilter: /process\.env\.TURBOPACK/,
47+
patchCode: createPatchCode(envVarRuleCreator("TURBOPACK", "false")),
5648
},
5749
],
5850
};

packages/open-next/src/build/patch/patches/patchFetchCacheISR.ts

Lines changed: 22 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ rule:
1111
kind: ternary_expression
1212
all:
1313
- has: {kind: 'null'}
14-
- has:
14+
- has:
1515
kind: await_expression
1616
has:
1717
kind: call_expression
@@ -51,7 +51,7 @@ rule:
5151
kind: statement_block
5252
has:
5353
kind: variable_declarator
54-
has:
54+
has:
5555
kind: await_expression
5656
has:
5757
kind: call_expression
@@ -84,13 +84,13 @@ rule:
8484
pattern: $STORE_OR_CACHE.isOnDemandRevalidate
8585
inside:
8686
kind: binary_expression
87-
has:
87+
has:
8888
kind: member_expression
8989
pattern: $STORE_OR_CACHE.isDraftMode
9090
inside:
9191
kind: if_statement
9292
stopBy: end
93-
has:
93+
has:
9494
kind: return_statement
9595
any:
9696
- has:
@@ -106,14 +106,12 @@ export const patchFetchCacheForISR: CodePatcher = {
106106
patches: [
107107
{
108108
versions: ">=14.0.0",
109-
field: {
110-
pathFilter: getCrossPlatformPathRegex(
111-
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
112-
{ escape: false },
113-
),
114-
contentFilter: /\.isOnDemandRevalidate/,
115-
patchCode: createPatchCode(fetchRule, Lang.JavaScript),
116-
},
109+
pathFilter: getCrossPlatformPathRegex(
110+
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
111+
{ escape: false },
112+
),
113+
contentFilter: /\.isOnDemandRevalidate/,
114+
patchCode: createPatchCode(fetchRule, Lang.JavaScript),
117115
},
118116
],
119117
};
@@ -123,14 +121,12 @@ export const patchUnstableCacheForISR: CodePatcher = {
123121
patches: [
124122
{
125123
versions: ">=14.2.0",
126-
field: {
127-
pathFilter: getCrossPlatformPathRegex(
128-
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|spec-extension/unstable-cache\.js)$`,
129-
{ escape: false },
130-
),
131-
contentFilter: /\.isOnDemandRevalidate/,
132-
patchCode: createPatchCode(unstable_cacheRule, Lang.JavaScript),
133-
},
124+
pathFilter: getCrossPlatformPathRegex(
125+
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|spec-extension/unstable-cache\.js)$`,
126+
{ escape: false },
127+
),
128+
contentFilter: /\.isOnDemandRevalidate/,
129+
patchCode: createPatchCode(unstable_cacheRule, Lang.JavaScript),
134130
},
135131
],
136132
};
@@ -140,14 +136,12 @@ export const patchUseCacheForISR: CodePatcher = {
140136
patches: [
141137
{
142138
versions: ">=15.3.0",
143-
field: {
144-
pathFilter: getCrossPlatformPathRegex(
145-
String.raw`(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`,
146-
{ escape: false },
147-
),
148-
contentFilter: /\.isOnDemandRevalidate/,
149-
patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
150-
},
139+
pathFilter: getCrossPlatformPathRegex(
140+
String.raw`(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`,
141+
{ escape: false },
142+
),
143+
contentFilter: /\.isOnDemandRevalidate/,
144+
patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
151145
},
152146
],
153147
};

packages/open-next/src/build/patch/patches/patchFetchCacheWaitUntil.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,12 @@ export const patchFetchCacheSetMissingWaitUntil: CodePatcher = {
2929
patches: [
3030
{
3131
versions: ">=15.0.0",
32-
field: {
33-
pathFilter: getCrossPlatformPathRegex(
34-
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
35-
{ escape: false },
36-
),
37-
contentFilter: /arrayBuffer\(\)\s*\.then/,
38-
patchCode: createPatchCode(rule),
39-
},
32+
pathFilter: getCrossPlatformPathRegex(
33+
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
34+
{ escape: false },
35+
),
36+
contentFilter: /arrayBuffer\(\)\s*\.then/,
37+
patchCode: createPatchCode(rule),
4038
},
4139
],
4240
};

packages/open-next/src/build/patch/patches/patchNextServer.ts

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -81,27 +81,21 @@ const pathFilter = getCrossPlatformPathRegex(
8181
const babelPatches = [
8282
// Empty the body of `NextServer#runMiddleware`
8383
{
84-
field: {
85-
pathFilter,
86-
contentFilter: /runMiddleware\(/,
87-
patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
88-
},
84+
pathFilter,
85+
contentFilter: /runMiddleware\(/,
86+
patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
8987
},
9088
// Empty the body of `NextServer#runEdgeFunction`
9189
{
92-
field: {
93-
pathFilter,
94-
contentFilter: /runEdgeFunction\(/,
95-
patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
96-
},
90+
pathFilter,
91+
contentFilter: /runEdgeFunction\(/,
92+
patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
9793
},
9894
// Drop `error-inspect` that pulls babel
9995
{
100-
field: {
101-
pathFilter,
102-
contentFilter: /error-inspect/,
103-
patchCode: createPatchCode(errorInspectRule),
104-
},
96+
pathFilter,
97+
contentFilter: /error-inspect/,
98+
patchCode: createPatchCode(errorInspectRule),
10599
},
106100
];
107101

@@ -110,30 +104,24 @@ export const patchNextServer: CodePatcher = {
110104
patches: [
111105
// Empty the body of `NextServer#imageOptimizer` - unused in OpenNext
112106
{
113-
field: {
114-
pathFilter,
115-
contentFilter: /imageOptimizer\(/,
116-
patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
117-
},
107+
pathFilter,
108+
contentFilter: /imageOptimizer\(/,
109+
patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
118110
},
119111
// Disable Next background preloading done at creation of `NextServer`
120112
{
121113
versions: ">=14.0.0",
122-
field: {
123-
pathFilter,
124-
contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
125-
patchCode: createPatchCode(disablePreloadingRule),
126-
},
114+
pathFilter,
115+
contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
116+
patchCode: createPatchCode(disablePreloadingRule),
127117
},
128118
// Don't match edge functions in `NextServer`
129119
{
130120
// Next 12 and some version of 13 use the bundled middleware/edge function
131121
versions: ">=14.0.0",
132-
field: {
133-
pathFilter,
134-
contentFilter: /getMiddlewareManifest/,
135-
patchCode: createPatchCode(removeMiddlewareManifestRule),
136-
},
122+
pathFilter,
123+
contentFilter: /getMiddlewareManifest/,
124+
patchCode: createPatchCode(removeMiddlewareManifestRule),
137125
},
138126
...babelPatches,
139127
],

0 commit comments

Comments
 (0)