Skip to content

Commit 2df80cc

Browse files
authored
Support invoking OpenNext programmatically (#135)
* Support invoking OpenNext programmatically * Sync
1 parent 194b389 commit 2df80cc

File tree

2 files changed

+55
-14
lines changed

2 files changed

+55
-14
lines changed

.changeset/green-bugs-bathe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"open-next": minor
3+
---
4+
5+
Support invoking OpenNext programmatically

packages/open-next/src/build.ts

Lines changed: 50 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,27 @@ import url from "node:url";
33
import path from "node:path";
44
import cp from "node:child_process";
55
import { minifyAll } from "./minimize-js.js";
6-
import { buildSync, BuildOptions } from "esbuild";
7-
import { exit } from "node:process";
6+
import { buildSync, BuildOptions as ESBuildOptions } from "esbuild";
87
import { createRequire as topLevelCreateRequire } from "node:module";
98

9+
interface BuildOptions {
10+
minify?: boolean;
11+
debug?: boolean;
12+
appPath?: string;
13+
}
14+
1015
const require = topLevelCreateRequire(import.meta.url);
1116
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
12-
const appPath = process.cwd();
13-
const appPublicPath = path.join(appPath, "public");
14-
const outputDir = ".open-next";
15-
const tempDir = path.join(outputDir, ".build");
17+
let options: ReturnType<typeof normalizeOptions>;
1618

1719
export type PublicFiles = {
1820
files: string[];
1921
};
2022

21-
export async function build() {
23+
export async function build(opts: BuildOptions = {}) {
24+
// Initialize options
25+
options = normalizeOptions(opts);
26+
2227
// Pre-build validation
2328
printNextjsVersion();
2429
printOpenNextVersion();
@@ -37,12 +42,26 @@ export async function build() {
3742
createServerBundle(monorepoRoot);
3843
createImageOptimizationBundle();
3944
createWarmerBundle();
40-
if (process.env.OPEN_NEXT_MINIFY) {
45+
if (options.minify) {
4146
await minifyServerBundle();
4247
}
4348
}
4449

50+
function normalizeOptions(opts: BuildOptions) {
51+
const appPath = opts.appPath ?? process.cwd();
52+
const outputDir = ".open-next";
53+
return {
54+
appPath,
55+
appPublicPath: path.join(appPath, "public"),
56+
outputDir,
57+
tempDir: path.join(outputDir, ".build"),
58+
minify: opts.minify ?? Boolean(process.env.OPEN_NEXT_MINIFY) ?? false,
59+
debug: opts.debug ?? Boolean(process.env.OPEN_NEXT_DEBUG) ?? false,
60+
};
61+
}
62+
4563
function checkRunningInsideNextjsApp() {
64+
const { appPath } = options;
4665
const extension = ["js", "cjs", "mjs"].find((ext) =>
4766
fs.existsSync(path.join(appPath, `next.config.${ext}`))
4867
);
@@ -55,6 +74,7 @@ function checkRunningInsideNextjsApp() {
5574
}
5675

5776
function findMonorepoRoot() {
77+
const { appPath } = options;
5878
let currentPath = appPath;
5979
while (currentPath !== "/") {
6080
const found = [
@@ -86,6 +106,7 @@ function setStandaloneBuildMode(monorepoRoot: string) {
86106
}
87107

88108
function buildNextjsApp(packager: "npm" | "yarn" | "pnpm") {
109+
const { appPath } = options;
89110
const result = cp.spawnSync(
90111
packager,
91112
packager === "npm" ? ["run", "build"] : ["build"],
@@ -114,6 +135,7 @@ function printHeader(header: string) {
114135
}
115136

116137
function printNextjsVersion() {
138+
const { appPath } = options;
117139
cp.spawnSync(
118140
"node",
119141
[
@@ -167,11 +189,13 @@ function injectMiddlewareGeolocation(outputPath: string, packagePath: string) {
167189
}
168190

169191
function initOutputDir() {
192+
const { outputDir, tempDir } = options;
170193
fs.rmSync(outputDir, { recursive: true, force: true });
171194
fs.mkdirSync(tempDir, { recursive: true });
172195
}
173196

174197
function listPublicFiles() {
198+
const { appPublicPath } = options;
175199
const result: PublicFiles = { files: [] };
176200

177201
if (!fs.existsSync(appPublicPath)) {
@@ -197,6 +221,8 @@ function listPublicFiles() {
197221
function createServerBundle(monorepoRoot: string) {
198222
console.info(`Bundling server function...`);
199223

224+
const { appPath, outputDir } = options;
225+
200226
// Create output folder
201227
const outputPath = path.join(outputDir, "server-function");
202228
fs.mkdirSync(outputPath, { recursive: true });
@@ -267,6 +293,8 @@ function createServerBundle(monorepoRoot: string) {
267293
function createWarmerBundle() {
268294
console.info(`Bundling warmer function...`);
269295

296+
const { outputDir } = options;
297+
270298
// Create output folder
271299
const outputPath = path.join(outputDir, "warmer-function");
272300
fs.mkdirSync(outputPath, { recursive: true });
@@ -292,6 +320,7 @@ function createWarmerBundle() {
292320

293321
async function minifyServerBundle() {
294322
console.info(`Minimizing server function...`);
323+
const { outputDir } = options;
295324
await minifyAll(path.join(outputDir, "server-function"), {
296325
compress_json: true,
297326
mangle: true,
@@ -301,6 +330,8 @@ async function minifyServerBundle() {
301330
function createImageOptimizationBundle() {
302331
console.info(`Bundling image optimization function...`);
303332

333+
const { appPath, outputDir } = options;
334+
304335
// Create output folder
305336
const outputPath = path.join(outputDir, "image-optimization-function");
306337
fs.mkdirSync(outputPath, { recursive: true });
@@ -354,6 +385,8 @@ function createImageOptimizationBundle() {
354385
function createAssets() {
355386
console.info(`Bundling assets...`);
356387

388+
const { appPath, appPublicPath, outputDir } = options;
389+
357390
// Create output folder
358391
const outputPath = path.join(outputDir, "assets");
359392
fs.mkdirSync(outputPath, { recursive: true });
@@ -377,18 +410,19 @@ function createAssets() {
377410
}
378411
}
379412

380-
function esbuildSync(options: BuildOptions) {
413+
function esbuildSync(esbuildOptions: ESBuildOptions) {
414+
const { debug } = options;
381415
const result = buildSync({
382416
target: "esnext",
383417
format: "esm",
384418
platform: "node",
385419
bundle: true,
386-
minify: process.env.OPEN_NEXT_DEBUG ? false : true,
387-
sourcemap: process.env.OPEN_NEXT_DEBUG ? "inline" : false,
388-
...options,
420+
minify: debug ? false : true,
421+
sourcemap: debug ? "inline" : false,
422+
...esbuildOptions,
389423
// "process.env.OPEN_NEXT_DEBUG" determines if the logger writes to console.log
390424
define: {
391-
...options.define,
425+
...esbuildOptions.define,
392426
"process.env.OPEN_NEXT_DEBUG": process.env.OPEN_NEXT_DEBUG
393427
? "true"
394428
: "false",
@@ -398,7 +432,9 @@ function esbuildSync(options: BuildOptions) {
398432
if (result.errors.length > 0) {
399433
result.errors.forEach((error) => console.error(error));
400434
throw new Error(
401-
`There was a problem bundling ${(options.entryPoints as string[])[0]}.`
435+
`There was a problem bundling ${
436+
(esbuildOptions.entryPoints as string[])[0]
437+
}.`
402438
);
403439
}
404440
}

0 commit comments

Comments
 (0)