@opennextjs/aws 3.1.4 → 3.1.5
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/dist/adapters/cache.js +68 -56
- package/dist/build/copyTracedFiles.js +1 -0
- package/dist/build/createServerBundle.d.ts +1 -2
- package/dist/build/createServerBundle.js +4 -3
- package/dist/build/generateOutput.d.ts +2 -2
- package/dist/build/generateOutput.js +16 -13
- package/dist/build/helper.d.ts +8 -6
- package/dist/build/helper.js +32 -7
- package/dist/build.d.ts +2 -1
- package/dist/build.js +56 -77
- package/dist/cache/next-types.d.ts +1 -0
- package/dist/converters/aws-cloudfront.js +1 -0
- package/dist/core/routing/i18n/accept-header.js +1 -0
- package/dist/core/routing/util.js +1 -1
- package/dist/core/routingHandler.js +1 -1
- package/dist/index.js +1 -0
- package/dist/minimize-js.js +1 -0
- package/dist/plugins/edge.js +1 -1
- package/dist/wrappers/aws-lambda-streaming.js +0 -1
- package/package.json +4 -3
package/dist/adapters/cache.js
CHANGED
|
@@ -101,6 +101,7 @@ export default class S3Cache {
|
|
|
101
101
|
rscData: Buffer.from(cacheData.rsc),
|
|
102
102
|
status: meta?.status,
|
|
103
103
|
headers: meta?.headers,
|
|
104
|
+
postponed: meta?.postponed,
|
|
104
105
|
},
|
|
105
106
|
};
|
|
106
107
|
}
|
|
@@ -145,65 +146,76 @@ export default class S3Cache {
|
|
|
145
146
|
.getStore()
|
|
146
147
|
?.pendingPromiseRunner.withResolvers();
|
|
147
148
|
try {
|
|
148
|
-
if (data
|
|
149
|
-
|
|
150
|
-
await globalThis.incrementalCache.set(key, {
|
|
151
|
-
type: "route",
|
|
152
|
-
body: body.toString(isBinaryContentType(String(headers["content-type"]))
|
|
153
|
-
? "base64"
|
|
154
|
-
: "utf8"),
|
|
155
|
-
meta: {
|
|
156
|
-
status,
|
|
157
|
-
headers,
|
|
158
|
-
},
|
|
159
|
-
}, false);
|
|
149
|
+
if (data === null || data === undefined) {
|
|
150
|
+
await globalThis.incrementalCache.delete(key);
|
|
160
151
|
}
|
|
161
|
-
else
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
152
|
+
else {
|
|
153
|
+
switch (data.kind) {
|
|
154
|
+
case "ROUTE":
|
|
155
|
+
case "APP_ROUTE":
|
|
156
|
+
const { body, status, headers } = data;
|
|
157
|
+
await globalThis.incrementalCache.set(key, {
|
|
158
|
+
type: "route",
|
|
159
|
+
body: body.toString(isBinaryContentType(String(headers["content-type"]))
|
|
160
|
+
? "base64"
|
|
161
|
+
: "utf8"),
|
|
162
|
+
meta: {
|
|
163
|
+
status,
|
|
164
|
+
headers,
|
|
165
|
+
},
|
|
166
|
+
}, false);
|
|
167
|
+
break;
|
|
168
|
+
case "PAGE":
|
|
169
|
+
case "PAGES": {
|
|
170
|
+
const { html, pageData, status, headers } = data;
|
|
171
|
+
const isAppPath = typeof pageData === "string";
|
|
172
|
+
if (isAppPath) {
|
|
173
|
+
await globalThis.incrementalCache.set(key, {
|
|
174
|
+
type: "app",
|
|
175
|
+
html,
|
|
176
|
+
rsc: pageData,
|
|
177
|
+
meta: {
|
|
178
|
+
status,
|
|
179
|
+
headers,
|
|
180
|
+
},
|
|
181
|
+
}, false);
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
await globalThis.incrementalCache.set(key, {
|
|
185
|
+
type: "page",
|
|
186
|
+
html,
|
|
187
|
+
json: pageData,
|
|
188
|
+
}, false);
|
|
189
|
+
}
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
case "APP_PAGE": {
|
|
193
|
+
const { html, rscData, headers, status } = data;
|
|
194
|
+
await globalThis.incrementalCache.set(key, {
|
|
195
|
+
type: "app",
|
|
196
|
+
html,
|
|
197
|
+
rsc: rscData.toString("utf8"),
|
|
198
|
+
meta: {
|
|
199
|
+
status,
|
|
200
|
+
headers,
|
|
201
|
+
},
|
|
202
|
+
}, false);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
case "FETCH":
|
|
206
|
+
await globalThis.incrementalCache.set(key, data, true);
|
|
207
|
+
break;
|
|
208
|
+
case "REDIRECT":
|
|
209
|
+
await globalThis.incrementalCache.set(key, {
|
|
210
|
+
type: "redirect",
|
|
211
|
+
props: data.props,
|
|
212
|
+
}, false);
|
|
213
|
+
break;
|
|
214
|
+
case "IMAGE":
|
|
215
|
+
// Not implemented
|
|
216
|
+
break;
|
|
181
217
|
}
|
|
182
218
|
}
|
|
183
|
-
else if (data?.kind === "APP_PAGE") {
|
|
184
|
-
const { html, rscData, headers, status } = data;
|
|
185
|
-
await globalThis.incrementalCache.set(key, {
|
|
186
|
-
type: "app",
|
|
187
|
-
html,
|
|
188
|
-
rsc: rscData.toString("utf8"),
|
|
189
|
-
meta: {
|
|
190
|
-
status,
|
|
191
|
-
headers,
|
|
192
|
-
},
|
|
193
|
-
}, false);
|
|
194
|
-
}
|
|
195
|
-
else if (data?.kind === "FETCH") {
|
|
196
|
-
await globalThis.incrementalCache.set(key, data, true);
|
|
197
|
-
}
|
|
198
|
-
else if (data?.kind === "REDIRECT") {
|
|
199
|
-
await globalThis.incrementalCache.set(key, {
|
|
200
|
-
type: "redirect",
|
|
201
|
-
props: data.props,
|
|
202
|
-
}, false);
|
|
203
|
-
}
|
|
204
|
-
else if (data === null || data === undefined) {
|
|
205
|
-
await globalThis.incrementalCache.delete(key);
|
|
206
|
-
}
|
|
207
219
|
// Write derivedTags to dynamodb
|
|
208
220
|
// If we use an in house version of getDerivedTags in build we should use it here instead of next's one
|
|
209
221
|
const derivedTags = data?.kind === "FETCH"
|
|
@@ -8,6 +8,7 @@ function copyPatchFile(outputDir) {
|
|
|
8
8
|
const outputPatchFile = path.join(outputDir, "patchedAsyncStorage.cjs");
|
|
9
9
|
copyFileSync(patchFile, outputPatchFile);
|
|
10
10
|
}
|
|
11
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
11
12
|
export async function copyTracedFiles(buildOutputPath, packagePath, outputDir, routes, bundledNextServer) {
|
|
12
13
|
const tsStart = Date.now();
|
|
13
14
|
const dotNextDir = path.join(buildOutputPath, ".next");
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
import { OpenNextConfig } from "../types/open-next";
|
|
2
1
|
import type { BuildOptions } from "./helper.js";
|
|
3
|
-
export declare function createServerBundle(
|
|
2
|
+
export declare function createServerBundle(options: BuildOptions): Promise<void>;
|
|
@@ -14,7 +14,8 @@ import { generateEdgeBundle } from "./edge/createEdgeBundle.js";
|
|
|
14
14
|
import { compareSemver, copyEnvFile, copyOpenNextConfig, esbuildAsync, traverseFiles, } from "./helper.js";
|
|
15
15
|
const require = topLevelCreateRequire(import.meta.url);
|
|
16
16
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
17
|
-
export async function createServerBundle(
|
|
17
|
+
export async function createServerBundle(options) {
|
|
18
|
+
const { config } = options;
|
|
18
19
|
const foundRoutes = new Set();
|
|
19
20
|
// Get all functions to build
|
|
20
21
|
const defaultFn = config.default;
|
|
@@ -22,7 +23,7 @@ export async function createServerBundle(config, options) {
|
|
|
22
23
|
// Recompile cache.ts as ESM if any function is using Deno runtime
|
|
23
24
|
if (defaultFn.runtime === "deno" ||
|
|
24
25
|
functions.some(([, fn]) => fn.runtime === "deno")) {
|
|
25
|
-
compileCache("esm");
|
|
26
|
+
compileCache(options, "esm");
|
|
26
27
|
}
|
|
27
28
|
const promises = functions.map(async ([name, fnOptions]) => {
|
|
28
29
|
const routes = fnOptions.routes;
|
|
@@ -208,7 +209,7 @@ function addDenoJson(outputPath, packagePath) {
|
|
|
208
209
|
};
|
|
209
210
|
fs.writeFileSync(path.join(outputPath, packagePath, "deno.json"), JSON.stringify(config, null, 2));
|
|
210
211
|
}
|
|
211
|
-
//TODO: check if this PR is still necessary https://github.com/
|
|
212
|
+
//TODO: check if this PR is still necessary https://github.com/opennextjs/opennextjs-aws/pull/341
|
|
212
213
|
function addMonorepoEntrypoint(outputPath, packagePath) {
|
|
213
214
|
// Note: in the monorepo case, the handler file is output to
|
|
214
215
|
// `.next/standalone/package/path/index.mjs`, but we want
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export declare function generateOutput(
|
|
1
|
+
import { type BuildOptions } from "./helper.js";
|
|
2
|
+
export declare function generateOutput(options: BuildOptions): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { getBuildId } from "./helper.js";
|
|
4
|
+
const indexHandler = "index.handler";
|
|
4
5
|
async function canStream(opts) {
|
|
5
6
|
if (!opts.override?.wrapper) {
|
|
6
7
|
return false;
|
|
@@ -59,7 +60,9 @@ function prefixPattern(basePath) {
|
|
|
59
60
|
: pattern;
|
|
60
61
|
};
|
|
61
62
|
}
|
|
62
|
-
|
|
63
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
64
|
+
export async function generateOutput(options) {
|
|
65
|
+
const { appBuildOutputPath, config } = options;
|
|
63
66
|
const edgeFunctions = {};
|
|
64
67
|
const isExternalMiddleware = config.middleware?.external ?? false;
|
|
65
68
|
if (isExternalMiddleware) {
|
|
@@ -75,14 +78,14 @@ export async function generateOutput(outputPath, config) {
|
|
|
75
78
|
if (value.placement === "global") {
|
|
76
79
|
edgeFunctions[key] = {
|
|
77
80
|
bundle: `.open-next/functions/${key}`,
|
|
78
|
-
handler:
|
|
81
|
+
handler: indexHandler,
|
|
79
82
|
...(await extractOverrideFn(value.override)),
|
|
80
83
|
};
|
|
81
84
|
}
|
|
82
85
|
});
|
|
83
86
|
const defaultOriginCanstream = await canStream(config.default);
|
|
84
87
|
//Load required-server-files.json
|
|
85
|
-
const requiredServerFiles = JSON.parse(fs.readFileSync(path.join(
|
|
88
|
+
const requiredServerFiles = JSON.parse(fs.readFileSync(path.join(appBuildOutputPath, ".next", "required-server-files.json"), "utf-8")).config;
|
|
86
89
|
const prefixer = prefixPattern(requiredServerFiles.basePath ?? "");
|
|
87
90
|
// First add s3 origins and image optimization
|
|
88
91
|
const defaultOrigins = {
|
|
@@ -111,7 +114,7 @@ export async function generateOutput(outputPath, config) {
|
|
|
111
114
|
},
|
|
112
115
|
imageOptimizer: {
|
|
113
116
|
type: "function",
|
|
114
|
-
handler:
|
|
117
|
+
handler: indexHandler,
|
|
115
118
|
bundle: ".open-next/image-optimization-function",
|
|
116
119
|
streaming: false,
|
|
117
120
|
imageLoader: await extractOverrideName("s3", config.imageOptimization?.loader),
|
|
@@ -127,7 +130,7 @@ export async function generateOutput(outputPath, config) {
|
|
|
127
130
|
}
|
|
128
131
|
: {
|
|
129
132
|
type: "function",
|
|
130
|
-
handler:
|
|
133
|
+
handler: indexHandler,
|
|
131
134
|
bundle: ".open-next/server-functions/default",
|
|
132
135
|
streaming: defaultOriginCanstream,
|
|
133
136
|
...(await extractOverrideFn(config.default.override)),
|
|
@@ -152,7 +155,7 @@ export async function generateOutput(outputPath, config) {
|
|
|
152
155
|
const streaming = await canStream(value);
|
|
153
156
|
origins[key] = {
|
|
154
157
|
type: "function",
|
|
155
|
-
handler:
|
|
158
|
+
handler: indexHandler,
|
|
156
159
|
bundle: `.open-next/server-functions/${key}`,
|
|
157
160
|
streaming,
|
|
158
161
|
...(await extractOverrideFn(value.override)),
|
|
@@ -170,7 +173,7 @@ export async function generateOutput(outputPath, config) {
|
|
|
170
173
|
const patterns = "patterns" in value ? value.patterns : ["*"];
|
|
171
174
|
patterns.forEach((pattern) => {
|
|
172
175
|
behaviors.push({
|
|
173
|
-
pattern: prefixer(pattern.replace(/BUILD_ID/, getBuildId(
|
|
176
|
+
pattern: prefixer(pattern.replace(/BUILD_ID/, getBuildId(appBuildOutputPath))),
|
|
174
177
|
origin: value.placement === "global" ? undefined : key,
|
|
175
178
|
edgeFunction: value.placement === "global"
|
|
176
179
|
? key
|
|
@@ -192,7 +195,7 @@ export async function generateOutput(outputPath, config) {
|
|
|
192
195
|
edgeFunction: isExternalMiddleware ? "middleware" : undefined,
|
|
193
196
|
});
|
|
194
197
|
//Compute behaviors for assets files
|
|
195
|
-
const assetPath = path.join(
|
|
198
|
+
const assetPath = path.join(appBuildOutputPath, ".open-next", "assets");
|
|
196
199
|
fs.readdirSync(assetPath).forEach((item) => {
|
|
197
200
|
if (fs.statSync(path.join(assetPath, item)).isDirectory()) {
|
|
198
201
|
behaviors.push({
|
|
@@ -209,7 +212,7 @@ export async function generateOutput(outputPath, config) {
|
|
|
209
212
|
});
|
|
210
213
|
// Check if we produced a dynamodb provider output
|
|
211
214
|
const isTagCacheDisabled = config.dangerous?.disableTagCache ||
|
|
212
|
-
!fs.existsSync(path.join(
|
|
215
|
+
!fs.existsSync(path.join(appBuildOutputPath, ".open-next", "dynamodb-provider"));
|
|
213
216
|
const output = {
|
|
214
217
|
edgeFunctions,
|
|
215
218
|
origins,
|
|
@@ -218,22 +221,22 @@ export async function generateOutput(outputPath, config) {
|
|
|
218
221
|
disableIncrementalCache: config.dangerous?.disableIncrementalCache,
|
|
219
222
|
disableTagCache: config.dangerous?.disableTagCache,
|
|
220
223
|
warmer: {
|
|
221
|
-
handler:
|
|
224
|
+
handler: indexHandler,
|
|
222
225
|
bundle: ".open-next/warmer-function",
|
|
223
226
|
},
|
|
224
227
|
initializationFunction: isTagCacheDisabled
|
|
225
228
|
? undefined
|
|
226
229
|
: {
|
|
227
|
-
handler:
|
|
230
|
+
handler: indexHandler,
|
|
228
231
|
bundle: ".open-next/dynamodb-provider",
|
|
229
232
|
},
|
|
230
233
|
revalidationFunction: config.dangerous?.disableIncrementalCache
|
|
231
234
|
? undefined
|
|
232
235
|
: {
|
|
233
|
-
handler:
|
|
236
|
+
handler: indexHandler,
|
|
234
237
|
bundle: ".open-next/revalidation-function",
|
|
235
238
|
},
|
|
236
239
|
},
|
|
237
240
|
};
|
|
238
|
-
fs.writeFileSync(path.join(
|
|
241
|
+
fs.writeFileSync(path.join(appBuildOutputPath, ".open-next", "open-next.output.json"), JSON.stringify(output));
|
|
239
242
|
}
|
package/dist/build/helper.d.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import { BuildOptions as ESBuildOptions } from "esbuild";
|
|
2
2
|
import { OpenNextConfig } from "../types/open-next.js";
|
|
3
3
|
export type BuildOptions = ReturnType<typeof normalizeOptions>;
|
|
4
|
-
export declare function normalizeOptions(config: OpenNextConfig
|
|
5
|
-
|
|
6
|
-
nextVersion: string;
|
|
4
|
+
export declare function normalizeOptions(config: OpenNextConfig): {
|
|
5
|
+
appBuildOutputPath: string;
|
|
7
6
|
appPackageJsonPath: string;
|
|
8
7
|
appPath: string;
|
|
9
|
-
appBuildOutputPath: string;
|
|
10
8
|
appPublicPath: string;
|
|
11
|
-
|
|
12
|
-
tempDir: string;
|
|
9
|
+
config: OpenNextConfig;
|
|
13
10
|
debug: boolean;
|
|
14
11
|
monorepoRoot: string;
|
|
12
|
+
nextVersion: string;
|
|
13
|
+
openNextVersion: string;
|
|
14
|
+
outputDir: string;
|
|
15
|
+
packager: "npm" | "yarn" | "pnpm" | "bun";
|
|
16
|
+
tempDir: string;
|
|
15
17
|
};
|
|
16
18
|
export declare function esbuildSync(esbuildOptions: ESBuildOptions, options: BuildOptions): void;
|
|
17
19
|
export declare function esbuildAsync(esbuildOptions: ESBuildOptions, options: BuildOptions): Promise<void>;
|
package/dist/build/helper.js
CHANGED
|
@@ -6,10 +6,11 @@ import { build as buildAsync, buildSync, } from "esbuild";
|
|
|
6
6
|
import logger from "../logger.js";
|
|
7
7
|
const require = topLevelCreateRequire(import.meta.url);
|
|
8
8
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
9
|
-
export function normalizeOptions(config
|
|
9
|
+
export function normalizeOptions(config) {
|
|
10
10
|
const appPath = path.join(process.cwd(), config.appPath || ".");
|
|
11
11
|
const buildOutputPath = path.join(process.cwd(), config.buildOutputPath || ".");
|
|
12
12
|
const outputDir = path.join(buildOutputPath, ".open-next");
|
|
13
|
+
const { root: monorepoRoot, packager } = findMonorepoRoot(path.join(process.cwd(), config.appPath || "."));
|
|
13
14
|
let appPackageJsonPath;
|
|
14
15
|
if (config.packageJsonPath) {
|
|
15
16
|
const _pkgPath = path.join(process.cwd(), config.packageJsonPath);
|
|
@@ -18,21 +19,45 @@ export function normalizeOptions(config, root) {
|
|
|
18
19
|
: path.join(_pkgPath, "./package.json");
|
|
19
20
|
}
|
|
20
21
|
else {
|
|
21
|
-
appPackageJsonPath = findNextPackageJsonPath(appPath,
|
|
22
|
+
appPackageJsonPath = findNextPackageJsonPath(appPath, monorepoRoot);
|
|
22
23
|
}
|
|
23
24
|
return {
|
|
24
|
-
|
|
25
|
-
nextVersion: getNextVersion(appPath),
|
|
25
|
+
appBuildOutputPath: buildOutputPath,
|
|
26
26
|
appPackageJsonPath,
|
|
27
27
|
appPath,
|
|
28
|
-
appBuildOutputPath: buildOutputPath,
|
|
29
28
|
appPublicPath: path.join(appPath, "public"),
|
|
29
|
+
config,
|
|
30
|
+
debug: Boolean(process.env.OPEN_NEXT_DEBUG) ?? false,
|
|
31
|
+
monorepoRoot,
|
|
32
|
+
nextVersion: getNextVersion(appPath),
|
|
33
|
+
openNextVersion: getOpenNextVersion(),
|
|
30
34
|
outputDir,
|
|
35
|
+
packager,
|
|
31
36
|
tempDir: path.join(outputDir, ".build"),
|
|
32
|
-
debug: Boolean(process.env.OPEN_NEXT_DEBUG) ?? false,
|
|
33
|
-
monorepoRoot: root,
|
|
34
37
|
};
|
|
35
38
|
}
|
|
39
|
+
function findMonorepoRoot(appPath) {
|
|
40
|
+
let currentPath = appPath;
|
|
41
|
+
while (currentPath !== "/") {
|
|
42
|
+
const found = [
|
|
43
|
+
{ file: "package-lock.json", packager: "npm" },
|
|
44
|
+
{ file: "yarn.lock", packager: "yarn" },
|
|
45
|
+
{ file: "pnpm-lock.yaml", packager: "pnpm" },
|
|
46
|
+
{ file: "bun.lockb", packager: "bun" },
|
|
47
|
+
].find((f) => fs.existsSync(path.join(currentPath, f.file)));
|
|
48
|
+
if (found) {
|
|
49
|
+
if (currentPath !== appPath) {
|
|
50
|
+
logger.info("Monorepo detected at", currentPath);
|
|
51
|
+
}
|
|
52
|
+
return { root: currentPath, packager: found.packager };
|
|
53
|
+
}
|
|
54
|
+
currentPath = path.dirname(currentPath);
|
|
55
|
+
}
|
|
56
|
+
// note: a lock file (package-lock.json, yarn.lock, or pnpm-lock.yaml) is
|
|
57
|
+
// not found in the app's directory or any of its parent directories.
|
|
58
|
+
// We are going to assume that the app is not part of a monorepo.
|
|
59
|
+
return { root: appPath, packager: "npm" };
|
|
60
|
+
}
|
|
36
61
|
function findNextPackageJsonPath(appPath, root) {
|
|
37
62
|
// This is needed for the case where the app is a single-version monorepo and the package.json is in the root of the monorepo
|
|
38
63
|
return fs.existsSync(path.join(appPath, "./package.json"))
|
package/dist/build.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { BuildOptions } from "./build/helper.js";
|
|
1
2
|
export type PublicFiles = {
|
|
2
3
|
files: string[];
|
|
3
4
|
};
|
|
4
5
|
export declare function build(openNextConfigPath?: string, nodeExternals?: string): Promise<void>;
|
|
5
6
|
/***************************/
|
|
6
7
|
/***************************/
|
|
7
|
-
export declare function compileCache(format?: "cjs" | "esm"): string;
|
|
8
|
+
export declare function compileCache(options: BuildOptions, format?: "cjs" | "esm"): string;
|
package/dist/build.js
CHANGED
|
@@ -16,8 +16,6 @@ import { openNextReplacementPlugin } from "./plugins/replacement.js";
|
|
|
16
16
|
import { openNextResolvePlugin } from "./plugins/resolve.js";
|
|
17
17
|
const require = topLevelCreateRequire(import.meta.url);
|
|
18
18
|
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
|
|
19
|
-
let options;
|
|
20
|
-
let config;
|
|
21
19
|
export async function build(openNextConfigPath, nodeExternals) {
|
|
22
20
|
showWindowsWarning();
|
|
23
21
|
// Load open-next.config.ts
|
|
@@ -26,39 +24,38 @@ export async function build(openNextConfigPath, nodeExternals) {
|
|
|
26
24
|
// On Windows, we need to use file:// protocol to load the config file using import()
|
|
27
25
|
if (process.platform === "win32")
|
|
28
26
|
configPath = `file://${configPath}`;
|
|
29
|
-
config = (await import(configPath)).default;
|
|
27
|
+
const config = (await import(configPath)).default;
|
|
30
28
|
if (!config || !config.default) {
|
|
31
29
|
logger.error(`config.default cannot be empty, it should be at least {}, see more info here: https://open-next.js.org/config#configuration-file`);
|
|
32
30
|
process.exit(1);
|
|
33
31
|
}
|
|
34
32
|
validateConfig(config);
|
|
35
33
|
compileOpenNextConfigEdge(tempDir, config, openNextConfigPath);
|
|
36
|
-
const { root: monorepoRoot, packager } = findMonorepoRoot(path.join(process.cwd(), config.appPath || "."));
|
|
37
34
|
// Initialize options
|
|
38
|
-
options = normalizeOptions(config
|
|
35
|
+
const options = normalizeOptions(config);
|
|
39
36
|
logger.setLevel(options.debug ? "debug" : "info");
|
|
40
37
|
// Pre-build validation
|
|
41
|
-
checkRunningInsideNextjsApp();
|
|
42
|
-
printNextjsVersion();
|
|
43
|
-
printOpenNextVersion();
|
|
38
|
+
checkRunningInsideNextjsApp(options);
|
|
39
|
+
printNextjsVersion(options);
|
|
40
|
+
printOpenNextVersion(options);
|
|
44
41
|
// Build Next.js app
|
|
45
42
|
printHeader("Building Next.js app");
|
|
46
|
-
setStandaloneBuildMode(
|
|
47
|
-
buildNextjsApp(
|
|
43
|
+
setStandaloneBuildMode(options);
|
|
44
|
+
buildNextjsApp(options);
|
|
48
45
|
// Generate deployable bundle
|
|
49
46
|
printHeader("Generating bundle");
|
|
50
|
-
initOutputDir(tempDir);
|
|
47
|
+
initOutputDir(tempDir, options);
|
|
51
48
|
// Compile cache.ts
|
|
52
|
-
compileCache();
|
|
49
|
+
compileCache(options);
|
|
53
50
|
// Compile middleware
|
|
54
|
-
await createMiddleware();
|
|
55
|
-
createStaticAssets();
|
|
56
|
-
await createCacheAssets(
|
|
57
|
-
await createServerBundle(
|
|
58
|
-
await createRevalidationBundle(
|
|
59
|
-
await createImageOptimizationBundle(
|
|
60
|
-
await createWarmerBundle(
|
|
61
|
-
await generateOutput(options
|
|
51
|
+
await createMiddleware(options);
|
|
52
|
+
createStaticAssets(options);
|
|
53
|
+
await createCacheAssets(options);
|
|
54
|
+
await createServerBundle(options);
|
|
55
|
+
await createRevalidationBundle(options);
|
|
56
|
+
await createImageOptimizationBundle(options);
|
|
57
|
+
await createWarmerBundle(options);
|
|
58
|
+
await generateOutput(options);
|
|
62
59
|
logger.info("OpenNext build complete.");
|
|
63
60
|
}
|
|
64
61
|
function showWindowsWarning() {
|
|
@@ -75,7 +72,7 @@ function initTempDir() {
|
|
|
75
72
|
fs.mkdirSync(tempDir, { recursive: true });
|
|
76
73
|
return tempDir;
|
|
77
74
|
}
|
|
78
|
-
function checkRunningInsideNextjsApp() {
|
|
75
|
+
function checkRunningInsideNextjsApp(options) {
|
|
79
76
|
const { appPath } = options;
|
|
80
77
|
const extension = ["js", "cjs", "mjs", "ts"].find((ext) => fs.existsSync(path.join(appPath, `next.config.${ext}`)));
|
|
81
78
|
if (!extension) {
|
|
@@ -83,43 +80,21 @@ function checkRunningInsideNextjsApp() {
|
|
|
83
80
|
process.exit(1);
|
|
84
81
|
}
|
|
85
82
|
}
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
while (currentPath !== "/") {
|
|
89
|
-
const found = [
|
|
90
|
-
{ file: "package-lock.json", packager: "npm" },
|
|
91
|
-
{ file: "yarn.lock", packager: "yarn" },
|
|
92
|
-
{ file: "pnpm-lock.yaml", packager: "pnpm" },
|
|
93
|
-
{ file: "bun.lockb", packager: "bun" },
|
|
94
|
-
].find((f) => fs.existsSync(path.join(currentPath, f.file)));
|
|
95
|
-
if (found) {
|
|
96
|
-
if (currentPath !== appPath) {
|
|
97
|
-
logger.info("Monorepo detected at", currentPath);
|
|
98
|
-
}
|
|
99
|
-
return { root: currentPath, packager: found.packager };
|
|
100
|
-
}
|
|
101
|
-
currentPath = path.dirname(currentPath);
|
|
102
|
-
}
|
|
103
|
-
// note: a lock file (package-lock.json, yarn.lock, or pnpm-lock.yaml) is
|
|
104
|
-
// not found in the app's directory or any of its parent directories.
|
|
105
|
-
// We are going to assume that the app is not part of a monorepo.
|
|
106
|
-
return { root: appPath, packager: "npm" };
|
|
107
|
-
}
|
|
108
|
-
function setStandaloneBuildMode(monorepoRoot) {
|
|
109
|
-
// Equivalent to setting `target: "standalone"` in next.config.js
|
|
83
|
+
function setStandaloneBuildMode(options) {
|
|
84
|
+
// Equivalent to setting `output: "standalone"` in next.config.js
|
|
110
85
|
process.env.NEXT_PRIVATE_STANDALONE = "true";
|
|
111
86
|
// Equivalent to setting `experimental.outputFileTracingRoot` in next.config.js
|
|
112
|
-
process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT = monorepoRoot;
|
|
87
|
+
process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT = options.monorepoRoot;
|
|
113
88
|
}
|
|
114
|
-
function buildNextjsApp(
|
|
115
|
-
const {
|
|
89
|
+
function buildNextjsApp(options) {
|
|
90
|
+
const { config, packager } = options;
|
|
116
91
|
const command = config.buildCommand ??
|
|
117
92
|
(["bun", "npm"].includes(packager)
|
|
118
93
|
? `${packager} run build`
|
|
119
94
|
: `${packager} build`);
|
|
120
95
|
cp.execSync(command, {
|
|
121
96
|
stdio: "inherit",
|
|
122
|
-
cwd: path.dirname(appPackageJsonPath),
|
|
97
|
+
cwd: path.dirname(options.appPackageJsonPath),
|
|
123
98
|
});
|
|
124
99
|
}
|
|
125
100
|
function printHeader(header) {
|
|
@@ -132,34 +107,32 @@ function printHeader(header) {
|
|
|
132
107
|
"",
|
|
133
108
|
].join("\n"));
|
|
134
109
|
}
|
|
135
|
-
function printNextjsVersion() {
|
|
136
|
-
|
|
137
|
-
logger.info(`Next.js version : ${nextVersion}`);
|
|
110
|
+
function printNextjsVersion(options) {
|
|
111
|
+
logger.info(`Next.js version : ${options.nextVersion}`);
|
|
138
112
|
}
|
|
139
|
-
function printOpenNextVersion() {
|
|
140
|
-
|
|
141
|
-
logger.info(`OpenNext v${openNextVersion}`);
|
|
113
|
+
function printOpenNextVersion(options) {
|
|
114
|
+
logger.info(`OpenNext v${options.openNextVersion}`);
|
|
142
115
|
}
|
|
143
|
-
function initOutputDir(
|
|
116
|
+
function initOutputDir(srcTempDir, options) {
|
|
144
117
|
// We need to get the build relative to the cwd to find the compiled config
|
|
145
118
|
// This is needed for the case where the app is a single-version monorepo and the package.json is in the root of the monorepo
|
|
146
119
|
// where the build is in the app directory, but the compiled config is in the root of the monorepo.
|
|
147
|
-
const
|
|
148
|
-
const openNextConfig = readFileSync(path.join(tempDir, "open-next.config.mjs"), "utf8");
|
|
120
|
+
const openNextConfig = readFileSync(path.join(srcTempDir, "open-next.config.mjs"), "utf8");
|
|
149
121
|
let openNextConfigEdge = null;
|
|
150
|
-
if (fs.existsSync(path.join(
|
|
151
|
-
openNextConfigEdge = readFileSync(path.join(
|
|
122
|
+
if (fs.existsSync(path.join(srcTempDir, "open-next.config.edge.mjs"))) {
|
|
123
|
+
openNextConfigEdge = readFileSync(path.join(srcTempDir, "open-next.config.edge.mjs"), "utf8");
|
|
152
124
|
}
|
|
153
|
-
fs.rmSync(outputDir, { recursive: true, force: true });
|
|
154
|
-
|
|
155
|
-
fs.
|
|
125
|
+
fs.rmSync(options.outputDir, { recursive: true, force: true });
|
|
126
|
+
const destTempDir = options.tempDir;
|
|
127
|
+
fs.mkdirSync(destTempDir, { recursive: true });
|
|
128
|
+
fs.writeFileSync(path.join(destTempDir, "open-next.config.mjs"), openNextConfig);
|
|
156
129
|
if (openNextConfigEdge) {
|
|
157
|
-
fs.writeFileSync(path.join(
|
|
130
|
+
fs.writeFileSync(path.join(destTempDir, "open-next.config.edge.mjs"), openNextConfigEdge);
|
|
158
131
|
}
|
|
159
132
|
}
|
|
160
|
-
async function createWarmerBundle(
|
|
133
|
+
async function createWarmerBundle(options) {
|
|
161
134
|
logger.info(`Bundling warmer function...`);
|
|
162
|
-
const { outputDir } = options;
|
|
135
|
+
const { config, outputDir } = options;
|
|
163
136
|
// Create output folder
|
|
164
137
|
const outputPath = path.join(outputDir, "warmer-function");
|
|
165
138
|
fs.mkdirSync(outputPath, { recursive: true });
|
|
@@ -192,9 +165,9 @@ async function createWarmerBundle(config) {
|
|
|
192
165
|
},
|
|
193
166
|
}, options);
|
|
194
167
|
}
|
|
195
|
-
async function createRevalidationBundle(
|
|
168
|
+
async function createRevalidationBundle(options) {
|
|
196
169
|
logger.info(`Bundling revalidation function...`);
|
|
197
|
-
const { appBuildOutputPath, outputDir } = options;
|
|
170
|
+
const { appBuildOutputPath, config, outputDir } = options;
|
|
198
171
|
// Create output folder
|
|
199
172
|
const outputPath = path.join(outputDir, "revalidation-function");
|
|
200
173
|
fs.mkdirSync(outputPath, { recursive: true });
|
|
@@ -218,9 +191,9 @@ async function createRevalidationBundle(config) {
|
|
|
218
191
|
// Copy over .next/prerender-manifest.json file
|
|
219
192
|
fs.copyFileSync(path.join(appBuildOutputPath, ".next", "prerender-manifest.json"), path.join(outputPath, "prerender-manifest.json"));
|
|
220
193
|
}
|
|
221
|
-
async function createImageOptimizationBundle(
|
|
194
|
+
async function createImageOptimizationBundle(options) {
|
|
222
195
|
logger.info(`Bundling image optimization function...`);
|
|
223
|
-
const { appPath, appBuildOutputPath, outputDir } = options;
|
|
196
|
+
const { appPath, appBuildOutputPath, config, outputDir } = options;
|
|
224
197
|
// Create output folder
|
|
225
198
|
const outputPath = path.join(outputDir, "image-optimization-function");
|
|
226
199
|
fs.mkdirSync(outputPath, { recursive: true });
|
|
@@ -306,7 +279,7 @@ async function createImageOptimizationBundle(config) {
|
|
|
306
279
|
logger.error("Failed to install sharp.");
|
|
307
280
|
}
|
|
308
281
|
}
|
|
309
|
-
function createStaticAssets() {
|
|
282
|
+
function createStaticAssets(options) {
|
|
310
283
|
logger.info(`Bundling static assets...`);
|
|
311
284
|
const { appBuildOutputPath, appPublicPath, outputDir, appPath } = options;
|
|
312
285
|
// Create output folder
|
|
@@ -331,12 +304,13 @@ function createStaticAssets() {
|
|
|
331
304
|
fs.copyFileSync(faviconPath, path.join(outputPath, "favicon.ico"));
|
|
332
305
|
}
|
|
333
306
|
}
|
|
334
|
-
async function createCacheAssets(
|
|
307
|
+
async function createCacheAssets(options) {
|
|
308
|
+
const { config } = options;
|
|
335
309
|
if (config.dangerous?.disableIncrementalCache)
|
|
336
310
|
return;
|
|
337
311
|
logger.info(`Bundling cache assets...`);
|
|
338
312
|
const { appBuildOutputPath, outputDir } = options;
|
|
339
|
-
const packagePath = path.relative(monorepoRoot, appBuildOutputPath);
|
|
313
|
+
const packagePath = path.relative(options.monorepoRoot, appBuildOutputPath);
|
|
340
314
|
const buildId = getBuildId(appBuildOutputPath);
|
|
341
315
|
// Copy pages to cache folder
|
|
342
316
|
const dotNextPath = path.join(appBuildOutputPath, ".next/standalone", packagePath);
|
|
@@ -354,7 +328,11 @@ async function createCacheAssets(monorepoRoot) {
|
|
|
354
328
|
const cacheFilesPath = {};
|
|
355
329
|
traverseFiles(outputPath, () => true, (filepath) => {
|
|
356
330
|
const ext = path.extname(filepath);
|
|
357
|
-
|
|
331
|
+
let newFilePath = ext !== "" ? filepath.replace(ext, ".cache") : `${filepath}.cache`;
|
|
332
|
+
// Handle prefetch cache files for partial prerendering
|
|
333
|
+
if (newFilePath.endsWith(".prefetch.cache")) {
|
|
334
|
+
newFilePath = newFilePath.replace(".prefetch.cache", ".cache");
|
|
335
|
+
}
|
|
358
336
|
switch (ext) {
|
|
359
337
|
case ".meta":
|
|
360
338
|
case ".html":
|
|
@@ -470,7 +448,8 @@ async function createCacheAssets(monorepoRoot) {
|
|
|
470
448
|
/***************************/
|
|
471
449
|
/* Server Helper Functions */
|
|
472
450
|
/***************************/
|
|
473
|
-
export function compileCache(format = "cjs") {
|
|
451
|
+
export function compileCache(options, format = "cjs") {
|
|
452
|
+
const { config } = options;
|
|
474
453
|
const ext = format === "cjs" ? "cjs" : "mjs";
|
|
475
454
|
const outfile = path.join(options.outputDir, ".build", `cache.${ext}`);
|
|
476
455
|
const isAfter15 = compareSemver(options.nextVersion, "15.0.0") >= 0;
|
|
@@ -490,9 +469,9 @@ export function compileCache(format = "cjs") {
|
|
|
490
469
|
}, options);
|
|
491
470
|
return outfile;
|
|
492
471
|
}
|
|
493
|
-
async function createMiddleware() {
|
|
472
|
+
async function createMiddleware(options) {
|
|
494
473
|
console.info(`Bundling middleware function...`);
|
|
495
|
-
const { appBuildOutputPath, outputDir } = options;
|
|
474
|
+
const { appBuildOutputPath, config, outputDir } = options;
|
|
496
475
|
// Get middleware manifest
|
|
497
476
|
const middlewareManifest = JSON.parse(readFileSync(path.join(appBuildOutputPath, ".next/server/middleware-manifest.json"), "utf8"));
|
|
498
477
|
const entry = middlewareManifest.middleware["/"];
|
|
@@ -75,6 +75,7 @@ async function convertFromCloudFrontRequestEvent(event) {
|
|
|
75
75
|
function convertToCloudfrontHeaders(headers, directResponse) {
|
|
76
76
|
const cloudfrontHeaders = {};
|
|
77
77
|
Object.entries(headers)
|
|
78
|
+
.map(([key, value]) => [key.toLowerCase(), value])
|
|
78
79
|
.filter(([key]) => !CloudFrontBlacklistedHeaders.some((header) => typeof header === "string" ? header === key : header.test(key)) &&
|
|
79
80
|
// Only remove read-only headers when directly responding in lambda@edge
|
|
80
81
|
(directResponse ? !cloudfrontReadOnlyHeaders.includes(key) : true))
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Copied from Next.js source code
|
|
2
2
|
// https://github.com/vercel/next.js/blob/canary/packages/next/src/server/accept-header.ts
|
|
3
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
3
4
|
function parse(raw, preferences, options) {
|
|
4
5
|
const lowers = new Map();
|
|
5
6
|
const header = raw.replace(/[ \t]/g, "");
|
|
@@ -5,7 +5,7 @@ import { addNextConfigHeaders, fixDataPage, handleFallbackFalse, handleRedirects
|
|
|
5
5
|
import { handleMiddleware } from "./routing/middleware";
|
|
6
6
|
// Add the locale prefix to the regex so we correctly match the rawPath
|
|
7
7
|
const optionalLocalePrefixRegex = !!RoutesManifest.locales.length
|
|
8
|
-
? `^/(?:${RoutesManifest.locales.map((locale) =>
|
|
8
|
+
? `^/(?:${RoutesManifest.locales.map((locale) => locale + "/?").join("|")})?`
|
|
9
9
|
: "^/";
|
|
10
10
|
// Add the basepath prefix to the regex so we correctly match the rawPath
|
|
11
11
|
const optionalBasepathPrefixRegex = !!RoutesManifest.basePath
|
package/dist/index.js
CHANGED
package/dist/minimize-js.js
CHANGED
package/dist/plugins/edge.js
CHANGED
|
@@ -55,7 +55,6 @@ const handler = async (handler, converter) => awslambda.streamifyResponse(async
|
|
|
55
55
|
}
|
|
56
56
|
const streamCreator = {
|
|
57
57
|
writeHeaders: (_prelude) => {
|
|
58
|
-
_prelude.headers["content-encoding"] = contentEncoding;
|
|
59
58
|
responseStream.setContentType("application/vnd.awslambda.http-integration-response");
|
|
60
59
|
_prelude.headers["content-encoding"] = contentEncoding;
|
|
61
60
|
const prelude = JSON.stringify(_prelude);
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"access": "public"
|
|
4
4
|
},
|
|
5
5
|
"name": "@opennextjs/aws",
|
|
6
|
-
"version": "3.1.
|
|
6
|
+
"version": "3.1.5",
|
|
7
7
|
"bin": {
|
|
8
8
|
"open-next": "./dist/index.js",
|
|
9
9
|
"@opennextjs/aws": "./dist/index.js"
|
|
@@ -53,11 +53,12 @@
|
|
|
53
53
|
"typescript": "^4.9.3"
|
|
54
54
|
},
|
|
55
55
|
"bugs": {
|
|
56
|
-
"url": "https://github.com/
|
|
56
|
+
"url": "https://github.com/opennextjs/opennextjs-aws/issues"
|
|
57
57
|
},
|
|
58
58
|
"repository": {
|
|
59
59
|
"type": "git",
|
|
60
|
-
"url": "
|
|
60
|
+
"url": "https://github.com/opennextjs/opennextjs-aws",
|
|
61
|
+
"directory": "packages/open-next"
|
|
61
62
|
},
|
|
62
63
|
"scripts": {
|
|
63
64
|
"build": "tsc && tsc-alias",
|