Skip to content

Commit 214b095

Browse files
committed
refactor: code simplification
1 parent 04379e2 commit 214b095

File tree

14 files changed

+211
-196
lines changed

14 files changed

+211
-196
lines changed

packages/open-next/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"@types/aws-lambda": "^8.10.109",
4848
"@types/node": "^18.16.1",
4949
"tsc-alias": "^1.8.8",
50-
"typescript": "^4.9.3"
50+
"typescript": "^5.6.3"
5151
},
5252
"bugs": {
5353
"url": "https://github.com/opennextjs/opennextjs-aws/issues"

packages/open-next/src/adapters/server-adapter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ export const handler = await createMainHandler();
2828
//////////////////////
2929

3030
function setNextjsServerWorkingDirectory() {
31-
// WORKAROUND: Set `NextServer` working directory (AWS specific) — https://github.com/serverless-stack/open-next#workaround-set-nextserver-working-directory-aws-specific
31+
// WORKAROUND: Set `NextServer` working directory (AWS specific)
32+
// See https://opennext.js.org/aws/v2/advanced/workaround#workaround-set-nextserver-working-directory-aws-specific
3233
process.chdir(__dirname);
3334
}
3435

packages/open-next/src/build/createAssets.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,17 @@ export function createStaticAssets(options: buildHelper.BuildOptions) {
1414
const outputPath = path.join(outputDir, "assets");
1515
fs.mkdirSync(outputPath, { recursive: true });
1616

17-
// Next.js outputs assets into multiple files. Copy into the same directory.
18-
// Copy over:
19-
// - .next/BUILD_ID => _next/BUILD_ID
20-
// - .next/static => _next/static
21-
// - public/* => *
22-
// - app/favicon.ico or src/app/favicon.ico => favicon.ico
17+
/**
18+
* Next.js outputs assets into multiple files. Copy into the same directory.
19+
*
20+
* Copy over:
21+
* - .next/BUILD_ID => BUILD_ID
22+
* - .next/static => _next/static
23+
* - public/* => *
24+
* - app/favicon.ico or src/app/favicon.ico => favicon.ico
25+
*
26+
* Note: BUILD_ID is used by the SST infra.
27+
*/
2328
fs.copyFileSync(
2429
path.join(appBuildOutputPath, ".next/BUILD_ID"),
2530
path.join(outputPath, "BUILD_ID"),

packages/open-next/src/build/createServerBundle.ts

Lines changed: 28 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -197,52 +197,44 @@ async function generateBundle(
197197
...(disableNextPrebundledReact ? ["requireHooks"] : []),
198198
...(disableRouting ? ["trustHostHeader"] : []),
199199
...(!isBefore13413 ? ["requestHandlerHost"] : []),
200-
...(!isAfter141 ? ["stableIncrementalCache"] : []),
201-
...(isAfter141 ? ["experimentalIncrementalCacheHandler"] : []),
200+
...(isAfter141
201+
? ["experimentalIncrementalCacheHandler"]
202+
: ["stableIncrementalCache"]),
202203
],
203204
}),
204205

205206
openNextResolvePlugin({
206207
fnName: name,
207-
overrides: overrides,
208+
overrides,
208209
}),
209210
];
210211

211-
if (plugins && plugins.length > 0) {
212-
logger.debug(
213-
`Applying plugins:: [${plugins
214-
.map(({ name }) => name)
215-
.join(",")}] for Next version: ${options.nextVersion}`,
216-
);
217-
}
218-
219212
const outfileExt = fnOptions.runtime === "deno" ? "ts" : "mjs";
220-
await buildHelper.esbuildAsync(
221-
{
222-
entryPoints: [
223-
path.join(options.openNextDistDir, "adapters", "server-adapter.js"),
224-
],
225-
external: ["next", "./middleware.mjs", "./next-server.runtime.prod.js"],
226-
outfile: path.join(outputPath, packagePath, `index.${outfileExt}`),
227-
banner: {
228-
js: [
229-
`globalThis.monorepoPackagePath = "${packagePath}";`,
230-
"import process from 'node:process';",
231-
"import { Buffer } from 'node:buffer';",
232-
"import { createRequire as topLevelCreateRequire } from 'module';",
233-
"const require = topLevelCreateRequire(import.meta.url);",
234-
"import bannerUrl from 'url';",
235-
"const __dirname = bannerUrl.fileURLToPath(new URL('.', import.meta.url));",
236-
name === "default" ? "" : `globalThis.fnName = "${name}";`,
237-
].join(""),
238-
},
239-
plugins,
240-
alias: {
241-
"next/dist/server/next-server.js": isBundled
242-
? "./next-server.runtime.prod.js"
243-
: "next/dist/server/next-server.js",
244-
},
213+
await buildHelper.esbuildAsync({
214+
entryPoints: [
215+
path.join(options.openNextDistDir, "adapters", "server-adapter.js"),
216+
],
217+
external: ["next", "./middleware.mjs", "./next-server.runtime.prod.js"],
218+
outfile: path.join(outputPath, packagePath, `index.${outfileExt}`),
219+
banner: {
220+
js: [
221+
`globalThis.monorepoPackagePath = "${packagePath}";`,
222+
"import process from 'node:process';",
223+
"import { Buffer } from 'node:buffer';",
224+
"import { createRequire as topLevelCreateRequire } from 'module';",
225+
"const require = topLevelCreateRequire(import.meta.url);",
226+
"import bannerUrl from 'url';",
227+
"const __dirname = bannerUrl.fileURLToPath(new URL('.', import.meta.url));",
228+
name === "default" ? "" : `globalThis.fnName = "${name}";`,
229+
].join(""),
245230
},
231+
plugins,
232+
alias: {
233+
...(isBundled
234+
? { "next/dist/server/next-server.js": "./next-server.runtime.prod.js" }
235+
: undefined),
236+
}
237+
},
246238
options,
247239
);
248240

packages/open-next/src/build/edge/createEdgeBundle.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ export async function buildEdgeBundle({
5252
await esbuildAsync(
5353
{
5454
entryPoints: [entrypoint],
55-
// inject: ,
5655
bundle: true,
5756
outfile,
5857
external: ["node:*", "next", "@aws-sdk/*"],

packages/open-next/src/core/requestHandler.ts

Lines changed: 93 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import { debug, error, warn } from "../adapters/logger";
99
import { patchAsyncStorage } from "./patchAsyncStorage";
1010
import { convertRes, createServerResponse, proxyRequest } from "./routing/util";
1111
import type { MiddlewareOutputEvent } from "./routingHandler";
12-
import routingHandler from "./routingHandler";
12+
import routingHandler, {
13+
MIDDLEWARE_HEADER_PREFIX,
14+
MIDDLEWARE_HEADER_PREFIX_LEN,
15+
} from "./routingHandler";
1316
import { requestHandler, setNextjsPrebundledReact } from "./util";
1417

1518
// This is used to identify requests in the cache
@@ -51,107 +54,103 @@ export async function openNextHandler(
5154
? preprocessResult.headers
5255
: preprocessResult.internalEvent.headers;
5356

54-
const overwrittenResponseHeaders = Object.entries(
55-
"type" in preprocessResult
56-
? preprocessResult.headers
57-
: preprocessResult.internalEvent.headers,
58-
).reduce((acc, [key, value]) => {
59-
if (!key.startsWith("x-middleware-response-")) {
60-
return acc;
61-
} else {
62-
const newKey = key.replace("x-middleware-response-", "");
63-
delete headers[key];
64-
headers[newKey] = value;
65-
return { ...acc, [newKey]: value };
57+
const overwrittenResponseHeaders: Record<string, string | string[]> = {};
58+
59+
for (const [rawKey, value] of Object.entries(headers)) {
60+
if (!rawKey.startsWith(MIDDLEWARE_HEADER_PREFIX)) {
61+
continue;
6662
}
67-
}, {});
63+
const key = rawKey.slice(MIDDLEWARE_HEADER_PREFIX_LEN);
64+
overwrittenResponseHeaders[key] = value;
65+
headers[key] = value;
66+
delete headers[rawKey];
67+
}
6868

6969
if ("type" in preprocessResult) {
70-
// // res is used only in the streaming case
70+
// response is used only in the streaming case
7171
if (responseStreaming) {
72-
const res = createServerResponse(
72+
const response = createServerResponse(
7373
internalEvent,
7474
headers,
7575
responseStreaming,
7676
);
77-
res.statusCode = preprocessResult.statusCode;
78-
res.flushHeaders();
77+
response.statusCode = preprocessResult.statusCode;
78+
response.flushHeaders();
7979
const [bodyToConsume, bodyToReturn] = preprocessResult.body.tee();
8080
for await (const chunk of bodyToConsume) {
81-
res.write(chunk);
81+
response.write(chunk);
8282
}
83-
res.end();
83+
response.end();
8484
preprocessResult.body = bodyToReturn;
8585
}
8686
return preprocessResult;
87-
} else {
88-
const preprocessedEvent = preprocessResult.internalEvent;
89-
debug("preprocessedEvent", preprocessedEvent);
90-
const reqProps = {
91-
method: preprocessedEvent.method,
92-
url: preprocessedEvent.url,
93-
//WORKAROUND: We pass this header to the serverless function to mimic a prefetch request which will not trigger revalidation since we handle revalidation differently
94-
// There is 3 way we can handle revalidation:
95-
// 1. We could just let the revalidation go as normal, but due to race condtions the revalidation will be unreliable
96-
// 2. We could alter the lastModified time of our cache to make next believe that the cache is fresh, but this could cause issues with stale data since the cdn will cache the stale data as if it was fresh
97-
// 3. OUR CHOICE: We could pass a purpose prefetch header to the serverless function to make next believe that the request is a prefetch request and not trigger revalidation (This could potentially break in the future if next changes the behavior of prefetch requests)
98-
headers: { ...headers, purpose: "prefetch" },
99-
body: preprocessedEvent.body,
100-
remoteAddress: preprocessedEvent.remoteAddress,
101-
};
102-
const requestId = Math.random().toString(36);
103-
const pendingPromiseRunner: DetachedPromiseRunner =
104-
new DetachedPromiseRunner();
105-
const isISRRevalidation = headers["x-isr"] === "1";
106-
const mergeHeadersPriority = globalThis.openNextConfig.dangerous
107-
?.headersAndCookiesPriority
108-
? globalThis.openNextConfig.dangerous.headersAndCookiesPriority(
109-
preprocessedEvent,
110-
)
111-
: "middleware";
112-
const internalResult = await globalThis.__als.run(
113-
{
114-
requestId,
115-
pendingPromiseRunner,
116-
isISRRevalidation,
117-
mergeHeadersPriority,
118-
},
119-
async () => {
120-
const preprocessedResult = preprocessResult as MiddlewareOutputEvent;
121-
const req = new IncomingMessage(reqProps);
122-
const res = createServerResponse(
123-
preprocessedEvent,
124-
overwrittenResponseHeaders,
125-
responseStreaming,
126-
);
127-
128-
await processRequest(
129-
req,
130-
res,
131-
preprocessedEvent,
132-
preprocessedResult.isExternalRewrite,
133-
);
134-
135-
const { statusCode, headers, isBase64Encoded, body } = convertRes(res);
136-
137-
const internalResult = {
138-
type: internalEvent.type,
139-
statusCode,
140-
headers,
141-
body,
142-
isBase64Encoded,
143-
};
144-
145-
// reset lastModified. We need to do this to avoid memory leaks
146-
delete globalThis.lastModified[requestId];
147-
148-
await pendingPromiseRunner.await();
149-
150-
return internalResult;
151-
},
152-
);
153-
return internalResult;
15487
}
88+
89+
const preprocessedEvent = preprocessResult.internalEvent;
90+
debug("preprocessedEvent", preprocessedEvent);
91+
const reqProps = {
92+
method: preprocessedEvent.method,
93+
url: preprocessedEvent.url,
94+
//WORKAROUND: We pass this header to the serverless function to mimic a prefetch request which will not trigger revalidation since we handle revalidation differently
95+
// There is 3 way we can handle revalidation:
96+
// 1. We could just let the revalidation go as normal, but due to race conditions the revalidation will be unreliable
97+
// 2. We could alter the lastModified time of our cache to make next believe that the cache is fresh, but this could cause issues with stale data since the cdn will cache the stale data as if it was fresh
98+
// 3. OUR CHOICE: We could pass a purpose prefetch header to the serverless function to make next believe that the request is a prefetch request and not trigger revalidation (This could potentially break in the future if next changes the behavior of prefetch requests)
99+
headers: { ...headers, purpose: "prefetch" },
100+
body: preprocessedEvent.body,
101+
remoteAddress: preprocessedEvent.remoteAddress,
102+
};
103+
const requestId = Math.random().toString(36);
104+
const pendingPromiseRunner = new DetachedPromiseRunner();
105+
const isISRRevalidation = headers["x-isr"] === "1";
106+
const mergeHeadersPriority = globalThis.openNextConfig.dangerous
107+
?.headersAndCookiesPriority
108+
? globalThis.openNextConfig.dangerous.headersAndCookiesPriority(
109+
preprocessedEvent,
110+
)
111+
: "middleware";
112+
const internalResult = await globalThis.__als.run(
113+
{
114+
requestId,
115+
pendingPromiseRunner,
116+
isISRRevalidation,
117+
mergeHeadersPriority,
118+
},
119+
async () => {
120+
const preprocessedResult = preprocessResult as MiddlewareOutputEvent;
121+
const req = new IncomingMessage(reqProps);
122+
const res = createServerResponse(
123+
preprocessedEvent,
124+
overwrittenResponseHeaders,
125+
responseStreaming,
126+
);
127+
128+
await processRequest(
129+
req,
130+
res,
131+
preprocessedEvent,
132+
preprocessedResult.isExternalRewrite,
133+
);
134+
135+
const { statusCode, headers, isBase64Encoded, body } = convertRes(res);
136+
137+
const internalResult = {
138+
type: internalEvent.type,
139+
statusCode,
140+
headers,
141+
body,
142+
isBase64Encoded,
143+
};
144+
145+
// reset lastModified. We need to do this to avoid memory leaks
146+
delete globalThis.lastModified[requestId];
147+
148+
await pendingPromiseRunner.await();
149+
150+
return internalResult;
151+
},
152+
);
153+
return internalResult;
155154
}
156155

157156
async function processRequest(
@@ -169,18 +168,16 @@ async function processRequest(
169168
// `serverHandler` is replaced at build time depending on user's
170169
// nextjs version to patch Nextjs 13.4.x and future breaking changes.
171170

172-
const { rawPath } = internalEvent;
173-
174171
if (isExternalRewrite) {
175172
return proxyRequest(internalEvent, res);
176-
} else {
177-
//#override applyNextjsPrebundledReact
178-
setNextjsPrebundledReact(rawPath);
179-
//#endOverride
180-
181-
// Next Server
182-
await requestHandler(req, res);
183173
}
174+
175+
//#override applyNextjsPrebundledReact
176+
setNextjsPrebundledReact(internalEvent.rawPath);
177+
//#endOverride
178+
179+
// Next Server
180+
await requestHandler(req, res);
184181
} catch (e: any) {
185182
// This might fail when using bundled next, importing won't do the trick either
186183
if (e.constructor.name === "NoFallbackError") {

0 commit comments

Comments
 (0)