diff --git a/packages/cloudflare/src/cli/build/build-worker.ts b/packages/cloudflare/src/cli/build/build-worker.ts index 81c0dbb20..0fe9dd9e6 100644 --- a/packages/cloudflare/src/cli/build/build-worker.ts +++ b/packages/cloudflare/src/cli/build/build-worker.ts @@ -32,16 +32,16 @@ export async function buildWorker(config: Config): Promise { // Copy over client-side generated files await cp( path.join(config.paths.dotNext, "static"), - path.join(config.paths.builderOutput, "assets", "_next", "static"), + path.join(config.paths.outputDir, "assets", "_next", "static"), { recursive: true, } ); // Copy over any static files (e.g. images) from the source project - const publicDir = path.join(config.paths.nextApp, "public"); + const publicDir = path.join(config.paths.sourceDir, "public"); if (existsSync(publicDir)) { - await cp(publicDir, path.join(config.paths.builderOutput, "assets"), { + await cp(publicDir, path.join(config.paths.outputDir, "assets"), { recursive: true, }); } @@ -52,7 +52,7 @@ export async function buildWorker(config: Config): Promise { copyPackageCliFiles(packageDistDir, config); const workerEntrypoint = path.join(config.paths.internalTemplates, "worker.ts"); - const workerOutputFile = path.join(config.paths.builderOutput, "index.mjs"); + const workerOutputFile = path.join(config.paths.outputDir, "index.mjs"); const nextConfigStr = readFileSync(path.join(config.paths.standaloneApp, "/server.js"), "utf8")?.match( diff --git a/packages/cloudflare/src/cli/build/index.ts b/packages/cloudflare/src/cli/build/index.ts index e13265858..879e565b7 100644 --- a/packages/cloudflare/src/cli/build/index.ts +++ b/packages/cloudflare/src/cli/build/index.ts @@ -1,8 +1,9 @@ import { containsDotNextDir, getConfig } from "../config"; +import type { ProjectOptions } from "../config"; import { buildNextjsApp } from "./build-next-app"; import { buildWorker } from "./build-worker"; import { cpSync } from "node:fs"; -import path from "node:path"; +import { join } from "node:path"; import { rm } from "node:fs/promises"; /** @@ -10,37 +11,29 @@ import { rm } from "node:fs/promises"; * * It saves the output in a `.worker-next` directory * - * @param appDir the directory of the Next.js app to build - * @param opts.outputDir the directory where to save the output (defaults to the app's directory) - * @param opts.skipBuild boolean indicating whether the Next.js build should be skipped (i.e. if the `.next` dir is already built) + * @param opts The options for the project */ -export async function build(appDir: string, opts: BuildOptions): Promise { +export async function build(opts: ProjectOptions): Promise { if (!opts.skipBuild) { // Build the next app - await buildNextjsApp(appDir); + await buildNextjsApp(opts.sourceDir); } - if (!containsDotNextDir(appDir)) { - throw new Error(`.next folder not found in ${appDir}`); + if (!containsDotNextDir(opts.sourceDir)) { + throw new Error(`.next folder not found in ${opts.sourceDir}`); } - // Create a clean output directory - const outputDir = path.resolve(opts.outputDir ?? appDir, ".worker-next"); - await cleanDirectory(outputDir); + // Clean the output directory + await cleanDirectory(opts.outputDir); // Copy the .next directory to the output directory so it can be mutated. - cpSync(path.join(appDir, ".next"), path.join(outputDir, ".next"), { recursive: true }); + cpSync(join(opts.sourceDir, ".next"), join(opts.outputDir, ".next"), { recursive: true }); - const config = getConfig(appDir, outputDir); + const config = getConfig(opts); await buildWorker(config); } -type BuildOptions = { - skipBuild: boolean; - outputDir?: string; -}; - async function cleanDirectory(path: string): Promise { return await rm(path, { recursive: true, force: true }); } diff --git a/packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts b/packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts index 1f5145d93..eb1bb1b88 100644 --- a/packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts +++ b/packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts @@ -10,7 +10,7 @@ export async function patchCache(code: string, config: Config): Promise const cacheHandlerFileName = "cache-handler.mjs"; const cacheHandlerEntrypoint = join(config.paths.internalTemplates, "cache-handler", "index.ts"); - const cacheHandlerOutputFile = join(config.paths.builderOutput, cacheHandlerFileName); + const cacheHandlerOutputFile = join(config.paths.outputDir, cacheHandlerFileName); await build({ entryPoints: [cacheHandlerEntrypoint], diff --git a/packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts b/packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts index e2cecb6f4..839521371 100644 --- a/packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts +++ b/packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts @@ -19,7 +19,7 @@ export function copyPrerenderedRoutes(config: Config) { const serverAppDirPath = join(config.paths.standaloneAppServer, "app"); const prerenderManifestPath = join(config.paths.standaloneAppDotNext, "prerender-manifest.json"); - const outputPath = join(config.paths.builderOutput, "assets", SEED_DATA_DIR); + const outputPath = join(config.paths.outputDir, "assets", SEED_DATA_DIR); const prerenderManifest: PrerenderManifest = existsSync(prerenderManifestPath) ? JSON.parse(readFileSync(prerenderManifestPath, "utf8")) @@ -38,7 +38,7 @@ export function copyPrerenderedRoutes(config: Config) { if (fullPath.endsWith(NEXT_META_SUFFIX)) { const data = JSON.parse(readFileSync(fullPath, "utf8")); - writeFileSync(destPath, JSON.stringify({ ...data, lastModified: config.buildTimestamp })); + writeFileSync(destPath, JSON.stringify({ ...data, lastModified: config.build.timestamp })); } else { copyFileSync(fullPath, destPath); } diff --git a/packages/cloudflare/src/cli/config.ts b/packages/cloudflare/src/cli/config.ts index b79d356d3..94f463b60 100644 --- a/packages/cloudflare/src/cli/config.ts +++ b/packages/cloudflare/src/cli/config.ts @@ -11,14 +11,18 @@ const UserConfig = { }; export type Config = { - // Timestamp for when the build was started - buildTimestamp: number; + build: { + // Timestamp for when the build was started + timestamp: number; + // Whether to skip building the Next.js app or not + shouldSkip: boolean; + }; paths: { // Path to the next application - nextApp: string; + sourceDir: string; // Path to the output folder - builderOutput: string; + outputDir: string; // Path to the app's `.next` directory (where `next build` saves the build output) dotNext: string; // Path to the application standalone root directory @@ -46,13 +50,14 @@ export type Config = { /** * Computes the configuration. * - * @param appDir Next app root folder - * @param outputDir Output of the cloudflare builder + * @param opts.sourceDir Next app root folder + * @param opts.outputDir The directory where to save the output (defaults to the app's directory) + * @param opts.skipBuild Whether the Next.js build should be skipped (i.e. if the `.next` dir is already built) * - * @returns the configuration, see `Config` + * @returns The configuration, see `Config` */ -export function getConfig(appDir: string, outputDir: string): Config { - const dotNext = path.join(outputDir, ".next"); +export function getConfig(opts: ProjectOptions): Config { + const dotNext = path.join(opts.outputDir, ".next"); const appPath = getNextjsApplicationPath(dotNext).replace(/\/$/, ""); const standaloneRoot = path.join(dotNext, "standalone"); const standaloneApp = path.join(standaloneRoot, appPath); @@ -64,11 +69,14 @@ export function getConfig(appDir: string, outputDir: string): Config { const internalTemplates = path.join(internalPackage, "cli", "templates"); return { - buildTimestamp: Date.now(), + build: { + timestamp: Date.now(), + shouldSkip: !!opts.skipBuild, + }, paths: { - nextApp: appDir, - builderOutput: outputDir, + sourceDir: opts.sourceDir, + outputDir: opts.outputDir, dotNext, standaloneRoot, standaloneApp, @@ -94,6 +102,12 @@ export function containsDotNextDir(folder: string): boolean { } } +export type ProjectOptions = { + sourceDir: string; + outputDir: string; + skipBuild?: boolean; +}; + /** * It basically tries to find the path that the application is under inside the `.next/standalone` directory, using the `.next/server` directory * presence as the condition that needs to be met. diff --git a/packages/cloudflare/src/cli/index.ts b/packages/cloudflare/src/cli/index.ts index 24ee2bfa1..b11ae6ba5 100644 --- a/packages/cloudflare/src/cli/index.ts +++ b/packages/cloudflare/src/cli/index.ts @@ -15,7 +15,8 @@ if (!["js", "cjs", "mjs", "ts"].some((ext) => existsSync(`./next.config.${ext}`) const { skipBuild, outputDir } = getArgs(); -await build(nextAppDir, { - outputDir, - skipBuild: !!skipBuild, +await build({ + sourceDir: nextAppDir, + outputDir: resolve(outputDir ?? nextAppDir, ".worker-next"), + skipBuild, });