-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
build.impl.ts
118 lines (103 loc) · 3.95 KB
/
build.impl.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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 { copySync, existsSync, mkdir, writeFileSync } from 'fs-extra';
import { gte } from 'semver';
import { directoryExists } from '@nx/workspace/src/utilities/fileutils';
import { checkAndCleanWithSemver } from '@nx/devkit/src/utils/semver';
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 { createCliOptions } from '../../utils/create-cli-options';
export default async function buildExecutor(
options: NextBuildBuilderOptions,
context: ExecutorContext
) {
// Cast to any to overwrite NODE_ENV
(process.env as any).NODE_ENV ||= 'production';
const projectRoot = context.projectGraph.nodes[context.projectName].data.root;
checkPublicDirectory(projectRoot);
// Set `__NEXT_REACT_ROOT` based on installed ReactDOM version
const packageJsonPath = join(projectRoot, 'package.json');
const packageJson = existsSync(packageJsonPath)
? readJsonFile(packageJsonPath)
: undefined;
const rootPackageJson = readJsonFile(join(context.root, 'package.json'));
const reactDomVersion =
packageJson?.dependencies?.['react-dom'] ??
rootPackageJson.dependencies?.['react-dom'];
const hasReact18 =
reactDomVersion &&
gte(checkAndCleanWithSemver('react-dom', reactDomVersion), '18.0.0');
if (hasReact18) {
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);
} catch (error) {
logger.error(`Error occurred while trying to run the ${command}`);
logger.error(error);
return { success: false };
}
if (!directoryExists(options.outputPath)) {
mkdir(options.outputPath);
}
const builtPackageJson = createPackageJson(
context.projectName,
context.projectGraph,
{
target: context.targetName,
root: context.root,
isProduction: !options.includeDevDependenciesInPackageJson, // By default we remove devDependencies since this is a production build.
}
);
// Update `package.json` to reflect how users should run the build artifacts
builtPackageJson.scripts = {
start: 'next start',
};
updatePackageJson(builtPackageJson, context);
writeJsonFile(`${options.outputPath}/package.json`, builtPackageJson);
if (options.generateLockfile) {
const lockFile = createLockFile(builtPackageJson);
writeFileSync(`${options.outputPath}/${getLockFileName()}`, lockFile, {
encoding: 'utf-8',
});
}
// If output path is different from source path, then copy over the config and public files.
// This is the default behavior when running `nx build <app>`.
if (options.outputPath.replace(/\/$/, '') !== projectRoot) {
createNextConfigFile(options, context);
copySync(join(projectRoot, 'public'), join(options.outputPath, 'public'), {
dereference: true,
});
}
return { success: true };
}