Skip to content

Commit e8f5e66

Browse files
authored
perf(OriginResolver): cache expensive compute (#1009)
1 parent 8dd43ee commit e8f5e66

File tree

2 files changed

+69
-27
lines changed

2 files changed

+69
-27
lines changed

.changeset/chilly-pens-tease.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+
perf(OriginResolver): cache expensive compute

packages/open-next/src/overrides/originResolver/pattern-env.ts

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -3,41 +3,78 @@ import type { OriginResolver } from "types/overrides";
33

44
import { debug, error } from "../../adapters/logger";
55

6+
// Cache parsed origins and compiled patterns at module level
7+
let cachedOrigins: Record<string, Origin>;
8+
const cachedPatterns: Array<{
9+
key: string;
10+
patterns: string[];
11+
regexes: RegExp[];
12+
}> = [];
13+
let initialized = false;
14+
15+
/**
16+
* Initializes the cached values on the first execution
17+
*/
18+
function initializeOnce(): void {
19+
if (initialized) return;
20+
21+
// Parse origin JSON once
22+
cachedOrigins = JSON.parse(process.env.OPEN_NEXT_ORIGIN ?? "{}") as Record<
23+
string,
24+
Origin
25+
>;
26+
27+
// Pre-compile all regex patterns
28+
const functions = globalThis.openNextConfig.functions ?? {};
29+
for (const key in functions) {
30+
if (key !== "default") {
31+
const value = functions[key];
32+
const regexes: RegExp[] = [];
33+
34+
for (const pattern of value.patterns) {
35+
// Convert cloudfront pattern to regex
36+
const regexPattern = `/${pattern
37+
.replace(/\*\*/g, "(.*)")
38+
.replace(/\*/g, "([^/]*)")
39+
.replace(/\//g, "\\/")
40+
.replace(/\?/g, ".")}`;
41+
regexes.push(new RegExp(regexPattern));
42+
}
43+
44+
cachedPatterns.push({
45+
key,
46+
patterns: value.patterns,
47+
regexes,
48+
});
49+
}
50+
}
51+
52+
initialized = true;
53+
}
54+
655
const envLoader: OriginResolver = {
756
name: "env",
857
resolve: async (_path: string) => {
958
try {
10-
const origin = JSON.parse(process.env.OPEN_NEXT_ORIGIN ?? "{}") as Record<
11-
string,
12-
Origin
13-
>;
14-
for (const [key, value] of Object.entries(
15-
globalThis.openNextConfig.functions ?? {},
16-
).filter(([key]) => key !== "default")) {
17-
if (
18-
value.patterns.some((pattern) => {
19-
// Convert cloudfront pattern to regex
20-
return new RegExp(
21-
// transform glob pattern to regex
22-
`/${pattern
23-
.replace(/\*\*/g, "(.*)")
24-
.replace(/\*/g, "([^/]*)")
25-
.replace(/\//g, "\\/")
26-
.replace(/\?/g, ".")}`,
27-
).test(_path);
28-
})
29-
) {
30-
debug("Using origin", key, value.patterns);
31-
return origin[key];
59+
initializeOnce();
60+
61+
// Test against pre-compiled patterns
62+
for (const { key, patterns, regexes } of cachedPatterns) {
63+
for (const regex of regexes) {
64+
if (regex.test(_path)) {
65+
debug("Using origin", key, patterns);
66+
return cachedOrigins[key];
67+
}
3268
}
3369
}
34-
if (_path.startsWith("/_next/image") && origin.imageOptimizer) {
70+
71+
if (_path.startsWith("/_next/image") && cachedOrigins.imageOptimizer) {
3572
debug("Using origin", "imageOptimizer", _path);
36-
return origin.imageOptimizer;
73+
return cachedOrigins.imageOptimizer;
3774
}
38-
if (origin.default) {
39-
debug("Using default origin", origin.default, _path);
40-
return origin.default;
75+
if (cachedOrigins.default) {
76+
debug("Using default origin", cachedOrigins.default, _path);
77+
return cachedOrigins.default;
4178
}
4279
return false as const;
4380
} catch (e) {

0 commit comments

Comments
 (0)