diff --git a/src/commands/build/nextjs/index.ts b/src/commands/build/nextjs/index.ts index f46ce5e..e99f2a7 100644 --- a/src/commands/build/nextjs/index.ts +++ b/src/commands/build/nextjs/index.ts @@ -1,8 +1,10 @@ import {Flags} from '@oclif/core' import {format} from "node:util"; +import {type Stats} from "node:fs"; import * as path from 'node:path'; import * as cp from 'node:child_process'; import * as fs from 'node:fs/promises'; +import {CommandError} from "@oclif/core/interfaces"; import {safely} from "../../../lib/utils.js"; import {BaseCommand} from "../../../baseCommand.js"; @@ -28,6 +30,8 @@ export default class Build extends BaseCommand { }), } + private configFilePaths: undefined | { original: string, config: string }; + async run(): Promise { const {args, flags} = await this.parse(Build) @@ -43,6 +47,12 @@ export default class Build extends BaseCommand { this.error(`Project directory is not a valid directory: ${projectDirPath}`); } + const buildCommand = flags.buildCommand; + const buildCommandParts = buildCommand.split(' '); + if (buildCommandParts.length === 0) { + this.error('Invalid build command'); + } + const [errorWithChangingDir, changedDir] = await safely(() => process.chdir(projectDirPath)); if (errorWithChangingDir) { this.error(`Error changing directory: ${errorWithChangingDir.message}`); @@ -89,6 +99,19 @@ export default class Build extends BaseCommand { const isConfigFileAModule = existingConfigFileInfo.filePath.endsWith('.mjs') || packageJson.type === 'module'; + const originalConfigFilePath = configFilePath + '.original'; + // check if original config file exists + const [errorWithCheckingOriginalConfigFileStats, originalConfigFileStats] = await safely(fs.stat(originalConfigFilePath)); + if (errorWithCheckingOriginalConfigFileStats && errorWithCheckingOriginalConfigFileStats.code !== 'ENOENT') { + this.error(`Error checking original config file: ${errorWithCheckingOriginalConfigFileStats.message}`); + } + if (originalConfigFileStats) { + this.error(`Original config file already exists: ${originalConfigFilePath}`); + } + // read the config file const [errorWithImportingConfig, importedConfigExports] = await safely(import(configFilePath)); if (errorWithImportingConfig) { @@ -99,21 +122,21 @@ export default class Build extends BaseCommand { if (!nextJsConfig) { this.error('Config file must export a default object'); } - this.log(format('User config', nextJsConfig)); + this.debug(format('User config', nextJsConfig)); nextJsConfig.output = 'standalone'; nextJsConfig.experimental = nextJsConfig.experimental || (nextJsConfig.experimental = {}); nextJsConfig.cacheHandler = path.resolve(projectDirPath, 'node_modules/@tildacloud/cli/dist/nextJsCacheHandler.' + (isConfigFileAModule ? 'mjs' : 'cjs')); nextJsConfig.experimental.swrDelta = 60 * 60 * 24 * 7; // 1 week - this.log('Modified config:', nextJsConfig); + this.debug(format('Modified config:', nextJsConfig)); // copy the original config file to a new file with .original extension - const originalConfigFilePath = configFilePath + '.original'; const [errorWithCopyingConfigFile] = await safely(fs.copyFile(configFilePath, originalConfigFilePath)); if (errorWithCopyingConfigFile) { this.error(`Error copying config file: ${errorWithCopyingConfigFile.message}`); } + this.configFilePaths = {original: originalConfigFilePath, config: configFilePath}; const tildaConfigFileComment = '// This file is automatically generated by Tilda. If it is not removed automatically, please remove this file and restore Next.js config file with .original extension in its place.'; @@ -125,40 +148,43 @@ export default class Build extends BaseCommand { this.log('Wrote modified config file:', configFilePath); - const buildCommand = flags.buildCommand; this.log('Running build command:', JSON.stringify(buildCommand), 'in', projectDirPath); + const buildProgram = buildCommandParts[0]; + const buildArgs = buildCommandParts.slice(1); - const commandParts = buildCommand.split(' '); - if (commandParts.length === 0) { - this.error('Invalid build command'); - } - - const program = commandParts[0]; - const commandArgs = commandParts.slice(1); - - const [errorWithBuildCommand] = await safely(() => cp.execFileSync(program, commandArgs, { + const [errorWithBuildCommand] = await safely(() => cp.execFileSync(buildProgram, buildArgs, { cwd: projectDirPath, stdio: 'inherit', env: {...process.env} })); - - // restore the original config file - const [errorWithRestoringConfigFile] = await safely(fs.copyFile(originalConfigFilePath, configFilePath)); - if (errorWithRestoringConfigFile) { - this.error(`Error restoring config file: ${errorWithRestoringConfigFile.message}`); - } - // remove the original reference config file - const [errorWithRemovingOriginalConfigFile] = await safely(fs.rm(originalConfigFilePath)); - if (errorWithRemovingOriginalConfigFile) { - this.error(`Error removing original config file: ${errorWithRemovingOriginalConfigFile.message}`); - } - - this.log('Restored original config file:', configFilePath); - if (errorWithBuildCommand) { this.error(`Error running build command: ${errorWithBuildCommand.message}`); } this.log('Build complete'); + + await this.restoreConfigFile(); + } + + async catch(error: CommandError) { + await this.restoreConfigFile() + throw error; + } + + async restoreConfigFile() { + if (this.configFilePaths) { + // restore the original config file + const [errorWithRestoringConfigFile] = await safely(fs.copyFile(this.configFilePaths.original, this.configFilePaths.config)); + if (errorWithRestoringConfigFile) { + this.error(`Error restoring config file: ${errorWithRestoringConfigFile.message}`); + } + // remove the original reference config file + const [errorWithRemovingOriginalConfigFile] = await safely(fs.rm(this.configFilePaths.original)); + if (errorWithRemovingOriginalConfigFile) { + this.error(`Error removing original config file: ${errorWithRemovingOriginalConfigFile.message}`); + } + + this.log('Restored original config file:', this.configFilePaths.config); + } } }