diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index a9a14696f..c109b3e08 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -33,7 +33,7 @@ jobs: - name: Get Latest Next Version id: get_latest_version run: | - latest_version=$(curl -s https://api.github.com/repos/vercel/next.js/releases/latest | jq -r '.tag_name') + latest_version=$(curl -s https://registry.npmjs.org/-/package/next/dist-tags | jq -r '.latest') echo "Latest version: $latest_version" echo "LATEST_VERSION=$latest_version" >> $GITHUB_ENV echo "LATEST_VERSION=$latest_version" >> $GITHUB_OUTPUT diff --git a/packages/open-next/src/build.ts b/packages/open-next/src/build.ts index 51ef46859..f55f3d95d 100755 --- a/packages/open-next/src/build.ts +++ b/packages/open-next/src/build.ts @@ -1,5 +1,5 @@ import cp from "node:child_process"; -import fs, { readFileSync } from "node:fs"; +import fs from "node:fs"; import { createRequire as topLevelCreateRequire } from "node:module"; import os from "node:os"; import path from "node:path"; @@ -47,9 +47,9 @@ export async function build( showWindowsWarning(); // Load open-next.config.ts - const tempDir = initTempDir(); + const tempBuildDir = fs.mkdtempSync(path.join(os.tmpdir(), "open-next-tmp")); let configPath = compileOpenNextConfigNode( - tempDir, + tempBuildDir, openNextConfigPath, nodeExternals, ); @@ -64,10 +64,10 @@ export async function build( } validateConfig(config); - compileOpenNextConfigEdge(tempDir, config, openNextConfigPath); + compileOpenNextConfigEdge(tempBuildDir, config, openNextConfigPath); // Initialize options - const options = normalizeOptions(config); + const options = normalizeOptions(config, tempBuildDir); logger.setLevel(options.debug ? "debug" : "info"); // Pre-build validation @@ -82,7 +82,7 @@ export async function build( // Generate deployable bundle printHeader("Generating bundle"); - initOutputDir(tempDir, options); + initOutputDir(options); // Compile cache.ts compileCache(options); @@ -113,14 +113,6 @@ function showWindowsWarning() { ); } -function initTempDir() { - const dir = path.join(process.cwd(), ".open-next"); - const tempDir = path.join(dir, ".build"); - fs.rmSync(dir, { recursive: true, force: true }); - fs.mkdirSync(tempDir, { recursive: true }); - return tempDir; -} - function checkRunningInsideNextjsApp(options: BuildOptions) { const { appPath } = options; const extension = ["js", "cjs", "mjs", "ts"].find((ext) => @@ -175,34 +167,14 @@ function printOpenNextVersion(options: BuildOptions) { logger.info(`OpenNext v${options.openNextVersion}`); } -function initOutputDir(srcTempDir: string, options: BuildOptions) { +function initOutputDir(options: BuildOptions) { // We need to get the build relative to the cwd to find the compiled config // 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 // where the build is in the app directory, but the compiled config is in the root of the monorepo. - const openNextConfig = readFileSync( - path.join(srcTempDir, "open-next.config.mjs"), - "utf8", - ); - let openNextConfigEdge: string | null = null; - if (fs.existsSync(path.join(srcTempDir, "open-next.config.edge.mjs"))) { - openNextConfigEdge = readFileSync( - path.join(srcTempDir, "open-next.config.edge.mjs"), - "utf8", - ); - } fs.rmSync(options.outputDir, { recursive: true, force: true }); - const destTempDir = options.tempDir; - fs.mkdirSync(destTempDir, { recursive: true }); - fs.writeFileSync( - path.join(destTempDir, "open-next.config.mjs"), - openNextConfig, - ); - if (openNextConfigEdge) { - fs.writeFileSync( - path.join(destTempDir, "open-next.config.edge.mjs"), - openNextConfigEdge, - ); - } + const { buildDir } = options; + fs.mkdirSync(buildDir, { recursive: true }); + fs.cpSync(options.tempBuildDir, buildDir, { recursive: true }); } async function createWarmerBundle(options: BuildOptions) { @@ -215,7 +187,7 @@ async function createWarmerBundle(options: BuildOptions) { fs.mkdirSync(outputPath, { recursive: true }); // Copy open-next.config.mjs into the bundle - copyOpenNextConfig(options.tempDir, outputPath); + copyOpenNextConfig(options.buildDir, outputPath); // Build Lambda code // note: bundle in OpenNext package b/c the adatper relys on the @@ -258,7 +230,7 @@ async function createRevalidationBundle(options: BuildOptions) { fs.mkdirSync(outputPath, { recursive: true }); //Copy open-next.config.mjs into the bundle - copyOpenNextConfig(options.tempDir, outputPath); + copyOpenNextConfig(options.buildDir, outputPath); // Build Lambda code await esbuildAsync( @@ -297,7 +269,7 @@ async function createImageOptimizationBundle(options: BuildOptions) { fs.mkdirSync(outputPath, { recursive: true }); // Copy open-next.config.mjs into the bundle - copyOpenNextConfig(options.tempDir, outputPath); + copyOpenNextConfig(options.buildDir, outputPath); const plugins = [ openNextResolvePlugin({ @@ -636,7 +608,7 @@ async function createCacheAssets(options: BuildOptions) { ); //Copy open-next.config.mjs into the bundle - copyOpenNextConfig(options.tempDir, providerPath); + copyOpenNextConfig(options.buildDir, providerPath); // TODO: check if metafiles doesn't contain duplicates fs.writeFileSync( @@ -660,7 +632,7 @@ export function compileCache( ) { const { config } = options; const ext = format === "cjs" ? "cjs" : "mjs"; - const outfile = path.join(options.outputDir, ".build", `cache.${ext}`); + const outfile = path.join(options.buildDir, `cache.${ext}`); const isAfter15 = compareSemver(options.nextVersion, "15.0.0") >= 0; @@ -695,7 +667,7 @@ async function createMiddleware(options: BuildOptions) { // Get middleware manifest const middlewareManifest = JSON.parse( - readFileSync( + fs.readFileSync( path.join(appBuildOutputPath, ".next/server/middleware-manifest.json"), "utf8", ), @@ -721,7 +693,7 @@ async function createMiddleware(options: BuildOptions) { // Copy open-next.config.mjs copyOpenNextConfig( - options.tempDir, + options.buildDir, outputPath, config.middleware.override?.wrapper === "cloudflare", ); @@ -739,7 +711,7 @@ async function createMiddleware(options: BuildOptions) { } else { await buildEdgeBundle({ entrypoint: path.join(__dirname, "core", "edgeFunctionHandler.js"), - outfile: path.join(outputDir, ".build", "middleware.mjs"), + outfile: path.join(options.buildDir, "middleware.mjs"), ...commonMiddlewareOptions, onlyBuildOnce: true, }); diff --git a/packages/open-next/src/build/compileConfig.ts b/packages/open-next/src/build/compileConfig.ts index eded84ac8..c78387011 100644 --- a/packages/open-next/src/build/compileConfig.ts +++ b/packages/open-next/src/build/compileConfig.ts @@ -7,7 +7,7 @@ import { OpenNextConfig } from "types/open-next.js"; import logger from "../logger.js"; export function compileOpenNextConfigNode( - tempDir: string, + outputDir: string, openNextConfigPath?: string, nodeExternals?: string, ) { @@ -15,20 +15,13 @@ export function compileOpenNextConfigNode( process.cwd(), openNextConfigPath ?? "open-next.config.ts", ); - const outputPath = path.join(tempDir, "open-next.config.mjs"); + const outputPath = path.join(outputDir, "open-next.config.mjs"); //Check if open-next.config.ts exists if (!fs.existsSync(sourcePath)) { //Create a simple open-next.config.mjs file logger.debug("Cannot find open-next.config.ts. Using default config."); - fs.writeFileSync( - outputPath, - [ - "var config = { default: { } };", - "var open_next_config_default = config;", - "export { open_next_config_default as default };", - ].join("\n"), - ); + fs.writeFileSync(outputPath, "export default { default: { } };"); } else { buildSync({ entryPoints: [sourcePath], diff --git a/packages/open-next/src/build/createServerBundle.ts b/packages/open-next/src/build/createServerBundle.ts index dc555f364..8f78bf9bd 100644 --- a/packages/open-next/src/build/createServerBundle.ts +++ b/packages/open-next/src/build/createServerBundle.ts @@ -144,7 +144,7 @@ async function generateBundle( const ext = fnOptions.runtime === "deno" ? "mjs" : "cjs"; fs.copyFileSync( - path.join(outputDir, ".build", `cache.${ext}`), + path.join(options.buildDir, `cache.${ext}`), path.join(outputPath, packagePath, "cache.cjs"), ); @@ -158,24 +158,21 @@ async function generateBundle( await bundleNextServer(path.join(outputPath, packagePath), appPath); } - // // Copy middleware + // Copy middleware if ( !config.middleware?.external && - existsSync(path.join(outputDir, ".build", "middleware.mjs")) + existsSync(path.join(options.buildDir, "middleware.mjs")) ) { fs.copyFileSync( - path.join(outputDir, ".build", "middleware.mjs"), + path.join(options.buildDir, "middleware.mjs"), path.join(outputPath, packagePath, "middleware.mjs"), ); } // Copy open-next.config.mjs - copyOpenNextConfig( - path.join(outputDir, ".build"), - path.join(outputPath, packagePath), - ); + copyOpenNextConfig(options.buildDir, path.join(outputPath, packagePath)); - //Copy env files + // Copy env files copyEnvFile(appBuildOutputPath, packagePath, outputPath); // Copy all necessary traced files diff --git a/packages/open-next/src/build/edge/createEdgeBundle.ts b/packages/open-next/src/build/edge/createEdgeBundle.ts index c8722dbc9..3ddafaba6 100644 --- a/packages/open-next/src/build/edge/createEdgeBundle.ts +++ b/packages/open-next/src/build/edge/createEdgeBundle.ts @@ -179,7 +179,7 @@ export async function generateEdgeBundle( fs.mkdirSync(outputPath, { recursive: true }); // Copy open-next.config.mjs - copyOpenNextConfig(path.join(outputDir, ".build"), outputPath, true); + copyOpenNextConfig(options.buildDir, outputPath, true); // Load middleware manifest const middlewareManifest = JSON.parse( diff --git a/packages/open-next/src/build/helper.ts b/packages/open-next/src/build/helper.ts index 539f39acc..d3c95d45f 100644 --- a/packages/open-next/src/build/helper.ts +++ b/packages/open-next/src/build/helper.ts @@ -17,7 +17,7 @@ const __dirname = url.fileURLToPath(new URL(".", import.meta.url)); export type BuildOptions = ReturnType; -export function normalizeOptions(config: OpenNextConfig) { +export function normalizeOptions(config: OpenNextConfig, tempBuildDir: string) { const appPath = path.join(process.cwd(), config.appPath || "."); const buildOutputPath = path.join( process.cwd(), @@ -44,6 +44,7 @@ export function normalizeOptions(config: OpenNextConfig) { appPackageJsonPath, appPath, appPublicPath: path.join(appPath, "public"), + buildDir: path.join(outputDir, ".build"), config, debug: Boolean(process.env.OPEN_NEXT_DEBUG) ?? false, monorepoRoot, @@ -51,7 +52,7 @@ export function normalizeOptions(config: OpenNextConfig) { openNextVersion: getOpenNextVersion(), outputDir, packager, - tempDir: path.join(outputDir, ".build"), + tempBuildDir, }; } @@ -77,6 +78,7 @@ function findMonorepoRoot(appPath: string) { // note: a lock file (package-lock.json, yarn.lock, or pnpm-lock.yaml) is // not found in the app's directory or any of its parent directories. // We are going to assume that the app is not part of a monorepo. + logger.warn("No lockfile found"); return { root: appPath, packager: "npm" as const }; } @@ -273,17 +275,17 @@ export function compareSemver(v1: string, v2: string): number { } export function copyOpenNextConfig( - tempDir: string, - outputPath: string, + inputDir: string, + outputDir: string, isEdge = false, ) { // Copy open-next.config.mjs fs.copyFileSync( path.join( - tempDir, + inputDir, isEdge ? "open-next.config.edge.mjs" : "open-next.config.mjs", ), - path.join(outputPath, "open-next.config.mjs"), + path.join(outputDir, "open-next.config.mjs"), ); }