diff --git a/packages/cloudflare/src/cli/build/build-worker.ts b/packages/cloudflare/src/cli/build/build-worker.ts index e2b2b37e..89301049 100644 --- a/packages/cloudflare/src/cli/build/build-worker.ts +++ b/packages/cloudflare/src/cli/build/build-worker.ts @@ -30,16 +30,14 @@ export async function buildWorker(config: Config): Promise { console.log(`\x1b[35m⚙️ Copying files...\n\x1b[0m`); // Copy over client-side generated files - await cp(join(config.paths.dotNext, "static"), join(config.paths.outputDir, "assets", "_next", "static"), { + await cp(join(config.paths.source.dotNext, "static"), join(config.paths.output.assets, "_next", "static"), { recursive: true, }); // Copy over any static files (e.g. images) from the source project - const publicDir = join(config.paths.sourceDir, "public"); + const publicDir = join(config.paths.source.root, "public"); if (existsSync(publicDir)) { - await cp(publicDir, join(config.paths.outputDir, "assets"), { - recursive: true, - }); + await cp(publicDir, config.paths.output.assets, { recursive: true }); } // Copy over prerendered assets (e.g. SSG routes) @@ -47,11 +45,11 @@ export async function buildWorker(config: Config): Promise { copyPackageCliFiles(packageDistDir, config); - const workerEntrypoint = join(config.paths.internalTemplates, "worker.ts"); - const workerOutputFile = join(config.paths.outputDir, "index.mjs"); + const workerEntrypoint = join(config.paths.internal.templates, "worker.ts"); + const workerOutputFile = join(config.paths.output.root, "index.mjs"); const nextConfigStr = - readFileSync(join(config.paths.standaloneApp, "/server.js"), "utf8")?.match( + readFileSync(join(config.paths.output.standaloneApp, "/server.js"), "utf8")?.match( /const nextConfig = ({.+?})\n/ )?.[1] ?? {}; @@ -72,15 +70,15 @@ export async function buildWorker(config: Config): Promise { // Note: we apply an empty shim to next/dist/compiled/ws because it generates two `eval`s: // eval("require")("bufferutil"); // eval("require")("utf-8-validate"); - "next/dist/compiled/ws": join(config.paths.internalTemplates, "shims", "empty.ts"), + "next/dist/compiled/ws": join(config.paths.internal.templates, "shims", "empty.ts"), // Note: we apply an empty shim to next/dist/compiled/edge-runtime since (amongst others) it generated the following `eval`: // eval(getModuleCode)(module, module.exports, throwingRequire, params.context, ...Object.values(params.scopedContext)); // which comes from https://github.com/vercel/edge-runtime/blob/6e96b55f/packages/primitives/src/primitives/load.js#L57-L63 // QUESTION: Why did I encountered this but mhart didn't? - "next/dist/compiled/edge-runtime": join(config.paths.internalTemplates, "shims", "empty.ts"), + "next/dist/compiled/edge-runtime": join(config.paths.internal.templates, "shims", "empty.ts"), // `@next/env` is a library Next.js uses for loading dotenv files, for obvious reasons we need to stub it here // source: https://github.com/vercel/next.js/tree/0ac10d79720/packages/next-env - "@next/env": join(config.paths.internalTemplates, "shims", "env.ts"), + "@next/env": join(config.paths.internal.templates, "shims", "env.ts"), }, define: { // config file used by Next.js, see: https://github.com/vercel/next.js/blob/68a7128/packages/next/src/build/utils.ts#L2137-L2139 @@ -174,10 +172,10 @@ function createFixRequiresESBuildPlugin(config: Config): Plugin { setup(build) { // Note: we (empty) shim require-hook modules as they generate problematic code that uses requires build.onResolve({ filter: /^\.\/require-hook$/ }, () => ({ - path: join(config.paths.internalTemplates, "shims", "empty.ts"), + path: join(config.paths.internal.templates, "shims", "empty.ts"), })); build.onResolve({ filter: /\.\/lib\/node-fs-methods$/ }, () => ({ - path: join(config.paths.internalTemplates, "shims", "empty.ts"), + path: join(config.paths.internal.templates, "shims", "empty.ts"), })); }, }; diff --git a/packages/cloudflare/src/cli/build/patches/investigated/copy-package-cli-files.ts b/packages/cloudflare/src/cli/build/patches/investigated/copy-package-cli-files.ts index 77c5314d..e85e658a 100644 --- a/packages/cloudflare/src/cli/build/patches/investigated/copy-package-cli-files.ts +++ b/packages/cloudflare/src/cli/build/patches/investigated/copy-package-cli-files.ts @@ -8,7 +8,7 @@ import { join } from "node:path"; export function copyPackageCliFiles(packageDistDir: string, config: Config) { console.log("# copyPackageTemplateFiles"); const sourceDir = join(packageDistDir, "cli"); - const destinationDir = join(config.paths.internalPackage, "cli"); + const destinationDir = join(config.paths.internal.package, "cli"); cpSync(sourceDir, destinationDir, { recursive: 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 9e12225d..b1ede21b 100644 --- a/packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts +++ b/packages/cloudflare/src/cli/build/patches/investigated/patch-cache.ts @@ -17,8 +17,8 @@ export async function patchCache(code: string, config: Config): Promise console.log("# patchCache"); const cacheHandlerFileName = "cache-handler.mjs"; - const cacheHandlerEntrypoint = join(config.paths.internalTemplates, "cache-handler", "index.ts"); - const cacheHandlerOutputFile = join(config.paths.outputDir, cacheHandlerFileName); + const cacheHandlerEntrypoint = join(config.paths.internal.templates, "cache-handler", "index.ts"); + const cacheHandlerOutputFile = join(config.paths.output.root, cacheHandlerFileName); await build({ entryPoints: [cacheHandlerEntrypoint], diff --git a/packages/cloudflare/src/cli/build/patches/investigated/update-webpack-chunks-file/index.ts b/packages/cloudflare/src/cli/build/patches/investigated/update-webpack-chunks-file/index.ts index b6c4902e..7a96ce9c 100644 --- a/packages/cloudflare/src/cli/build/patches/investigated/update-webpack-chunks-file/index.ts +++ b/packages/cloudflare/src/cli/build/patches/investigated/update-webpack-chunks-file/index.ts @@ -11,11 +11,11 @@ import { join } from "node:path"; */ export async function updateWebpackChunksFile(config: Config) { console.log("# updateWebpackChunksFile"); - const webpackRuntimeFile = join(config.paths.standaloneAppServer, "webpack-runtime.js"); + const webpackRuntimeFile = join(config.paths.output.standaloneAppServer, "webpack-runtime.js"); const fileContent = readFileSync(webpackRuntimeFile, "utf-8"); - const chunks = readdirSync(join(config.paths.standaloneAppServer, "chunks")) + const chunks = readdirSync(join(config.paths.output.standaloneAppServer, "chunks")) .filter((chunk) => /^\d+\.js$/.test(chunk)) .map((chunk) => { console.log(` - chunk ${chunk}`); diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-eval-manifest.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-eval-manifest.ts index 8181a947..504ab275 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-eval-manifest.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-eval-manifest.ts @@ -13,8 +13,10 @@ import { normalizePath } from "../../utils"; export function inlineEvalManifest(code: string, config: Config): string { console.log("# inlineEvalManifest"); const manifestJss = globSync( - normalizePath(join(config.paths.standaloneAppDotNext, "**", "*_client-reference-manifest.js")) - ).map((file) => normalizePath(file).replace(normalizePath(config.paths.standaloneApp) + posix.sep, "")); + normalizePath(join(config.paths.output.standaloneAppDotNext, "**", "*_client-reference-manifest.js")) + ).map((file) => + normalizePath(file).replace(normalizePath(config.paths.output.standaloneApp) + posix.sep, "") + ); return code.replace( /function evalManifest\((.+?), .+?\) {/, `$& @@ -22,7 +24,7 @@ export function inlineEvalManifest(code: string, config: Config): string { .map( (manifestJs) => ` if ($1.endsWith("${manifestJs}")) { - require(${JSON.stringify(join(config.paths.standaloneApp, manifestJs))}); + require(${JSON.stringify(join(config.paths.output.standaloneApp, manifestJs))}); return { __RSC_MANIFEST: { "${manifestJs diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest-require.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest-require.ts index 513eb841..83db6fc5 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest-require.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-middleware-manifest-require.ts @@ -9,7 +9,7 @@ import { join } from "node:path"; export function inlineMiddlewareManifestRequire(code: string, config: Config) { console.log("# inlineMiddlewareManifestRequire"); - const middlewareManifestPath = join(config.paths.standaloneAppServer, "middleware-manifest.json"); + const middlewareManifestPath = join(config.paths.output.standaloneAppServer, "middleware-manifest.json"); const middlewareManifest = existsSync(middlewareManifestPath) ? JSON.parse(readFileSync(middlewareManifestPath, "utf-8")) diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-next-require.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-next-require.ts index 532d8375..bbacaef0 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/inline-next-require.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/inline-next-require.ts @@ -8,8 +8,8 @@ import { join } from "node:path"; */ export function inlineNextRequire(code: string, config: Config) { console.log("# inlineNextRequire"); - const pagesManifestFile = join(config.paths.standaloneAppServer, "pages-manifest.json"); - const appPathsManifestFile = join(config.paths.standaloneAppServer, "app-paths-manifest.json"); + const pagesManifestFile = join(config.paths.output.standaloneAppServer, "pages-manifest.json"); + const appPathsManifestFile = join(config.paths.output.standaloneAppServer, "app-paths-manifest.json"); const pagesManifestFiles = existsSync(pagesManifestFile) ? Object.values(JSON.parse(readFileSync(pagesManifestFile, "utf-8"))).map( @@ -33,7 +33,7 @@ export function inlineNextRequire(code: string, config: Config) { .map( (htmlPage) => ` if (pagePath.endsWith("${htmlPage}")) { - return ${JSON.stringify(readFileSync(join(config.paths.standaloneApp, htmlPage), "utf-8"))}; + return ${JSON.stringify(readFileSync(join(config.paths.output.standaloneApp, htmlPage), "utf-8"))}; } ` ) @@ -42,7 +42,7 @@ export function inlineNextRequire(code: string, config: Config) { .map( (module) => ` if (pagePath.endsWith("${module}")) { - return require(${JSON.stringify(join(config.paths.standaloneApp, module))}); + return require(${JSON.stringify(join(config.paths.output.standaloneApp, module))}); } ` ) diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-find-dir.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/patch-find-dir.ts index 481cbda8..29daf7ce 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-find-dir.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/patch-find-dir.ts @@ -15,10 +15,10 @@ export function patchFindDir(code: string, config: Config): string { `function findDir(dir, name) { if (dir.endsWith(".next/server")) { if (name === "app") { - return ${existsSync(`${join(config.paths.standaloneAppServer, "app")}`)}; + return ${existsSync(`${join(config.paths.output.standaloneAppServer, "app")}`)}; } if (name === "pages") { - return ${existsSync(`${join(config.paths.standaloneAppServer, "pages")}`)}; + return ${existsSync(`${join(config.paths.output.standaloneAppServer, "pages")}`)}; } } throw new Error("Unknown findDir call: " + dir + " " + name); diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts index d149c448..94962a70 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/patch-read-file.ts @@ -13,7 +13,7 @@ export function patchReadFile(code: string, config: Config): string { code = code.replace( "getBuildId() {", `getBuildId() { - return ${JSON.stringify(readFileSync(join(config.paths.standaloneAppDotNext, "BUILD_ID"), "utf-8"))}; + return ${JSON.stringify(readFileSync(join(config.paths.output.standaloneAppDotNext, "BUILD_ID"), "utf-8"))}; ` ); @@ -21,8 +21,10 @@ export function patchReadFile(code: string, config: Config): string { // (source: https://github.com/vercel/next.js/blob/15aeb92e/packages/next/src/server/load-manifest.ts#L34-L56) // Note: we could/should probably just patch readFileSync here or something! const manifestJsons = globSync( - normalizePath(join(config.paths.standaloneAppDotNext, "**", "*-manifest.json")) - ).map((file) => normalizePath(file).replace(normalizePath(config.paths.standaloneApp) + posix.sep, "")); + normalizePath(join(config.paths.output.standaloneAppDotNext, "**", "*-manifest.json")) + ).map((file) => + normalizePath(file).replace(normalizePath(config.paths.output.standaloneApp) + posix.sep, "") + ); code = code.replace( /function loadManifest\((.+?), .+?\) {/, `$& @@ -30,7 +32,7 @@ export function patchReadFile(code: string, config: Config): string { .map( (manifestJson) => ` if ($1.endsWith("${manifestJson}")) { - return ${readFileSync(join(config.paths.standaloneApp, manifestJson), "utf-8")}; + return ${readFileSync(join(config.paths.output.standaloneApp, manifestJson), "utf-8")}; } ` ) diff --git a/packages/cloudflare/src/cli/build/patches/to-investigate/wrangler-deps.ts b/packages/cloudflare/src/cli/build/patches/to-investigate/wrangler-deps.ts index 5651cc8e..4235f4ea 100644 --- a/packages/cloudflare/src/cli/build/patches/to-investigate/wrangler-deps.ts +++ b/packages/cloudflare/src/cli/build/patches/to-investigate/wrangler-deps.ts @@ -55,7 +55,7 @@ export function patchWranglerDeps(config: Config) { * @returns the node_modules/next/dist directory path */ function getDistPath(config: Config): string { - for (const root of [config.paths.standaloneApp, config.paths.standaloneRoot]) { + for (const root of [config.paths.output.standaloneApp, config.paths.output.standaloneRoot]) { try { const distPath = join(root, "node_modules", "next", "dist"); if (statSync(distPath).isDirectory()) return distPath; 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 83952137..51eb4680 100644 --- a/packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts +++ b/packages/cloudflare/src/cli/build/utils/copy-prerendered-routes.ts @@ -17,9 +17,9 @@ import { readPathsRecursively } from "./read-paths-recursively"; export function copyPrerenderedRoutes(config: Config) { console.log("# copyPrerenderedRoutes"); - const serverAppDirPath = join(config.paths.standaloneAppServer, "app"); - const prerenderManifestPath = join(config.paths.standaloneAppDotNext, "prerender-manifest.json"); - const outputPath = join(config.paths.outputDir, "assets", SEED_DATA_DIR); + const serverAppDirPath = join(config.paths.output.standaloneAppServer, "app"); + const prerenderManifestPath = join(config.paths.output.standaloneAppDotNext, "prerender-manifest.json"); + const outputPath = join(config.paths.output.assets, SEED_DATA_DIR); const prerenderManifest: PrerenderManifest = existsSync(prerenderManifestPath) ? JSON.parse(readFileSync(prerenderManifestPath, "utf8")) diff --git a/packages/cloudflare/src/cli/config.ts b/packages/cloudflare/src/cli/config.ts index f52ff2cc..61ea28b5 100644 --- a/packages/cloudflare/src/cli/config.ts +++ b/packages/cloudflare/src/cli/config.ts @@ -14,24 +14,36 @@ export type Config = { }; paths: { - // Path to the next application - sourceDir: string; - // Path to the output folder - 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 - standaloneRoot: string; - // Path to the application standalone directory (where `next build` saves the standalone app) - standaloneApp: string; - // Path to the `.next` directory specific to the standalone application - standaloneAppDotNext: string; - // Path to the `server` directory specific to the standalone application - standaloneAppServer: string; - // Package in the standalone node_modules - internalPackage: string; - // Templates in the package in the standalone node_modules - internalTemplates: string; + source: { + // Path to the next application + root: string; + // Path to the app's `.next` directory (where `next build` saves the build output) + dotNext: string; + // Path to the application standalone root directory + standaloneRoot: string; + }; + output: { + // Path to the output directory + root: string; + // Path to the OpenNext static assets directory + assets: string; + // Path to the app's `.next` directory in the OpenNext output directory + dotNext: string; + // Path to the application standalone root directory + standaloneRoot: string; + // Path to the application standalone directory (where `next build` saves the standalone app) + standaloneApp: string; + // Path to the `.next` directory specific to the standalone application + standaloneAppDotNext: string; + // Path to the `server` directory specific to the standalone application + standaloneAppServer: string; + }; + internal: { + // Package in the standalone node_modules + package: string; + // Templates in the package in the standalone node_modules + templates: string; + }; }; cache: { @@ -49,6 +61,8 @@ export type Config = { * @returns The configuration, see `Config` */ export function getConfig(projectOpts: ProjectOptions): Config { + const sourceDirDotNext = join(projectOpts.sourceDir, ".next"); + const dotNext = join(projectOpts.outputDir, ".next"); const appPath = getNextjsApplicationPath(dotNext).replace(/\/$/, ""); const standaloneRoot = join(dotNext, "standalone"); @@ -70,15 +84,24 @@ export function getConfig(projectOpts: ProjectOptions): Config { }, paths: { - sourceDir: projectOpts.sourceDir, - outputDir: projectOpts.outputDir, - dotNext, - standaloneRoot, - standaloneApp, - standaloneAppDotNext, - standaloneAppServer, - internalPackage, - internalTemplates, + source: { + root: projectOpts.sourceDir, + dotNext: sourceDirDotNext, + standaloneRoot: join(sourceDirDotNext, "standalone"), + }, + output: { + root: projectOpts.outputDir, + assets: join(projectOpts.outputDir, "assets"), + dotNext, + standaloneRoot, + standaloneApp, + standaloneAppDotNext, + standaloneAppServer, + }, + internal: { + package: internalPackage, + templates: internalTemplates, + }, }, cache: {