Skip to content

Commit e0ed614

Browse files
authored
Split build.ts (#562)
1 parent 5c6bd72 commit e0ed614

14 files changed

+856
-752
lines changed

packages/open-next/src/build.ts

Lines changed: 27 additions & 674 deletions
Large diffs are not rendered by default.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import cp from "node:child_process";
2+
import path from "node:path";
3+
4+
import * as buildHelper from "./helper.js";
5+
6+
export function setStandaloneBuildMode(options: buildHelper.BuildOptions) {
7+
// Equivalent to setting `output: "standalone"` in next.config.js
8+
process.env.NEXT_PRIVATE_STANDALONE = "true";
9+
// Equivalent to setting `experimental.outputFileTracingRoot` in next.config.js
10+
process.env.NEXT_PRIVATE_OUTPUT_TRACE_ROOT = options.monorepoRoot;
11+
}
12+
13+
export function buildNextjsApp(options: buildHelper.BuildOptions) {
14+
const { config, packager } = options;
15+
const command =
16+
config.buildCommand ??
17+
(["bun", "npm"].includes(packager)
18+
? `${packager} run build`
19+
: `${packager} build`);
20+
cp.execSync(command, {
21+
stdio: "inherit",
22+
cwd: path.dirname(options.appPackageJsonPath),
23+
});
24+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createRequire as topLevelCreateRequire } from "node:module";
1+
import { createRequire } from "node:module";
22

33
import { build } from "esbuild";
44
import path from "path";
@@ -43,7 +43,7 @@ const externals = [
4343
];
4444

4545
export async function bundleNextServer(outputDir: string, appPath: string) {
46-
const require = topLevelCreateRequire(`${appPath}/package.json`);
46+
const require = createRequire(`${appPath}/package.json`);
4747
const entrypoint = require.resolve("next/dist/esm/server/next-server.js");
4848

4949
await build({
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import path from "node:path";
2+
3+
import * as buildHelper from "./helper.js";
4+
5+
/**
6+
* Compiles the cache adapter.
7+
*
8+
* @param options Build options.
9+
* @param format Output format.
10+
* @returns The path to the compiled file.
11+
*/
12+
export function compileCache(
13+
options: buildHelper.BuildOptions,
14+
format: "cjs" | "esm" = "cjs",
15+
) {
16+
const { config } = options;
17+
const ext = format === "cjs" ? "cjs" : "mjs";
18+
const outFile = path.join(options.buildDir, `cache.${ext}`);
19+
20+
const isAfter15 =
21+
buildHelper.compareSemver(options.nextVersion, "15.0.0") >= 0;
22+
23+
buildHelper.esbuildSync(
24+
{
25+
external: ["next", "styled-jsx", "react", "@aws-sdk/*"],
26+
entryPoints: [path.join(options.openNextDistDir, "adapters", "cache.js")],
27+
outfile: outFile,
28+
target: ["node18"],
29+
format,
30+
banner: {
31+
js: [
32+
`globalThis.disableIncrementalCache = ${
33+
config.dangerous?.disableIncrementalCache ?? false
34+
};`,
35+
`globalThis.disableDynamoDBCache = ${
36+
config.dangerous?.disableTagCache ?? false
37+
};`,
38+
`globalThis.isNextAfter15 = ${isAfter15};`,
39+
].join(""),
40+
},
41+
},
42+
options,
43+
);
44+
return outFile;
45+
}
Lines changed: 74 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,74 @@
11
import fs from "node:fs";
2+
import os from "node:os";
23
import path from "node:path";
34

45
import { buildSync } from "esbuild";
56
import { OpenNextConfig } from "types/open-next.js";
67

78
import logger from "../logger.js";
9+
import { validateConfig } from "./validateConfig.js";
810

9-
export function compileOpenNextConfigNode(
10-
outputDir: string,
11+
/**
12+
* Compiles the OpenNext configuration.
13+
*
14+
* The configuration is always compiled for Node.js and for the edge only if needed.
15+
*
16+
* @param baseDir Directory where to look for the configuration.
17+
* @param openNextConfigPath Override the default configuration when provided. Relative to baseDir.
18+
* @param nodeExternals Externals for the Node.js compilation.
19+
* @return The configuration and the build directory.
20+
*/
21+
export async function compileOpenNextConfig(
22+
baseDir: string,
1123
openNextConfigPath?: string,
1224
nodeExternals?: string,
1325
) {
1426
const sourcePath = path.join(
15-
process.cwd(),
27+
baseDir,
1628
openNextConfigPath ?? "open-next.config.ts",
1729
);
30+
31+
const buildDir = fs.mkdtempSync(path.join(os.tmpdir(), "open-next-tmp"));
32+
let configPath = compileOpenNextConfigNode(
33+
sourcePath,
34+
buildDir,
35+
nodeExternals ? nodeExternals.split(",") : [],
36+
);
37+
38+
// On Windows, we need to use file:// protocol to load the config file using import()
39+
if (process.platform === "win32") configPath = `file://${configPath}`;
40+
const config = (await import(configPath)).default as OpenNextConfig;
41+
if (!config || !config.default) {
42+
logger.error(
43+
`config.default cannot be empty, it should be at least {}, see more info here: https://open-next.js.org/config#configuration-file`,
44+
);
45+
process.exit(1);
46+
}
47+
48+
validateConfig(config);
49+
50+
// We need to check if the config uses the edge runtime at any point
51+
// If it does, we need to compile it with the edge runtime
52+
const usesEdgeRuntime =
53+
config.middleware?.external ||
54+
Object.values(config.functions || {}).some((fn) => fn.runtime === "edge");
55+
if (!usesEdgeRuntime) {
56+
logger.debug(
57+
"No edge runtime found in the open-next.config.ts. Using default config.",
58+
);
59+
//Nothing to do here
60+
} else {
61+
compileOpenNextConfigEdge(sourcePath, buildDir, config.edgeExternals ?? []);
62+
}
63+
64+
return { config, buildDir };
65+
}
66+
67+
export function compileOpenNextConfigNode(
68+
sourcePath: string,
69+
outputDir: string,
70+
externals: string[],
71+
) {
1872
const outputPath = path.join(outputDir, "open-next.config.mjs");
1973

2074
//Check if open-next.config.ts exists
@@ -29,7 +83,7 @@ export function compileOpenNextConfigNode(
2983
bundle: true,
3084
format: "esm",
3185
target: ["node18"],
32-
external: nodeExternals ? nodeExternals.split(",") : [],
86+
external: externals,
3387
platform: "node",
3488
banner: {
3589
js: [
@@ -46,38 +100,22 @@ export function compileOpenNextConfigNode(
46100
}
47101

48102
export function compileOpenNextConfigEdge(
49-
tempDir: string,
50-
config: OpenNextConfig,
51-
openNextConfigPath?: string,
103+
sourcePath: string,
104+
outputDir: string,
105+
externals: string[],
52106
) {
53-
const sourcePath = path.join(
54-
process.cwd(),
55-
openNextConfigPath ?? "open-next.config.ts",
56-
);
57-
const outputPath = path.join(tempDir, "open-next.config.edge.mjs");
107+
const outputPath = path.join(outputDir, "open-next.config.edge.mjs");
58108

59-
// We need to check if the config uses the edge runtime at any point
60-
// If it does, we need to compile it with the edge runtime
61-
const usesEdgeRuntime =
62-
config.middleware?.external ||
63-
Object.values(config.functions || {}).some((fn) => fn.runtime === "edge");
64-
if (!usesEdgeRuntime) {
65-
logger.debug(
66-
"No edge runtime found in the open-next.config.ts. Using default config.",
67-
);
68-
//Nothing to do here
69-
} else {
70-
logger.info("Compiling open-next.config.ts for edge runtime.", outputPath);
71-
buildSync({
72-
entryPoints: [sourcePath],
73-
outfile: outputPath,
74-
bundle: true,
75-
format: "esm",
76-
target: ["es2020"],
77-
conditions: ["worker", "browser"],
78-
platform: "browser",
79-
external: config.edgeExternals ?? [],
80-
});
81-
logger.info("Compiled open-next.config.ts for edge runtime.");
82-
}
109+
logger.info("Compiling open-next.config.ts for edge runtime.", outputPath);
110+
buildSync({
111+
entryPoints: [sourcePath],
112+
outfile: outputPath,
113+
bundle: true,
114+
format: "esm",
115+
target: ["es2020"],
116+
conditions: ["worker", "browser"],
117+
platform: "browser",
118+
external: externals,
119+
});
120+
logger.info("Compiled open-next.config.ts for edge runtime.");
83121
}

0 commit comments

Comments
 (0)