Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/forty-paws-nail.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@opennextjs/aws": patch
---

refactor the CodePatcher
95 changes: 38 additions & 57 deletions packages/open-next/src/build/patch/codePatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,18 @@ import logger from "../../logger.js";
import type { getManifests } from "../copyTracedFiles.js";
import * as buildHelper from "../helper.js";

type Versions =
/**
* Accepted formats:
* - `">=16.0.0"`
* - `"<=16.0.0"`
* - `">=16.0.0 <=17.0.0"`
*
* **Be careful with spaces**
*/
export type Versions =
| `>=${number}.${number}.${number} <=${number}.${number}.${number}`
| `>=${number}.${number}.${number}`
| `<=${number}.${number}.${number}`;
export interface VersionedField<T> {
/**
* The versions of Next.js that this field should be used for
* Should be in the format `">=16.0.0 <=17.0.0"` or `">=16.0.0"` or `"<=17.0.0"`
* **Be careful with spaces**
*/
versions?: Versions;
field: T;
}

export type PatchCodeFn = (args: {
/**
Expand All @@ -40,11 +39,13 @@ interface IndividualPatch {
pathFilter: RegExp;
contentFilter?: RegExp;
patchCode: PatchCodeFn;
// Only apply the patch to specific versions of Next.js
versions?: Versions;
}

export interface CodePatcher {
name: string;
patches: IndividualPatch | VersionedField<IndividualPatch>[];
patches: IndividualPatch[];
}

export function parseVersions(versions?: Versions): {
Expand Down Expand Up @@ -92,48 +93,30 @@ export function parseVersions(versions?: Versions): {
};
}

export function extractVersionedField<T>(
fields: VersionedField<T>[],
/**
* Check whether the version is in the range
*
* @param version A semver version
* @param versionRange A version range
* @returns whether the version satisfies the range
*/
export function isVersionInRange(
version: string,
): T[] {
const result: T[] = [];
versionRange?: Versions,
): boolean {
const { before, after } = parseVersions(versionRange);

for (const field of fields) {
// No versions specified, the patch always apply
if (!field.versions) {
result.push(field.field);
continue;
}

const { before, after } = parseVersions(field.versions);
let inRange = true;

// range
if (before && after) {
if (
buildHelper.compareSemver(version, "<=", before) &&
buildHelper.compareSemver(version, ">=", after)
) {
result.push(field.field);
}
continue;
}

// before only
if (before) {
if (buildHelper.compareSemver(version, "<=", before)) {
result.push(field.field);
}
continue;
}
if (before) {
inRange &&= buildHelper.compareSemver(version, "<=", before);
}

// after only
if (after) {
if (buildHelper.compareSemver(version, ">=", after)) {
result.push(field.field);
}
}
if (after) {
inRange &&= buildHelper.compareSemver(version, ">=", after);
}
return result;

return inRange;
}

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

// We first filter against the version
// We also flatten the array of patches so that we get both the name and all the necessary patches
const patchesToApply = codePatcher.flatMap(({ name, patches }) =>
Array.isArray(patches)
? extractVersionedField(patches, nextVersion).map((patch) => ({
name,
patch,
}))
: [{ name, patch: patches }],
);
const patchesToApply = codePatcher.flatMap(({ name, patches }) => {
return patches
.filter(({ versions }) =>
isVersionInRange(buildOptions.nextVersion, versions),
)
.map((patch) => ({ patch, name }));
});

await Promise.all(
tracedFiles.map(async (filePath) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,8 @@ export const patchBackgroundRevalidation = {
{
// TODO: test for earlier versions of Next
versions: ">=14.1.0",
field: {
pathFilter: getCrossPlatformPathRegex("server/response-cache/index.js"),
patchCode: createPatchCode(rule),
},
pathFilter: getCrossPlatformPathRegex("server/response-cache/index.js"),
patchCode: createPatchCode(rule),
},
],
} satisfies CodePatcher;
28 changes: 10 additions & 18 deletions packages/open-next/src/build/patch/patches/patchEnvVar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,32 +27,24 @@ export const patchEnvVars: CodePatcher = {
// This patch will set the `NEXT_RUNTIME` env var to "node" to avoid loading unnecessary edge deps at runtime
{
versions: ">=15.0.0",
field: {
pathFilter: /module\.compiled\.js$/,
contentFilter: /process\.env\.NEXT_RUNTIME/,
patchCode: createPatchCode(envVarRuleCreator("NEXT_RUNTIME", '"node"')),
},
pathFilter: /module\.compiled\.js$/,
contentFilter: /process\.env\.NEXT_RUNTIME/,
patchCode: createPatchCode(envVarRuleCreator("NEXT_RUNTIME", '"node"')),
},
// This patch will set `NODE_ENV` to production to avoid loading unnecessary dev deps at runtime
{
versions: ">=15.0.0",
field: {
pathFilter:
/(module\.compiled|react\/index|react\/jsx-runtime|react-dom\/index)\.js$/,
contentFilter: /process\.env\.NODE_ENV/,
patchCode: createPatchCode(
envVarRuleCreator("NODE_ENV", '"production"'),
),
},
pathFilter:
/(module\.compiled|react\/index|react\/jsx-runtime|react-dom\/index)\.js$/,
contentFilter: /process\.env\.NODE_ENV/,
patchCode: createPatchCode(envVarRuleCreator("NODE_ENV", '"production"')),
},
// This patch will set `TURBOPACK` env to false to avoid loading turbopack related deps at runtime
{
versions: ">=15.0.0",
field: {
pathFilter: /module\.compiled\.js$/,
contentFilter: /process\.env\.TURBOPACK/,
patchCode: createPatchCode(envVarRuleCreator("TURBOPACK", "false")),
},
pathFilter: /module\.compiled\.js$/,
contentFilter: /process\.env\.TURBOPACK/,
patchCode: createPatchCode(envVarRuleCreator("TURBOPACK", "false")),
},
],
};
50 changes: 22 additions & 28 deletions packages/open-next/src/build/patch/patches/patchFetchCacheISR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ rule:
kind: ternary_expression
all:
- has: {kind: 'null'}
- has:
- has:
kind: await_expression
has:
kind: call_expression
Expand Down Expand Up @@ -51,7 +51,7 @@ rule:
kind: statement_block
has:
kind: variable_declarator
has:
has:
kind: await_expression
has:
kind: call_expression
Expand Down Expand Up @@ -84,13 +84,13 @@ rule:
pattern: $STORE_OR_CACHE.isOnDemandRevalidate
inside:
kind: binary_expression
has:
has:
kind: member_expression
pattern: $STORE_OR_CACHE.isDraftMode
inside:
kind: if_statement
stopBy: end
has:
has:
kind: return_statement
any:
- has:
Expand All @@ -106,14 +106,12 @@ export const patchFetchCacheForISR: CodePatcher = {
patches: [
{
versions: ">=14.0.0",
field: {
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
{ escape: false },
),
contentFilter: /\.isOnDemandRevalidate/,
patchCode: createPatchCode(fetchRule, Lang.JavaScript),
},
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
{ escape: false },
),
contentFilter: /\.isOnDemandRevalidate/,
patchCode: createPatchCode(fetchRule, Lang.JavaScript),
},
],
};
Expand All @@ -123,14 +121,12 @@ export const patchUnstableCacheForISR: CodePatcher = {
patches: [
{
versions: ">=14.2.0",
field: {
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|spec-extension/unstable-cache\.js)$`,
{ escape: false },
),
contentFilter: /\.isOnDemandRevalidate/,
patchCode: createPatchCode(unstable_cacheRule, Lang.JavaScript),
},
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|spec-extension/unstable-cache\.js)$`,
{ escape: false },
),
contentFilter: /\.isOnDemandRevalidate/,
patchCode: createPatchCode(unstable_cacheRule, Lang.JavaScript),
},
],
};
Expand All @@ -140,14 +136,12 @@ export const patchUseCacheForISR: CodePatcher = {
patches: [
{
versions: ">=15.3.0",
field: {
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`,
{ escape: false },
),
contentFilter: /\.isOnDemandRevalidate/,
patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
},
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|\.runtime\..*\.js|use-cache/use-cache-wrapper\.js)$`,
{ escape: false },
),
contentFilter: /\.isOnDemandRevalidate/,
patchCode: createPatchCode(useCacheRule, Lang.JavaScript),
},
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,12 @@ export const patchFetchCacheSetMissingWaitUntil: CodePatcher = {
patches: [
{
versions: ">=15.0.0",
field: {
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
{ escape: false },
),
contentFilter: /arrayBuffer\(\)\s*\.then/,
patchCode: createPatchCode(rule),
},
pathFilter: getCrossPlatformPathRegex(
String.raw`(server/chunks/.*\.js|.*\.runtime\..*\.js|patch-fetch\.js)$`,
{ escape: false },
),
contentFilter: /arrayBuffer\(\)\s*\.then/,
patchCode: createPatchCode(rule),
},
],
};
48 changes: 18 additions & 30 deletions packages/open-next/src/build/patch/patches/patchNextServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,27 +81,21 @@ const pathFilter = getCrossPlatformPathRegex(
const babelPatches = [
// Empty the body of `NextServer#runMiddleware`
{
field: {
pathFilter,
contentFilter: /runMiddleware\(/,
patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
},
pathFilter,
contentFilter: /runMiddleware\(/,
patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
},
// Empty the body of `NextServer#runEdgeFunction`
{
field: {
pathFilter,
contentFilter: /runEdgeFunction\(/,
patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
},
pathFilter,
contentFilter: /runEdgeFunction\(/,
patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
},
// Drop `error-inspect` that pulls babel
{
field: {
pathFilter,
contentFilter: /error-inspect/,
patchCode: createPatchCode(errorInspectRule),
},
pathFilter,
contentFilter: /error-inspect/,
patchCode: createPatchCode(errorInspectRule),
},
];

Expand All @@ -110,30 +104,24 @@ export const patchNextServer: CodePatcher = {
patches: [
// Empty the body of `NextServer#imageOptimizer` - unused in OpenNext
{
field: {
pathFilter,
contentFilter: /imageOptimizer\(/,
patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
},
pathFilter,
contentFilter: /imageOptimizer\(/,
patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
},
// Disable Next background preloading done at creation of `NextServer`
{
versions: ">=14.0.0",
field: {
pathFilter,
contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
patchCode: createPatchCode(disablePreloadingRule),
},
pathFilter,
contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
patchCode: createPatchCode(disablePreloadingRule),
},
// Don't match edge functions in `NextServer`
{
// Next 12 and some version of 13 use the bundled middleware/edge function
versions: ">=14.0.0",
field: {
pathFilter,
contentFilter: /getMiddlewareManifest/,
patchCode: createPatchCode(removeMiddlewareManifestRule),
},
pathFilter,
contentFilter: /getMiddlewareManifest/,
patchCode: createPatchCode(removeMiddlewareManifestRule),
},
...babelPatches,
],
Expand Down
Loading