// @ts-check import path from "path"; import fs from "fs"; import { execSync, spawnSync } from "child_process"; require("dotenv").config({ path: path.resolve(__dirname, "../.env"), }); const isLocal = process.env.NEXT_PUBLIC_DSQL_LOCAL || null; const DIST_DIR = path.resolve(process.cwd(), "./.dist"); let PREV_BUILD_NO = "0"; const MAX_BUILDS = process.env.DSQL_MAX_BUILDS ? Number(process.env.DSQL_MAX_BUILDS) : 10; if ( MAX_BUILDS < 1 || Number.isNaN(MAX_BUILDS) || typeof MAX_BUILDS !== "number" ) { throw new Error("Invalid MAX_BUILDS"); } if (!fs.existsSync(DIST_DIR)) fs.mkdirSync(DIST_DIR); if (fs.existsSync(`${DIST_DIR}/BUILD`)) { PREV_BUILD_NO = fs.readFileSync(`${DIST_DIR}/BUILD`, "utf-8"); } else { fs.writeFileSync(`${DIST_DIR}/BUILD`, "0", "utf-8"); } try { const buildNumber = fs.readFileSync(`${DIST_DIR}/BUILD`, "utf-8"); const newBuildNumber = Number(buildNumber) + 1; if (newBuildNumber < 0) { throw new Error("Invalid Build Number"); } fs.writeFileSync(`${DIST_DIR}/BUILD`, String(newBuildNumber)); if (newBuildNumber > MAX_BUILDS) { const builds = fs.readdirSync(DIST_DIR); const buildDirs = builds.filter((build) => build.match(/build-\d+/)); for (const buildDir of buildDirs) { const buildDirPath = path.join(DIST_DIR, buildDir); const buildDirStat = fs.statSync(buildDirPath); if (buildDirStat.isDirectory()) { const buildDirName = buildDir.split("-")[1]; const buildDirNumber = Number(buildDirName); if (buildDirNumber <= newBuildNumber - MAX_BUILDS) { fs.rmdirSync(buildDirPath, { recursive: true }); console.log("Deleted Build Directory =>", buildDirPath); } } } } } catch (error: any) { console.log("Build Number Parse Error =>", error.message); process.exit(1); } /** @type {import('child_process').SpawnSyncOptionsWithStringEncoding} */ const spawnSyncOptions: import("child_process").SpawnSyncOptionsWithStringEncoding = { stdio: "inherit", encoding: "utf-8", shell: process.platform?.match(/win32/i) ? "bash.exe" : undefined, env: { ...process.env, BUILDING_APP: "true", }, }; const build = spawnSync("bunx", ["next", "build"], spawnSyncOptions); /** * @returns {string} */ function grabNewDistDir(): string { if (isLocal) return ".local_dist"; try { const buildNumber = fs.readFileSync(`${DIST_DIR}/BUILD`, "utf-8"); return `.dist/build-${buildNumber}`; } catch (/** @type {*} */ error: any) { console.log("Build Number Parse Error =>", error.message); process.exit(); } } const newDistDir = grabNewDistDir(); /** * # Revert Directories * @param {string} dir - New Build Directory Path */ function revert(dir: string) { console.log("Build Failed!", build?.error?.message || build.stderr); fs.writeFileSync(`${DIST_DIR}/BUILD`, PREV_BUILD_NO, "utf-8"); execSync(`rm -Rf ${dir}`, { cwd: process.cwd() }); const writeErr = build.error ? build.error.message : build.stderr ? build.stderr.toString() : "NO BUILD_ID found in New Build Folder"; fs.writeFileSync( `${DIST_DIR}/LAST_BUILD_FAIL`, Date() + "\n\n" + writeErr, "utf-8" ); process.exit(1); } if ( build.error || build.stderr || build.status != 0 || !fs.existsSync(`${newDistDir}/BUILD_ID`) ) { if (!isLocal) { revert(newDistDir); throw new Error("Build Failed!"); } } process.on("exit", () => { const onExitDir = grabNewDistDir(); if (!fs.existsSync(`${onExitDir}/BUILD_ID`) && !isLocal) { revert(onExitDir); } });