@opennextjs/aws 3.6.5 → 3.7.0
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 -1
- package/dist/adapters/cache.js +4 -4
- package/dist/adapters/composable-cache.js +14 -4
- package/dist/adapters/edge-adapter.js +5 -1
- package/dist/adapters/middleware.js +18 -8
- package/dist/build/copyTracedFiles.js +10 -5
- package/dist/build/createAssets.js +55 -51
- package/dist/build/createServerBundle.js +0 -1
- package/dist/build/patch/patches/index.d.ts +0 -1
- package/dist/build/patch/patches/index.js +0 -1
- package/dist/build/patch/patches/patchNextServer.d.ts +13 -3
- package/dist/build/patch/patches/patchNextServer.js +82 -44
- package/dist/core/createMainHandler.js +4 -1
- package/dist/core/requestHandler.js +11 -2
- package/dist/core/resolve.d.ts +5 -0
- package/dist/core/resolve.js +11 -0
- package/dist/core/routing/cacheInterceptor.js +13 -1
- package/dist/core/routing/matcher.d.ts +5 -0
- package/dist/core/routing/matcher.js +9 -3
- package/dist/core/routing/util.js +2 -0
- package/dist/core/routingHandler.d.ts +5 -1
- package/dist/core/routingHandler.js +75 -52
- package/dist/overrides/assetResolver/dummy.d.ts +8 -0
- package/dist/overrides/assetResolver/dummy.js +9 -0
- package/dist/overrides/converters/edge.js +7 -1
- package/dist/types/global.d.ts +9 -1
- package/dist/types/next-types.d.ts +2 -0
- package/dist/types/open-next.d.ts +8 -1
- package/dist/types/overrides.d.ts +19 -5
- package/dist/utils/cache.d.ts +2 -1
- package/dist/utils/cache.js +32 -0
- package/dist/utils/promise.d.ts +2 -1
- package/dist/utils/promise.js +3 -2
- package/package.json +1 -1
- package/dist/build/patch/patches/dropBabel.d.ts +0 -20
- package/dist/build/patch/patches/dropBabel.js +0 -72
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ OpenNext takes the Next.js build output and converts it into packages that can b
|
|
|
23
23
|
|
|
24
24
|
## Features
|
|
25
25
|
|
|
26
|
-
OpenNext aims to support all Next.js
|
|
26
|
+
OpenNext aims to support all Next.js 15 features. Some features are work in progress. If you are running into any problems make sure to check the [docs](https://opennext.js.org/aws) first before you open a [new issue](/issues/new) or visit our [Discord](https://discord.gg/opennextjs) to let us know!
|
|
27
27
|
|
|
28
28
|
- [x] App & Pages Router
|
|
29
29
|
- [x] API routes
|
package/dist/adapters/cache.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getTagsFromValue, hasBeenRevalidated } from "../utils/cache";
|
|
1
|
+
import { getTagsFromValue, hasBeenRevalidated, writeTags } from "../utils/cache";
|
|
2
2
|
import { isBinaryContentType } from "../utils/binary";
|
|
3
3
|
import { debug, error, warn } from "./logger";
|
|
4
4
|
function isFetchCache(options) {
|
|
@@ -246,7 +246,7 @@ export default class Cache {
|
|
|
246
246
|
try {
|
|
247
247
|
if (globalThis.tagCache.mode === "nextMode") {
|
|
248
248
|
const paths = (await globalThis.tagCache.getPathsByTags?.(_tags)) ?? [];
|
|
249
|
-
await
|
|
249
|
+
await writeTags(_tags);
|
|
250
250
|
if (paths.length > 0) {
|
|
251
251
|
// TODO: we should introduce a new method in cdnInvalidationHandler to invalidate paths by tags for cdn that supports it
|
|
252
252
|
// It also means that we'll need to provide the tags used in every request to the wrapper or converter.
|
|
@@ -291,7 +291,7 @@ export default class Cache {
|
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
// Update all keys with the given tag with revalidatedAt set to now
|
|
294
|
-
await
|
|
294
|
+
await writeTags(toInsert);
|
|
295
295
|
// We can now invalidate all paths in the CDN
|
|
296
296
|
// This only applies to `revalidateTag`, not to `res.revalidate()`
|
|
297
297
|
const uniquePaths = Array.from(new Set(toInsert
|
|
@@ -340,7 +340,7 @@ export default class Cache {
|
|
|
340
340
|
const storedTags = await globalThis.tagCache.getByPath(key);
|
|
341
341
|
const tagsToWrite = derivedTags.filter((tag) => !storedTags.includes(tag));
|
|
342
342
|
if (tagsToWrite.length > 0) {
|
|
343
|
-
await
|
|
343
|
+
await writeTags(tagsToWrite.map((tag) => ({
|
|
344
344
|
path: key,
|
|
345
345
|
tag: tag,
|
|
346
346
|
// In case the tags are not there we just need to create them
|
|
@@ -1,8 +1,15 @@
|
|
|
1
|
+
import { writeTags } from "../utils/cache";
|
|
1
2
|
import { fromReadableStream, toReadableStream } from "../utils/stream";
|
|
2
3
|
import { debug } from "./logger";
|
|
4
|
+
const pendingWritePromiseMap = new Map();
|
|
3
5
|
export default {
|
|
4
6
|
async get(cacheKey) {
|
|
5
7
|
try {
|
|
8
|
+
// We first check if we have a pending write for this cache key
|
|
9
|
+
// If we do, we return the pending promise instead of fetching the cache
|
|
10
|
+
if (pendingWritePromiseMap.has(cacheKey)) {
|
|
11
|
+
return pendingWritePromiseMap.get(cacheKey);
|
|
12
|
+
}
|
|
6
13
|
const result = await globalThis.incrementalCache.get(cacheKey, "composable");
|
|
7
14
|
if (!result?.value?.value) {
|
|
8
15
|
return undefined;
|
|
@@ -32,7 +39,10 @@ export default {
|
|
|
32
39
|
}
|
|
33
40
|
},
|
|
34
41
|
async set(cacheKey, pendingEntry) {
|
|
35
|
-
|
|
42
|
+
pendingWritePromiseMap.set(cacheKey, pendingEntry);
|
|
43
|
+
const entry = await pendingEntry.finally(() => {
|
|
44
|
+
pendingWritePromiseMap.delete(cacheKey);
|
|
45
|
+
});
|
|
36
46
|
const valueToStore = await fromReadableStream(entry.value);
|
|
37
47
|
await globalThis.incrementalCache.set(cacheKey, {
|
|
38
48
|
...entry,
|
|
@@ -42,7 +52,7 @@ export default {
|
|
|
42
52
|
const storedTags = await globalThis.tagCache.getByPath(cacheKey);
|
|
43
53
|
const tagsToWrite = entry.tags.filter((tag) => !storedTags.includes(tag));
|
|
44
54
|
if (tagsToWrite.length > 0) {
|
|
45
|
-
await
|
|
55
|
+
await writeTags(tagsToWrite.map((tag) => ({ tag, path: cacheKey })));
|
|
46
56
|
}
|
|
47
57
|
}
|
|
48
58
|
},
|
|
@@ -60,7 +70,7 @@ export default {
|
|
|
60
70
|
},
|
|
61
71
|
async expireTags(...tags) {
|
|
62
72
|
if (globalThis.tagCache.mode === "nextMode") {
|
|
63
|
-
return
|
|
73
|
+
return writeTags(tags);
|
|
64
74
|
}
|
|
65
75
|
const tagCache = globalThis.tagCache;
|
|
66
76
|
const revalidatedAt = Date.now();
|
|
@@ -79,7 +89,7 @@ export default {
|
|
|
79
89
|
for (const entry of pathsToUpdate.flat()) {
|
|
80
90
|
setToWrite.add(entry);
|
|
81
91
|
}
|
|
82
|
-
await
|
|
92
|
+
await writeTags(Array.from(setToWrite));
|
|
83
93
|
},
|
|
84
94
|
// This one is necessary for older versions of next
|
|
85
95
|
async receiveExpiredTags(...tags) {
|
|
@@ -4,11 +4,15 @@ import { emptyReadableStream } from "../utils/stream";
|
|
|
4
4
|
import { NextConfig } from "../adapters/config";
|
|
5
5
|
import { createGenericHandler } from "../core/createGenericHandler";
|
|
6
6
|
import { convertBodyToReadableStream } from "../core/routing/util";
|
|
7
|
+
import { INTERNAL_EVENT_REQUEST_ID } from "../core/routingHandler";
|
|
7
8
|
globalThis.__openNextAls = new AsyncLocalStorage();
|
|
8
9
|
const defaultHandler = async (internalEvent, options) => {
|
|
9
10
|
globalThis.isEdgeRuntime = true;
|
|
11
|
+
const requestId = globalThis.openNextConfig.middleware?.external
|
|
12
|
+
? internalEvent.headers[INTERNAL_EVENT_REQUEST_ID]
|
|
13
|
+
: Math.random().toString(36);
|
|
10
14
|
// We run everything in the async local storage context so that it is available in edge runtime functions
|
|
11
|
-
return runWithOpenNextRequestContext({ isISRRevalidation: false, waitUntil: options?.waitUntil }, async () => {
|
|
15
|
+
return runWithOpenNextRequestContext({ isISRRevalidation: false, waitUntil: options?.waitUntil, requestId }, async () => {
|
|
12
16
|
// @ts-expect-error - This is bundled
|
|
13
17
|
const handler = await import("./middleware.mjs");
|
|
14
18
|
const response = await handler.default({
|
|
@@ -1,25 +1,29 @@
|
|
|
1
1
|
import { runWithOpenNextRequestContext } from "../utils/promise";
|
|
2
2
|
import { debug, error } from "../adapters/logger";
|
|
3
3
|
import { createGenericHandler } from "../core/createGenericHandler";
|
|
4
|
-
import { resolveIncrementalCache, resolveOriginResolver, resolveProxyRequest, resolveQueue, resolveTagCache, } from "../core/resolve";
|
|
4
|
+
import { resolveAssetResolver, resolveIncrementalCache, resolveOriginResolver, resolveProxyRequest, resolveQueue, resolveTagCache, } from "../core/resolve";
|
|
5
5
|
import { constructNextUrl } from "../core/routing/util";
|
|
6
|
-
import routingHandler, { INTERNAL_HEADER_INITIAL_URL, INTERNAL_HEADER_RESOLVED_ROUTES, } from "../core/routingHandler";
|
|
6
|
+
import routingHandler, { INTERNAL_EVENT_REQUEST_ID, INTERNAL_HEADER_INITIAL_URL, INTERNAL_HEADER_RESOLVED_ROUTES, } from "../core/routingHandler";
|
|
7
7
|
globalThis.internalFetch = fetch;
|
|
8
8
|
globalThis.__openNextAls = new AsyncLocalStorage();
|
|
9
9
|
const defaultHandler = async (internalEvent, options) => {
|
|
10
|
-
const
|
|
11
|
-
const
|
|
10
|
+
const config = globalThis.openNextConfig.middleware;
|
|
11
|
+
const originResolver = await resolveOriginResolver(config?.originResolver);
|
|
12
|
+
const externalRequestProxy = await resolveProxyRequest(config?.override?.proxyExternalRequest);
|
|
13
|
+
const assetResolver = await resolveAssetResolver(config?.assetResolver);
|
|
12
14
|
//#override includeCacheInMiddleware
|
|
13
|
-
globalThis.tagCache = await resolveTagCache(
|
|
14
|
-
globalThis.queue = await resolveQueue(
|
|
15
|
-
globalThis.incrementalCache = await resolveIncrementalCache(
|
|
15
|
+
globalThis.tagCache = await resolveTagCache(config?.override?.tagCache);
|
|
16
|
+
globalThis.queue = await resolveQueue(config?.override?.queue);
|
|
17
|
+
globalThis.incrementalCache = await resolveIncrementalCache(config?.override?.incrementalCache);
|
|
16
18
|
//#endOverride
|
|
19
|
+
const requestId = Math.random().toString(36);
|
|
17
20
|
// We run everything in the async local storage context so that it is available in the external middleware
|
|
18
21
|
return runWithOpenNextRequestContext({
|
|
19
22
|
isISRRevalidation: internalEvent.headers["x-isr"] === "1",
|
|
20
23
|
waitUntil: options?.waitUntil,
|
|
24
|
+
requestId,
|
|
21
25
|
}, async () => {
|
|
22
|
-
const result = await routingHandler(internalEvent);
|
|
26
|
+
const result = await routingHandler(internalEvent, { assetResolver });
|
|
23
27
|
if ("internalEvent" in result) {
|
|
24
28
|
debug("Middleware intercepted event", internalEvent);
|
|
25
29
|
if (!result.isExternalRewrite) {
|
|
@@ -32,6 +36,7 @@ const defaultHandler = async (internalEvent, options) => {
|
|
|
32
36
|
...result.internalEvent.headers,
|
|
33
37
|
[INTERNAL_HEADER_INITIAL_URL]: internalEvent.url,
|
|
34
38
|
[INTERNAL_HEADER_RESOLVED_ROUTES]: JSON.stringify(result.resolvedRoutes),
|
|
39
|
+
[INTERNAL_EVENT_REQUEST_ID]: requestId,
|
|
35
40
|
},
|
|
36
41
|
},
|
|
37
42
|
isExternalRewrite: result.isExternalRewrite,
|
|
@@ -50,6 +55,10 @@ const defaultHandler = async (internalEvent, options) => {
|
|
|
50
55
|
type: "middleware",
|
|
51
56
|
internalEvent: {
|
|
52
57
|
...result.internalEvent,
|
|
58
|
+
headers: {
|
|
59
|
+
...result.internalEvent.headers,
|
|
60
|
+
[INTERNAL_EVENT_REQUEST_ID]: requestId,
|
|
61
|
+
},
|
|
53
62
|
rawPath: "/500",
|
|
54
63
|
url: constructNextUrl(result.internalEvent.url, "/500"),
|
|
55
64
|
method: "GET",
|
|
@@ -63,6 +72,7 @@ const defaultHandler = async (internalEvent, options) => {
|
|
|
63
72
|
};
|
|
64
73
|
}
|
|
65
74
|
}
|
|
75
|
+
result.headers[INTERNAL_EVENT_REQUEST_ID] = requestId;
|
|
66
76
|
debug("Middleware response", result);
|
|
67
77
|
return result;
|
|
68
78
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import url from "node:url";
|
|
2
|
-
import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
|
|
2
|
+
import { copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, readlinkSync, statSync, symlinkSync, writeFileSync, } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { loadAppPathsManifest, loadBuildId, loadConfig, loadFunctionsConfigManifest, loadMiddlewareManifest, loadPagesManifest, loadPrerenderManifest, } from "../adapters/config/util.js";
|
|
5
5
|
import { getCrossPlatformPathRegex } from "../utils/regex.js";
|
|
@@ -223,15 +223,15 @@ File ${serverPath} does not exist
|
|
|
223
223
|
copyFileSync(path.join(standaloneNextDir, filePath), path.join(outputNextDir, filePath));
|
|
224
224
|
}
|
|
225
225
|
};
|
|
226
|
+
const manifests = getManifests(standaloneNextDir);
|
|
227
|
+
const { config, prerenderManifest, pagesManifest } = manifests;
|
|
226
228
|
// Get all the static files - Should be only for pages dir
|
|
227
229
|
// Ideally we would filter only those that might get accessed in this specific functions
|
|
228
230
|
// Maybe even move this to s3 directly
|
|
229
231
|
if (hasPageDir) {
|
|
230
232
|
// First we get truly static files - i.e. pages without getStaticProps
|
|
231
|
-
const staticFiles = Object.values(
|
|
233
|
+
const staticFiles = Object.values(pagesManifest);
|
|
232
234
|
// Then we need to get all fallback: true dynamic routes html
|
|
233
|
-
const prerenderManifest = loadPrerenderManifest(standaloneNextDir);
|
|
234
|
-
const config = loadConfig(standaloneNextDir);
|
|
235
235
|
const locales = config.i18n?.locales;
|
|
236
236
|
Object.values(prerenderManifest.dynamicRoutes).forEach((route) => {
|
|
237
237
|
if (typeof route.fallback === "string") {
|
|
@@ -249,10 +249,15 @@ File ${serverPath} does not exist
|
|
|
249
249
|
.filter((file) => file.endsWith(".html"))
|
|
250
250
|
.forEach((file) => copyStaticFile(`server/${file}`));
|
|
251
251
|
}
|
|
252
|
+
// Copy .next/static/css from standalone to output dir
|
|
253
|
+
// needed for optimizeCss feature to work
|
|
254
|
+
if (config.experimental.optimizeCss) {
|
|
255
|
+
cpSync(path.join(standaloneNextDir, "static", "css"), path.join(outputNextDir, "static", "css"), { recursive: true });
|
|
256
|
+
}
|
|
252
257
|
logger.debug("copyTracedFiles:", Date.now() - tsStart, "ms");
|
|
253
258
|
return {
|
|
254
259
|
tracedFiles,
|
|
255
260
|
nodePackages,
|
|
256
|
-
manifests
|
|
261
|
+
manifests,
|
|
257
262
|
};
|
|
258
263
|
}
|
|
@@ -62,44 +62,46 @@ export function createCacheAssets(options) {
|
|
|
62
62
|
const packagePath = buildHelper.getPackagePath(options);
|
|
63
63
|
const buildId = buildHelper.getBuildId(options);
|
|
64
64
|
let useTagCache = false;
|
|
65
|
-
// Copy pages to cache folder
|
|
66
65
|
const dotNextPath = path.join(appBuildOutputPath, ".next/standalone", packagePath);
|
|
67
|
-
const
|
|
68
|
-
|
|
66
|
+
const outputCachePath = path.join(outputDir, "cache", buildId);
|
|
67
|
+
fs.mkdirSync(outputCachePath, { recursive: true });
|
|
68
|
+
const sourceDirs = [".next/server/pages", ".next/server/app"]
|
|
69
69
|
.map((dir) => path.join(dotNextPath, dir))
|
|
70
|
-
.filter(fs.existsSync)
|
|
71
|
-
.forEach((dir) => fs.cpSync(dir, outputPath, { recursive: true }));
|
|
72
|
-
// Remove non-cache files
|
|
70
|
+
.filter(fs.existsSync);
|
|
73
71
|
const htmlPages = buildHelper.getHtmlPages(dotNextPath);
|
|
74
|
-
|
|
72
|
+
const isFileSkipped = (relativePath) => relativePath.endsWith(".js") ||
|
|
75
73
|
relativePath.endsWith(".js.nft.json") ||
|
|
76
|
-
(relativePath.endsWith(".html") && htmlPages.has(relativePath))
|
|
74
|
+
(relativePath.endsWith(".html") && htmlPages.has(relativePath));
|
|
77
75
|
// Merge cache files into a single file
|
|
78
76
|
const cacheFilesPath = {};
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
77
|
+
// Process each source directory
|
|
78
|
+
sourceDirs.forEach((sourceDir) => {
|
|
79
|
+
buildHelper.traverseFiles(sourceDir, ({ relativePath }) => !isFileSkipped(relativePath), ({ absolutePath, relativePath }) => {
|
|
80
|
+
const ext = path.extname(absolutePath);
|
|
81
|
+
switch (ext) {
|
|
82
|
+
case ".meta":
|
|
83
|
+
case ".html":
|
|
84
|
+
case ".json":
|
|
85
|
+
case ".body":
|
|
86
|
+
case ".rsc": {
|
|
87
|
+
const newFilePath = path
|
|
88
|
+
.join(outputCachePath, relativePath)
|
|
89
|
+
.substring(0, path.join(outputCachePath, relativePath).length - ext.length)
|
|
90
|
+
.replace(/\.prefetch$/, "")
|
|
91
|
+
.concat(".cache");
|
|
92
|
+
cacheFilesPath[newFilePath] = {
|
|
93
|
+
[ext.slice(1)]: absolutePath,
|
|
94
|
+
...cacheFilesPath[newFilePath],
|
|
95
|
+
};
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case ".map":
|
|
99
|
+
break;
|
|
100
|
+
default:
|
|
101
|
+
logger.warn(`Unknown file extension: ${ext}`);
|
|
102
|
+
break;
|
|
96
103
|
}
|
|
97
|
-
|
|
98
|
-
break;
|
|
99
|
-
default:
|
|
100
|
-
logger.warn(`Unknown file extension: ${ext}`);
|
|
101
|
-
break;
|
|
102
|
-
}
|
|
104
|
+
});
|
|
103
105
|
});
|
|
104
106
|
// Generate cache file
|
|
105
107
|
Object.entries(cacheFilesPath).forEach(([cacheFilePath, files]) => {
|
|
@@ -122,6 +124,8 @@ export function createCacheAssets(options) {
|
|
|
122
124
|
: "utf8")
|
|
123
125
|
: undefined,
|
|
124
126
|
};
|
|
127
|
+
// Ensure directory exists before writing
|
|
128
|
+
fs.mkdirSync(path.dirname(cacheFilePath), { recursive: true });
|
|
125
129
|
fs.writeFileSync(cacheFilePath, JSON.stringify(cacheFileContent));
|
|
126
130
|
});
|
|
127
131
|
// We need to traverse the cache to find every .meta file
|
|
@@ -149,36 +153,36 @@ export function createCacheAssets(options) {
|
|
|
149
153
|
if (!options.config.dangerous?.disableTagCache) {
|
|
150
154
|
// Compute dynamodb cache data
|
|
151
155
|
// Traverse files inside cache to find all meta files and cache tags associated with them
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
fileData.headers["x-next-cache-tags"]
|
|
157
|
-
.
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
156
|
+
sourceDirs.forEach((sourceDir) => {
|
|
157
|
+
buildHelper.traverseFiles(sourceDir, ({ absolutePath, relativePath }) => absolutePath.endsWith(".meta") && !isFileSkipped(relativePath), ({ absolutePath, relativePath }) => {
|
|
158
|
+
const fileContent = fs.readFileSync(absolutePath, "utf8");
|
|
159
|
+
const fileData = JSON.parse(fileContent);
|
|
160
|
+
if (fileData.headers?.["x-next-cache-tags"]) {
|
|
161
|
+
fileData.headers["x-next-cache-tags"]
|
|
162
|
+
.split(",")
|
|
163
|
+
.forEach((tag) => {
|
|
164
|
+
// TODO: We should split the tag using getDerivedTags from next.js or maybe use an in house implementation
|
|
165
|
+
metaFiles.push({
|
|
166
|
+
tag: { S: path.posix.join(buildId, tag.trim()) },
|
|
167
|
+
path: {
|
|
168
|
+
S: path.posix.join(buildId, relativePath.replace(".meta", "")),
|
|
169
|
+
},
|
|
170
|
+
// We don't care about the revalidation time here, we just need to make sure it's there
|
|
171
|
+
revalidatedAt: { N: "1" },
|
|
172
|
+
});
|
|
167
173
|
});
|
|
168
|
-
}
|
|
169
|
-
}
|
|
174
|
+
}
|
|
175
|
+
});
|
|
170
176
|
});
|
|
171
177
|
if (metaFiles.length > 0) {
|
|
172
178
|
useTagCache = true;
|
|
173
179
|
const providerPath = path.join(outputDir, "dynamodb-provider");
|
|
174
|
-
//Copy open-next.config.mjs into the bundle
|
|
180
|
+
// Copy open-next.config.mjs into the bundle
|
|
175
181
|
fs.mkdirSync(providerPath, { recursive: true });
|
|
176
182
|
buildHelper.copyOpenNextConfig(options.buildDir, providerPath);
|
|
177
183
|
// TODO: check if metafiles doesn't contain duplicates
|
|
178
184
|
fs.writeFileSync(path.join(providerPath, "dynamodb-cache.json"), JSON.stringify(metaFiles));
|
|
179
185
|
}
|
|
180
186
|
}
|
|
181
|
-
// We need to remove files later because we need the metafiles for dynamodb tags cache
|
|
182
|
-
buildHelper.removeFiles(outputPath, ({ relativePath }) => !relativePath.endsWith(".cache"));
|
|
183
187
|
return { useTagCache, metaFiles };
|
|
184
188
|
}
|
|
@@ -126,7 +126,6 @@ async function generateBundle(name, options, fnOptions, codeCustomization) {
|
|
|
126
126
|
patches.patchEnvVars,
|
|
127
127
|
patches.patchBackgroundRevalidation,
|
|
128
128
|
patches.patchUseCacheForISR,
|
|
129
|
-
patches.patchDropBabel,
|
|
130
129
|
...additionalCodePatches,
|
|
131
130
|
]);
|
|
132
131
|
// Build Lambda code
|
|
@@ -3,4 +3,3 @@ export { patchNextServer } from "./patchNextServer.js";
|
|
|
3
3
|
export { patchFetchCacheForISR, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patchFetchCacheISR.js";
|
|
4
4
|
export { patchFetchCacheSetMissingWaitUntil } from "./patchFetchCacheWaitUntil.js";
|
|
5
5
|
export { patchBackgroundRevalidation } from "./patchBackgroundRevalidation.js";
|
|
6
|
-
export { patchDropBabel } from "./dropBabel.js";
|
|
@@ -3,4 +3,3 @@ export { patchNextServer } from "./patchNextServer.js";
|
|
|
3
3
|
export { patchFetchCacheForISR, patchUnstableCacheForISR, patchUseCacheForISR, } from "./patchFetchCacheISR.js";
|
|
4
4
|
export { patchFetchCacheSetMissingWaitUntil } from "./patchFetchCacheWaitUntil.js";
|
|
5
5
|
export { patchBackgroundRevalidation } from "./patchBackgroundRevalidation.js";
|
|
6
|
-
export { patchDropBabel } from "./dropBabel.js";
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
import type { CodePatcher } from "../codePatcher.js";
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
|
|
2
|
+
export declare const disablePreloadingRule = "\nrule:\n kind: statement_block\n inside:\n kind: if_statement\n any:\n - has:\n kind: member_expression\n pattern: this.nextConfig.experimental.preloadEntriesOnStart\n stopBy: end\n - has:\n kind: binary_expression\n pattern: appDocumentPreloading === true\n stopBy: end\nfix:\n '{}'\n";
|
|
3
|
+
export declare const removeMiddlewareManifestRule = "\nrule:\n kind: statement_block\n inside:\n kind: method_definition\n has:\n kind: property_identifier\n regex: ^getMiddlewareManifest$\nfix:\n '{return null;}'\n";
|
|
4
|
+
/**
|
|
5
|
+
* Swaps the body for a throwing implementation
|
|
6
|
+
*
|
|
7
|
+
* @param methodName The name of the method
|
|
8
|
+
* @returns A rule to replace the body with a `throw`
|
|
9
|
+
*/
|
|
10
|
+
export declare function createEmptyBodyRule(methodName: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Drops `require("./node-environment-extensions/error-inspect");`
|
|
13
|
+
*/
|
|
14
|
+
export declare const errorInspectRule = "\nrule:\n pattern: require(\"./node-environment-extensions/error-inspect\");\nfix: |-\n // Removed by OpenNext\n // require(\"./node-environment-extensions/error-inspect\");\n";
|
|
5
15
|
export declare const patchNextServer: CodePatcher;
|
|
@@ -1,51 +1,24 @@
|
|
|
1
|
+
import { getCrossPlatformPathRegex } from "../../../utils/regex.js";
|
|
1
2
|
import { createPatchCode } from "../astCodePatcher.js";
|
|
2
|
-
//
|
|
3
|
-
export const minimalRule = `
|
|
4
|
-
rule:
|
|
5
|
-
kind: member_expression
|
|
6
|
-
pattern: process.env.NEXT_MINIMAL
|
|
7
|
-
any:
|
|
8
|
-
- inside:
|
|
9
|
-
kind: parenthesized_expression
|
|
10
|
-
stopBy: end
|
|
11
|
-
inside:
|
|
12
|
-
kind: if_statement
|
|
13
|
-
any:
|
|
14
|
-
- inside:
|
|
15
|
-
kind: statement_block
|
|
16
|
-
inside:
|
|
17
|
-
kind: method_definition
|
|
18
|
-
any:
|
|
19
|
-
- has: {kind: property_identifier, field: name, regex: runEdgeFunction}
|
|
20
|
-
- has: {kind: property_identifier, field: name, regex: runMiddleware}
|
|
21
|
-
- has: {kind: property_identifier, field: name, regex: imageOptimizer}
|
|
22
|
-
- has:
|
|
23
|
-
kind: statement_block
|
|
24
|
-
has:
|
|
25
|
-
kind: expression_statement
|
|
26
|
-
pattern: res.statusCode = 400;
|
|
27
|
-
fix:
|
|
28
|
-
'true'
|
|
29
|
-
`;
|
|
30
|
-
// This rule will disable the background preloading of route done by NextServer by default during the creation of NextServer
|
|
3
|
+
// Disable the background preloading of route done by NextServer by default during the creation of NextServer
|
|
31
4
|
export const disablePreloadingRule = `
|
|
32
5
|
rule:
|
|
33
6
|
kind: statement_block
|
|
34
7
|
inside:
|
|
35
8
|
kind: if_statement
|
|
36
|
-
any:
|
|
37
|
-
- has:
|
|
9
|
+
any:
|
|
10
|
+
- has:
|
|
38
11
|
kind: member_expression
|
|
39
12
|
pattern: this.nextConfig.experimental.preloadEntriesOnStart
|
|
40
13
|
stopBy: end
|
|
41
|
-
- has:
|
|
14
|
+
- has:
|
|
42
15
|
kind: binary_expression
|
|
43
16
|
pattern: appDocumentPreloading === true
|
|
44
17
|
stopBy: end
|
|
45
18
|
fix:
|
|
46
19
|
'{}'
|
|
47
20
|
`;
|
|
48
|
-
//
|
|
21
|
+
// Mostly for splitted edge functions so that we don't try to match them on the other non edge functions
|
|
49
22
|
export const removeMiddlewareManifestRule = `
|
|
50
23
|
rule:
|
|
51
24
|
kind: statement_block
|
|
@@ -53,39 +26,104 @@ rule:
|
|
|
53
26
|
kind: method_definition
|
|
54
27
|
has:
|
|
55
28
|
kind: property_identifier
|
|
56
|
-
regex: getMiddlewareManifest
|
|
29
|
+
regex: ^getMiddlewareManifest$
|
|
57
30
|
fix:
|
|
58
31
|
'{return null;}'
|
|
59
32
|
`;
|
|
33
|
+
/**
|
|
34
|
+
* Swaps the body for a throwing implementation
|
|
35
|
+
*
|
|
36
|
+
* @param methodName The name of the method
|
|
37
|
+
* @returns A rule to replace the body with a `throw`
|
|
38
|
+
*/
|
|
39
|
+
export function createEmptyBodyRule(methodName) {
|
|
40
|
+
return `
|
|
41
|
+
rule:
|
|
42
|
+
pattern:
|
|
43
|
+
selector: method_definition
|
|
44
|
+
context: "class { async ${methodName}($$$PARAMS) { $$$_ } }"
|
|
45
|
+
fix: |-
|
|
46
|
+
async ${methodName}($$$PARAMS) {
|
|
47
|
+
throw new Error("${methodName} should not be called with OpenNext");
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Drops `require("./node-environment-extensions/error-inspect");`
|
|
53
|
+
*/
|
|
54
|
+
export const errorInspectRule = `
|
|
55
|
+
rule:
|
|
56
|
+
pattern: require("./node-environment-extensions/error-inspect");
|
|
57
|
+
fix: |-
|
|
58
|
+
// Removed by OpenNext
|
|
59
|
+
// require("./node-environment-extensions/error-inspect");
|
|
60
|
+
`;
|
|
61
|
+
const pathFilter = getCrossPlatformPathRegex(String.raw `/next/dist/server/next-server\.js$`, {
|
|
62
|
+
escape: false,
|
|
63
|
+
});
|
|
64
|
+
/**
|
|
65
|
+
* Patches to avoid pulling babel (~4MB).
|
|
66
|
+
*
|
|
67
|
+
* Details:
|
|
68
|
+
* - empty `NextServer#runMiddleware` and `NextServer#runEdgeFunction` that are not used
|
|
69
|
+
* - drop `next/dist/server/node-environment-extensions/error-inspect.js`
|
|
70
|
+
*/
|
|
71
|
+
const babelPatches = [
|
|
72
|
+
// Empty the body of `NextServer#runMiddleware`
|
|
73
|
+
{
|
|
74
|
+
field: {
|
|
75
|
+
pathFilter,
|
|
76
|
+
contentFilter: /runMiddleware\(/,
|
|
77
|
+
patchCode: createPatchCode(createEmptyBodyRule("runMiddleware")),
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
// Empty the body of `NextServer#runEdgeFunction`
|
|
81
|
+
{
|
|
82
|
+
field: {
|
|
83
|
+
pathFilter,
|
|
84
|
+
contentFilter: /runEdgeFunction\(/,
|
|
85
|
+
patchCode: createPatchCode(createEmptyBodyRule("runEdgeFunction")),
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
// Drop `error-inspect` that pulls babel
|
|
89
|
+
{
|
|
90
|
+
field: {
|
|
91
|
+
pathFilter,
|
|
92
|
+
contentFilter: /error-inspect/,
|
|
93
|
+
patchCode: createPatchCode(errorInspectRule),
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
];
|
|
60
97
|
export const patchNextServer = {
|
|
61
98
|
name: "patch-next-server",
|
|
62
99
|
patches: [
|
|
63
|
-
//
|
|
100
|
+
// Empty the body of `NextServer#imageOptimizer` - unused in OpenNext
|
|
64
101
|
{
|
|
65
|
-
versions: ">=15.0.0",
|
|
66
102
|
field: {
|
|
67
|
-
pathFilter
|
|
68
|
-
contentFilter: /
|
|
69
|
-
patchCode: createPatchCode(
|
|
103
|
+
pathFilter,
|
|
104
|
+
contentFilter: /imageOptimizer\(/,
|
|
105
|
+
patchCode: createPatchCode(createEmptyBodyRule("imageOptimizer")),
|
|
70
106
|
},
|
|
71
107
|
},
|
|
72
|
-
// Disable Next background preloading done at creation of `
|
|
108
|
+
// Disable Next background preloading done at creation of `NextServer`
|
|
73
109
|
{
|
|
74
|
-
versions: ">=
|
|
110
|
+
versions: ">=14.0.0",
|
|
75
111
|
field: {
|
|
76
|
-
pathFilter
|
|
112
|
+
pathFilter,
|
|
77
113
|
contentFilter: /this\.nextConfig\.experimental\.preloadEntriesOnStart/,
|
|
78
114
|
patchCode: createPatchCode(disablePreloadingRule),
|
|
79
115
|
},
|
|
80
116
|
},
|
|
81
117
|
// Don't match edge functions in `NextServer`
|
|
82
118
|
{
|
|
83
|
-
|
|
119
|
+
// Next 12 and some version of 13 use the bundled middleware/edge function
|
|
120
|
+
versions: ">=14.0.0",
|
|
84
121
|
field: {
|
|
85
|
-
pathFilter
|
|
122
|
+
pathFilter,
|
|
86
123
|
contentFilter: /getMiddlewareManifest/,
|
|
87
124
|
patchCode: createPatchCode(removeMiddlewareManifestRule),
|
|
88
125
|
},
|
|
89
126
|
},
|
|
127
|
+
...babelPatches,
|
|
90
128
|
],
|
|
91
129
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { debug } from "../adapters/logger";
|
|
2
2
|
import { generateUniqueId } from "../adapters/util";
|
|
3
3
|
import { openNextHandler } from "./requestHandler";
|
|
4
|
-
import { resolveCdnInvalidation, resolveConverter, resolveIncrementalCache, resolveProxyRequest, resolveQueue, resolveTagCache, resolveWrapper, } from "./resolve";
|
|
4
|
+
import { resolveAssetResolver, resolveCdnInvalidation, resolveConverter, resolveIncrementalCache, resolveProxyRequest, resolveQueue, resolveTagCache, resolveWrapper, } from "./resolve";
|
|
5
5
|
export async function createMainHandler() {
|
|
6
6
|
// @ts-expect-error `./open-next.config.mjs` exists only in the build output
|
|
7
7
|
const config = await import("./open-next.config.mjs").then((m) => m.default);
|
|
@@ -16,6 +16,9 @@ export async function createMainHandler() {
|
|
|
16
16
|
globalThis.queue = await resolveQueue(thisFunction.override?.queue);
|
|
17
17
|
globalThis.incrementalCache = await resolveIncrementalCache(thisFunction.override?.incrementalCache);
|
|
18
18
|
globalThis.tagCache = await resolveTagCache(thisFunction.override?.tagCache);
|
|
19
|
+
if (config.middleware?.external !== true) {
|
|
20
|
+
globalThis.assetResolver = await resolveAssetResolver(globalThis.openNextConfig.middleware?.assetResolver);
|
|
21
|
+
}
|
|
19
22
|
globalThis.proxyExternalRequest = await resolveProxyRequest(thisFunction.override?.proxyExternalRequest);
|
|
20
23
|
globalThis.cdnInvalidationHandler = await resolveCdnInvalidation(thisFunction.override?.cdnInvalidation);
|
|
21
24
|
// From the config, we create the converter
|
|
@@ -5,7 +5,7 @@ import { NextConfig } from "../adapters/config/index";
|
|
|
5
5
|
import { debug, error } from "../adapters/logger";
|
|
6
6
|
import { patchAsyncStorage } from "./patchAsyncStorage";
|
|
7
7
|
import { constructNextUrl, convertRes, convertToQuery, createServerResponse, } from "./routing/util";
|
|
8
|
-
import routingHandler, { INTERNAL_HEADER_INITIAL_URL, INTERNAL_HEADER_RESOLVED_ROUTES, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
|
|
8
|
+
import routingHandler, { INTERNAL_EVENT_REQUEST_ID, INTERNAL_HEADER_INITIAL_URL, INTERNAL_HEADER_RESOLVED_ROUTES, MIDDLEWARE_HEADER_PREFIX, MIDDLEWARE_HEADER_PREFIX_LEN, } from "./routingHandler";
|
|
9
9
|
import { requestHandler, setNextjsPrebundledReact } from "./util";
|
|
10
10
|
// This is used to identify requests in the cache
|
|
11
11
|
globalThis.__openNextAls = new AsyncLocalStorage();
|
|
@@ -14,10 +14,17 @@ patchAsyncStorage();
|
|
|
14
14
|
//#endOverride
|
|
15
15
|
export async function openNextHandler(internalEvent, options) {
|
|
16
16
|
const initialHeaders = internalEvent.headers;
|
|
17
|
+
// We only use the requestId header if we are using an external middleware
|
|
18
|
+
// This is to ensure that no one can spoof the requestId
|
|
19
|
+
// When using an external middleware, we always assume that headers cannot be spoofed
|
|
20
|
+
const requestId = globalThis.openNextConfig.middleware?.external
|
|
21
|
+
? internalEvent.headers[INTERNAL_EVENT_REQUEST_ID]
|
|
22
|
+
: Math.random().toString(36);
|
|
17
23
|
// We run everything in the async local storage context so that it is available in the middleware as well as in NextServer
|
|
18
24
|
return runWithOpenNextRequestContext({
|
|
19
25
|
isISRRevalidation: initialHeaders["x-isr"] === "1",
|
|
20
26
|
waitUntil: options?.waitUntil,
|
|
27
|
+
requestId,
|
|
21
28
|
}, async () => {
|
|
22
29
|
await globalThis.__next_route_preloader("waitUntil");
|
|
23
30
|
if (initialHeaders["x-forwarded-host"]) {
|
|
@@ -40,7 +47,9 @@ export async function openNextHandler(internalEvent, options) {
|
|
|
40
47
|
...internalHeaders,
|
|
41
48
|
};
|
|
42
49
|
//#override withRouting
|
|
43
|
-
routingResult = await routingHandler(internalEvent
|
|
50
|
+
routingResult = await routingHandler(internalEvent, {
|
|
51
|
+
assetResolver: globalThis.assetResolver,
|
|
52
|
+
});
|
|
44
53
|
//#endOverride
|
|
45
54
|
const headers = "type" in routingResult
|
|
46
55
|
? routingResult.headers
|