fix(nextjs): make next build package manager agnostic (#18661)

This commit is contained in:
Nicholas Cunningham 2023-08-17 11:54:31 -06:00 committed by GitHub
parent 0b84bbcc75
commit 2e1bccd0c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,15 +1,13 @@
import 'dotenv/config';
import {
detectPackageManager,
ExecutorContext,
getPackageManagerVersion,
logger,
readJsonFile,
workspaceRoot,
writeJsonFile,
} from '@nx/devkit';
import { createLockFile, createPackageJson, getLockFileName } from '@nx/js';
import { join } from 'path';
import { join, resolve as pathResolve } from 'path';
import { copySync, existsSync, mkdir, writeFileSync } from 'fs-extra';
import { gte } from 'semver';
import { directoryExists } from '@nx/workspace/src/utilities/fileutils';
@ -19,9 +17,11 @@ import { updatePackageJson } from './lib/update-package-json';
import { createNextConfigFile } from './lib/create-next-config-file';
import { checkPublicDirectory } from './lib/check-project';
import { NextBuildBuilderOptions } from '../../utils/types';
import { execSync, ExecSyncOptions } from 'child_process';
import { ChildProcess, fork } from 'child_process';
import { createCliOptions } from '../../utils/create-cli-options';
let childProcess: ChildProcess;
export default async function buildExecutor(
options: NextBuildBuilderOptions,
context: ExecutorContext
@ -49,32 +49,16 @@ export default async function buildExecutor(
process.env['__NEXT_REACT_ROOT'] ||= 'true';
}
const { experimentalAppOnly, profile, debug, outputPath } = options;
// Set output path here since it can also be set via CLI
// We can retrieve it inside plugins/with-nx
process.env.NX_NEXT_OUTPUT_PATH ??= outputPath;
const args = createCliOptions({ experimentalAppOnly, profile, debug });
const isYarnBerry =
detectPackageManager() === 'yarn' &&
gte(getPackageManagerVersion('yarn', workspaceRoot), '2.0.0');
const buildCommand = isYarnBerry
? `yarn next build ${projectRoot}`
: 'npx next build';
const command = `${buildCommand} ${args.join(' ')}`;
const execSyncOptions: ExecSyncOptions = {
stdio: 'inherit',
encoding: 'utf-8',
cwd: projectRoot,
};
try {
execSync(command, execSyncOptions);
await runCliBuild(workspaceRoot, projectRoot, options);
} catch (error) {
logger.error(`Error occurred while trying to run the ${command}`);
logger.error(`Error occurred while trying to run the build command`);
logger.error(error);
return { success: false };
} finally {
if (childProcess) {
childProcess.kill();
}
}
if (!directoryExists(options.outputPath)) {
@ -116,3 +100,44 @@ export default async function buildExecutor(
}
return { success: true };
}
function runCliBuild(
workspaceRoot: string,
projectRoot: string,
options: NextBuildBuilderOptions
) {
const { experimentalAppOnly, profile, debug, outputPath } = options;
// Set output path here since it can also be set via CLI
// We can retrieve it inside plugins/with-nx
process.env.NX_NEXT_OUTPUT_PATH ??= outputPath;
const args = createCliOptions({ experimentalAppOnly, profile, debug });
return new Promise((resolve, reject) => {
childProcess = fork(
require.resolve('next/dist/bin/next'),
['build', ...args],
{
cwd: pathResolve(workspaceRoot, projectRoot),
stdio: 'inherit',
env: process.env,
}
);
// Ensure the child process is killed when the parent exits
process.on('exit', () => childProcess.kill());
process.on('SIGTERM', () => childProcess.kill());
childProcess.on('error', (err) => {
reject(err);
});
childProcess.on('exit', (code) => {
if (code === 0) {
resolve(code);
} else {
reject(code);
}
});
});
}