|
| 1 | +import { cpSync } from "node:fs"; |
| 2 | +import { createRequire } from "node:module"; |
| 3 | +import { dirname, join } from "node:path"; |
| 4 | + |
| 5 | +import { buildNextjsApp, setStandaloneBuildMode } from "@opennextjs/aws/build/buildNextApp.js"; |
| 6 | +import { compileCache } from "@opennextjs/aws/build/compileCache.js"; |
| 7 | +import { compileOpenNextConfig } from "@opennextjs/aws/build/compileConfig.js"; |
| 8 | +import { createCacheAssets, createStaticAssets } from "@opennextjs/aws/build/createAssets.js"; |
| 9 | +import { createMiddleware } from "@opennextjs/aws/build/createMiddleware.js"; |
| 10 | +import * as buildHelper from "@opennextjs/aws/build/helper.js"; |
| 11 | +import { printHeader, showWarningOnWindows } from "@opennextjs/aws/build/utils.js"; |
| 12 | +import logger from "@opennextjs/aws/logger.js"; |
| 13 | + |
| 14 | +import type { ProjectOptions } from "../config.js"; |
| 15 | +import { containsDotNextDir, getConfig } from "../config.js"; |
| 16 | +import { bundleServer } from "./bundle-server.js"; |
| 17 | +import { compileEnvFiles } from "./open-next/compile-env-files.js"; |
| 18 | +import { copyCacheAssets } from "./open-next/copyCacheAssets.js"; |
| 19 | +import { createServerBundle } from "./open-next/createServerBundle.js"; |
| 20 | +import { |
| 21 | + createOpenNextConfigIfNotExistent, |
| 22 | + createWranglerConfigIfNotExistent, |
| 23 | + ensureCloudflareConfig, |
| 24 | +} from "./utils/index.js"; |
| 25 | + |
| 26 | +/** |
| 27 | + * Builds the application in a format that can be passed to workerd |
| 28 | + * |
| 29 | + * It saves the output in a `.worker-next` directory |
| 30 | + * |
| 31 | + * @param projectOpts The options for the project |
| 32 | + */ |
| 33 | +export async function build(projectOpts: ProjectOptions): Promise<void> { |
| 34 | + printHeader("Cloudflare build"); |
| 35 | + |
| 36 | + showWarningOnWindows(); |
| 37 | + |
| 38 | + const baseDir = projectOpts.sourceDir; |
| 39 | + const require = createRequire(import.meta.url); |
| 40 | + const openNextDistDir = dirname(require.resolve("@opennextjs/aws/index.js")); |
| 41 | + |
| 42 | + await createOpenNextConfigIfNotExistent(projectOpts); |
| 43 | + |
| 44 | + const { config, buildDir } = await compileOpenNextConfig(baseDir); |
| 45 | + |
| 46 | + ensureCloudflareConfig(config); |
| 47 | + |
| 48 | + // Initialize options |
| 49 | + const options = buildHelper.normalizeOptions(config, openNextDistDir, buildDir); |
| 50 | + logger.setLevel(options.debug ? "debug" : "info"); |
| 51 | + |
| 52 | + // Do not minify the code so that we can apply string replacement patch. |
| 53 | + // Note that wrangler will still minify the bundle. |
| 54 | + options.minify = false; |
| 55 | + |
| 56 | + // Pre-build validation |
| 57 | + buildHelper.checkRunningInsideNextjsApp(options); |
| 58 | + logger.info(`App directory: ${options.appPath}`); |
| 59 | + buildHelper.printNextjsVersion(options); |
| 60 | + ensureNextjsVersionSupported(options); |
| 61 | + buildHelper.printOpenNextVersion(options); |
| 62 | + |
| 63 | + if (projectOpts.skipNextBuild) { |
| 64 | + logger.warn("Skipping Next.js build"); |
| 65 | + } else { |
| 66 | + // Build the next app |
| 67 | + printHeader("Building Next.js app"); |
| 68 | + setStandaloneBuildMode(options); |
| 69 | + buildNextjsApp(options); |
| 70 | + } |
| 71 | + |
| 72 | + if (!containsDotNextDir(projectOpts.sourceDir)) { |
| 73 | + throw new Error(`.next folder not found in ${projectOpts.sourceDir}`); |
| 74 | + } |
| 75 | + |
| 76 | + // Generate deployable bundle |
| 77 | + printHeader("Generating bundle"); |
| 78 | + buildHelper.initOutputDir(options); |
| 79 | + |
| 80 | + // Compile cache.ts |
| 81 | + compileCache(options); |
| 82 | + |
| 83 | + // Compile .env files |
| 84 | + compileEnvFiles(options); |
| 85 | + |
| 86 | + // Compile middleware |
| 87 | + await createMiddleware(options, { forceOnlyBuildOnce: true }); |
| 88 | + |
| 89 | + createStaticAssets(options); |
| 90 | + |
| 91 | + if (config.dangerous?.disableIncrementalCache !== true) { |
| 92 | + createCacheAssets(options); |
| 93 | + copyCacheAssets(options); |
| 94 | + } |
| 95 | + |
| 96 | + await createServerBundle(options); |
| 97 | + |
| 98 | + // TODO: drop this copy. |
| 99 | + // Copy the .next directory to the output directory so it can be mutated. |
| 100 | + cpSync(join(projectOpts.sourceDir, ".next"), join(projectOpts.outputDir, ".next"), { recursive: true }); |
| 101 | + |
| 102 | + const projConfig = getConfig(projectOpts); |
| 103 | + |
| 104 | + // TODO: rely on options only. |
| 105 | + await bundleServer(projConfig, options); |
| 106 | + |
| 107 | + if (!projectOpts.skipWranglerConfigCheck) { |
| 108 | + await createWranglerConfigIfNotExistent(projectOpts); |
| 109 | + } |
| 110 | + |
| 111 | + logger.info("OpenNext build complete."); |
| 112 | +} |
| 113 | + |
| 114 | +function ensureNextjsVersionSupported(options: buildHelper.BuildOptions) { |
| 115 | + if (buildHelper.compareSemver(options.nextVersion, "14.0.0") < 0) { |
| 116 | + logger.error("Next.js version unsupported, please upgrade to version 14 or greater."); |
| 117 | + process.exit(1); |
| 118 | + } |
| 119 | +} |
0 commit comments