Skip to content

Commit aa97c43

Browse files
authored
Fix cannot write default config file b/c folder not created (#364)
* Fix cannot write default config file b/c folder not created * Removed copyTracedFiles debug log
1 parent b86860c commit aa97c43

File tree

5 files changed

+105
-100
lines changed

5 files changed

+105
-100
lines changed

packages/open-next/src/build.ts

+62-59
Original file line numberDiff line numberDiff line change
@@ -29,35 +29,27 @@ import { OpenNextConfig } from "./types/open-next.js";
2929

3030
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
3131
let options: BuildOptions;
32+
let config: OpenNextConfig;
3233

3334
export type PublicFiles = {
3435
files: string[];
3536
};
3637

3738
export async function build(openNextConfigPath?: string) {
38-
const outputTmpPath = path.join(process.cwd(), ".open-next", ".build");
39+
showWindowsWarning();
3940

40-
if (os.platform() === "win32") {
41-
logger.error(
42-
"OpenNext is not properly supported on Windows. On windows you should use WSL. It might works or it might fail in unpredictable way at runtime",
43-
);
44-
// Wait 10s here so that the user see this message
45-
await new Promise((resolve) => setTimeout(resolve, 10000));
46-
}
47-
48-
// Compile open-next.config.ts
49-
createOpenNextConfigBundle(outputTmpPath, openNextConfigPath);
50-
51-
const config = await import(outputTmpPath + "/open-next.config.mjs");
52-
const opts = config.default as OpenNextConfig;
53-
validateConfig(opts);
41+
// Load open-next.config.ts
42+
const tempDir = initTempDir();
43+
const configPath = compileOpenNextConfig(tempDir, openNextConfigPath);
44+
config = (await import(configPath)).default as OpenNextConfig;
45+
validateConfig(config);
5446

5547
const { root: monorepoRoot, packager } = findMonorepoRoot(
56-
path.join(process.cwd(), opts.appPath || "."),
48+
path.join(process.cwd(), config.appPath || "."),
5749
);
5850

5951
// Initialize options
60-
options = normalizeOptions(opts, monorepoRoot);
52+
options = normalizeOptions(config, monorepoRoot);
6153
logger.setLevel(options.debug ? "debug" : "info");
6254

6355
// Pre-build validation
@@ -75,57 +67,70 @@ export async function build(openNextConfigPath?: string) {
7567
initOutputDir();
7668

7769
// Compile cache.ts
78-
compileCache(options);
70+
compileCache();
7971

8072
// Compile middleware
81-
await createMiddleware(opts);
73+
await createMiddleware();
8274

8375
createStaticAssets();
84-
if (!options.dangerous?.disableIncrementalCache) {
85-
await createCacheAssets(monorepoRoot, options.dangerous?.disableTagCache);
86-
}
87-
await createServerBundle(opts, options);
76+
await createCacheAssets(monorepoRoot);
77+
await createServerBundle(config, options);
8878
await createRevalidationBundle();
8979
createImageOptimizationBundle();
9080
await createWarmerBundle();
91-
await generateOutput(options.appBuildOutputPath, opts);
81+
await generateOutput(options.appBuildOutputPath, config);
9282
}
9383

94-
function createOpenNextConfigBundle(
95-
tempDir: string,
96-
openNextConfigPath?: string,
97-
) {
98-
//Check if open-next.config.ts exists
99-
const pathToOpenNextConfig = path.join(
84+
function showWindowsWarning() {
85+
if (os.platform() !== "win32") return;
86+
87+
logger.warn("OpenNext is not fully compatible with Windows.");
88+
logger.warn(
89+
"For optimal performance, it is recommended to use Windows Subsystem for Linux (WSL).",
90+
);
91+
logger.warn(
92+
"While OpenNext may function on Windows, it could encounter unpredictable failures during runtime.",
93+
);
94+
}
95+
96+
function initTempDir() {
97+
const dir = path.join(process.cwd(), ".open-next");
98+
const tempDir = path.join(dir, ".build");
99+
fs.rmSync(dir, { recursive: true, force: true });
100+
fs.mkdirSync(tempDir, { recursive: true });
101+
return tempDir;
102+
}
103+
104+
function compileOpenNextConfig(tempDir: string, openNextConfigPath?: string) {
105+
const sourcePath = path.join(
100106
process.cwd(),
101107
openNextConfigPath ?? "open-next.config.ts",
102108
);
103-
if (!fs.existsSync(pathToOpenNextConfig)) {
109+
const outputPath = path.join(tempDir, "open-next.config.mjs");
110+
111+
//Check if open-next.config.ts exists
112+
if (!fs.existsSync(sourcePath)) {
104113
//Create a simple open-next.config.mjs file
105-
logger.warn(
106-
"You don't have an open-next.config.ts file. Using default configuration.",
107-
);
114+
logger.debug("Cannot find open-next.config.ts. Using default config.");
108115
fs.writeFileSync(
109-
path.join(tempDir, "open-next.config.mjs"),
110-
`var config = {
111-
default: {
112-
},
113-
};
114-
var open_next_config_default = config;
115-
export {
116-
open_next_config_default as default
117-
};
118-
`,
116+
outputPath,
117+
[
118+
"var config = { default: { } };",
119+
"var open_next_config_default = config;",
120+
"export { open_next_config_default as default };",
121+
].join("\n"),
119122
);
120123
} else {
121124
buildSync({
122-
entryPoints: [pathToOpenNextConfig],
123-
outfile: path.join(tempDir, "open-next.config.mjs"),
125+
entryPoints: [sourcePath],
126+
outfile: outputPath,
124127
bundle: true,
125128
format: "esm",
126129
target: ["node18"],
127130
});
128131
}
132+
133+
return outputPath;
129134
}
130135

131136
function checkRunningInsideNextjsApp() {
@@ -176,7 +181,7 @@ function setStandaloneBuildMode(monorepoRoot: string) {
176181
function buildNextjsApp(packager: "npm" | "yarn" | "pnpm" | "bun") {
177182
const { nextPackageJsonPath } = options;
178183
const command =
179-
options.buildCommand ??
184+
config.buildCommand ??
180185
(["bun", "npm"].includes(packager)
181186
? `${packager} run build`
182187
: `${packager} build`);
@@ -430,10 +435,9 @@ function createStaticAssets() {
430435
}
431436
}
432437

433-
async function createCacheAssets(
434-
monorepoRoot: string,
435-
disableDynamoDBCache = false,
436-
) {
438+
async function createCacheAssets(monorepoRoot: string) {
439+
if (config.dangerous?.disableIncrementalCache) return;
440+
437441
logger.info(`Bundling cache assets...`);
438442

439443
const { appBuildOutputPath, outputDir } = options;
@@ -527,7 +531,7 @@ async function createCacheAssets(
527531
fs.writeFileSync(cacheFilePath, JSON.stringify(cacheFileContent));
528532
});
529533

530-
if (!disableDynamoDBCache) {
534+
if (!config.dangerous?.disableTagCache) {
531535
// Generate dynamodb data
532536
// We need to traverse the cache to find every .meta file
533537
const metaFiles: {
@@ -635,9 +639,8 @@ async function createCacheAssets(
635639
/* Server Helper Functions */
636640
/***************************/
637641

638-
function compileCache(options: BuildOptions) {
642+
function compileCache() {
639643
const outfile = path.join(options.outputDir, ".build", "cache.cjs");
640-
const dangerousOptions = options.dangerous;
641644
esbuildSync(
642645
{
643646
external: ["next", "styled-jsx", "react", "@aws-sdk/*"],
@@ -648,10 +651,10 @@ function compileCache(options: BuildOptions) {
648651
banner: {
649652
js: [
650653
`globalThis.disableIncrementalCache = ${
651-
dangerousOptions?.disableIncrementalCache ?? false
654+
config.dangerous?.disableIncrementalCache ?? false
652655
};`,
653656
`globalThis.disableDynamoDBCache = ${
654-
dangerousOptions?.disableTagCache ?? false
657+
config.dangerous?.disableTagCache ?? false
655658
};`,
656659
].join(""),
657660
},
@@ -661,10 +664,10 @@ function compileCache(options: BuildOptions) {
661664
return outfile;
662665
}
663666

664-
async function createMiddleware(config: OpenNextConfig) {
667+
async function createMiddleware() {
665668
console.info(`Bundling middleware function...`);
666669

667-
const { appBuildOutputPath, outputDir, externalMiddleware } = options;
670+
const { appBuildOutputPath, outputDir } = options;
668671

669672
// Get middleware manifest
670673
const middlewareManifest = JSON.parse(
@@ -688,7 +691,7 @@ async function createMiddleware(config: OpenNextConfig) {
688691
appBuildOutputPath,
689692
};
690693

691-
if (externalMiddleware) {
694+
if (config.middleware?.external) {
692695
outputPath = path.join(outputDir, "middleware");
693696
fs.mkdirSync(outputPath, { recursive: true });
694697

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

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
} from "fs";
1212
import path from "path";
1313
import { NextConfig, PrerenderManifest } from "types/next-types";
14+
import logger from "../logger";
1415

1516
export async function copyTracedFiles(
1617
buildOutputPath: string,
@@ -19,7 +20,7 @@ export async function copyTracedFiles(
1920
routes: string[],
2021
bundledNextServer: boolean,
2122
) {
22-
console.time("copyTracedFiles");
23+
const tsStart = Date.now();
2324
const dotNextDir = path.join(buildOutputPath, ".next");
2425
const standaloneDir = path.join(dotNextDir, "standalone");
2526
const standaloneNextDir = path.join(standaloneDir, packagePath, ".next");
@@ -232,5 +233,5 @@ export async function copyTracedFiles(
232233
});
233234
}
234235

235-
console.timeEnd("copyTracedFiles");
236+
logger.debug("copyTracedFiles:", Date.now() - tsStart, "ms");
236237
}

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

+12-11
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,21 @@ const require = topLevelCreateRequire(import.meta.url);
2929
const __dirname = url.fileURLToPath(new URL(".", import.meta.url));
3030

3131
export async function createServerBundle(
32-
options: OpenNextConfig,
33-
buildRuntimeOptions: BuildOptions,
32+
config: OpenNextConfig,
33+
options: BuildOptions,
3434
) {
3535
const foundRoutes = new Set<string>();
3636
// Get all functions to build
37-
const defaultFn = options.default;
38-
const functions = Object.entries(options.functions ?? {});
37+
const defaultFn = config.default;
38+
const functions = Object.entries(config.functions ?? {});
3939

4040
const promises = functions.map(async ([name, fnOptions]) => {
4141
const routes = fnOptions.routes;
4242
routes.forEach((route) => foundRoutes.add(route));
4343
if (fnOptions.runtime === "edge") {
44-
await generateEdgeBundle(name, buildRuntimeOptions, fnOptions);
44+
await generateEdgeBundle(name, options, fnOptions);
4545
} else {
46-
await generateBundle(name, buildRuntimeOptions, fnOptions);
46+
await generateBundle(name, config, options, fnOptions);
4747
}
4848
});
4949

@@ -54,13 +54,13 @@ export async function createServerBundle(
5454

5555
const remainingRoutes = new Set<string>();
5656

57-
const { monorepoRoot, appBuildOutputPath } = buildRuntimeOptions;
57+
const { monorepoRoot, appBuildOutputPath } = options;
5858

5959
const packagePath = path.relative(monorepoRoot, appBuildOutputPath);
6060

6161
// Find remaining routes
6262
const serverPath = path.join(
63-
buildRuntimeOptions.appBuildOutputPath,
63+
appBuildOutputPath,
6464
".next",
6565
"standalone",
6666
packagePath,
@@ -105,7 +105,7 @@ export async function createServerBundle(
105105
}
106106

107107
// Generate default function
108-
await generateBundle("default", buildRuntimeOptions, {
108+
await generateBundle("default", config, options, {
109109
...defaultFn,
110110
routes: Array.from(remainingRoutes),
111111
patterns: ["*"],
@@ -114,6 +114,7 @@ export async function createServerBundle(
114114

115115
async function generateBundle(
116116
name: string,
117+
config: OpenNextConfig,
117118
options: BuildOptions,
118119
fnOptions: SplittedFunctionOptions,
119120
) {
@@ -149,7 +150,7 @@ async function generateBundle(
149150

150151
// // Copy middleware
151152
if (
152-
!options.externalMiddleware &&
153+
!config.middleware?.external &&
153154
existsSync(path.join(outputDir, ".build", "middleware.mjs"))
154155
) {
155156
fs.copyFileSync(
@@ -187,7 +188,7 @@ async function generateBundle(
187188
const isBefore13413 = compareSemver(options.nextVersion, "13.4.13") <= 0;
188189
const isAfter141 = compareSemver(options.nextVersion, "14.0.4") >= 0;
189190

190-
const disableRouting = isBefore13413 || options.externalMiddleware;
191+
const disableRouting = isBefore13413 || config.middleware?.external;
191192
const plugins = [
192193
openNextReplacementPlugin({
193194
name: `requestHandlerOverride ${name}`,

0 commit comments

Comments
 (0)