@nx/next
Version:
202 lines (201 loc) • 8.16 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createNodesV2 = exports.createNodes = exports.createDependencies = void 0;
const internal_1 = require("@nx/devkit/internal");
const devkit_1 = require("@nx/devkit");
const js_1 = require("@nx/js");
const internal_2 = require("@nx/js/internal");
const fs_1 = require("fs");
const devkit_internals_1 = require("nx/src/devkit-internals");
const cache_directory_1 = require("nx/src/utils/cache-directory");
const path_1 = require("path");
const nextConfigBlob = '**/next.config.{ts,js,cjs,mjs}';
/**
* @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
*/
const createDependencies = () => {
return [];
};
exports.createDependencies = createDependencies;
exports.createNodes = [
nextConfigBlob,
async (configFiles, options, context) => {
const optionsHash = (0, devkit_internals_1.hashObject)(options);
const cachePath = (0, path_1.join)(cache_directory_1.workspaceDataDirectory, `next-${optionsHash}.json`);
const targetsCache = new internal_1.PluginCache(cachePath);
const isTsSolutionSetup = (0, internal_2.isUsingTsSolutionSetup)();
const packageManager = (0, devkit_1.detectPackageManager)(context.workspaceRoot);
const pmc = (0, devkit_1.getPackageManagerCommand)(packageManager);
const lockFileName = (0, js_1.getLockFileName)(packageManager);
const normalizedOptions = normalizeOptions(options);
try {
const { entries, preErrors } = await filterNextConfigs(configFiles, context);
const projectHashes = await (0, internal_1.calculateHashesForCreateNodes)(entries.map((e) => e.projectRoot), normalizedOptions, context, entries.map(() => [lockFileName]));
let results = [];
let nodeErrors = [];
try {
results = await (0, devkit_1.createNodesFromFiles)((configFile, _, ctx, idx) => createNodesInternal(configFile, normalizedOptions, ctx, targetsCache, isTsSolutionSetup, pmc, projectHashes[idx]), entries.map((e) => e.configFile), options, context);
}
catch (e) {
if (e instanceof devkit_1.AggregateCreateNodesError) {
results = e.partialResults ?? [];
nodeErrors = e.errors;
}
else {
throw e;
}
}
const allErrors = [...preErrors, ...nodeErrors];
if (allErrors.length > 0) {
throw new devkit_1.AggregateCreateNodesError(allErrors, results);
}
return results;
}
finally {
targetsCache.writeToDisk();
}
},
];
exports.createNodesV2 = exports.createNodes;
async function createNodesInternal(configFilePath, options, context, targetsCache, isTsSolutionSetup, pmc, hash) {
const projectRoot = (0, path_1.dirname)(configFilePath);
if (!targetsCache.has(hash)) {
targetsCache.set(hash, await buildNextTargets(configFilePath, projectRoot, options, context, isTsSolutionSetup, pmc));
}
return {
projects: {
[projectRoot]: {
root: projectRoot,
targets: targetsCache.get(hash),
},
},
};
}
async function buildNextTargets(nextConfigPath, projectRoot, options, context, isTsSolutionSetup, pmc) {
const nextConfig = await getNextConfig(nextConfigPath, context);
const namedInputs = (0, internal_1.getNamedInputs)(projectRoot, context);
const targets = {};
targets[options.buildTargetName] = await getBuildTargetConfig(namedInputs, projectRoot, nextConfig, isTsSolutionSetup);
targets[options.devTargetName] = getDevTargetConfig(projectRoot, isTsSolutionSetup);
const startTarget = getStartTargetConfig(options, projectRoot);
targets[options.startTargetName] = startTarget;
targets[options.serveStaticTargetName] = startTarget;
(0, internal_2.addBuildAndWatchDepsTargets)(context.workspaceRoot, projectRoot, targets, options, pmc);
return targets;
}
async function getBuildTargetConfig(namedInputs, projectRoot, nextConfig, isTsSolutionSetup) {
const nextOutputPath = await getOutputs(projectRoot, nextConfig);
// Set output path here so that `withNx` can pick it up.
const targetConfig = {
command: `next build`,
options: {
cwd: projectRoot,
},
dependsOn: ['^build'],
cache: true,
inputs: getInputs(namedInputs),
outputs: [`${nextOutputPath}/!(cache)/**/*`, `${nextOutputPath}/!(cache)`],
};
// v14/v15/v16 all emit the same `next build` inferred target shape - no per-major branch needed.
// The tty=false is not version-specific: Next.js exits 0 on SIGINT regardless of major
// (https://github.com/vercel/next.js/issues/62906). Turbopack-default-on (v16+) and other
// bundler differences live at the executor / runtime layer, not here.
targetConfig.options.tty = false;
if (isTsSolutionSetup) {
targetConfig.syncGenerators = ['@nx/js:typescript-sync'];
}
return targetConfig;
}
function getDevTargetConfig(projectRoot, isTsSolutionSetup) {
const targetConfig = {
continuous: true,
command: `next dev`,
options: {
cwd: projectRoot,
},
};
if (isTsSolutionSetup) {
targetConfig.syncGenerators = ['@nx/js:typescript-sync'];
}
return targetConfig;
}
function getStartTargetConfig(options, projectRoot) {
const targetConfig = {
continuous: true,
command: `next start`,
options: {
cwd: projectRoot,
},
dependsOn: [options.buildTargetName],
};
return targetConfig;
}
async function getOutputs(projectRoot, nextConfig) {
let dir = '.next';
const { PHASE_PRODUCTION_BUILD } = require('next/constants');
if (typeof nextConfig === 'function') {
// Works for both async and sync functions.
const configResult = await Promise.resolve(nextConfig(PHASE_PRODUCTION_BUILD, { defaultConfig: {} }));
if (configResult?.distDir) {
dir = configResult?.distDir;
}
}
else if (typeof nextConfig === 'object' && nextConfig?.distDir) {
// If nextConfig is an object, directly use its 'distDir' property.
dir = nextConfig.distDir;
}
if (projectRoot === '.') {
return `{projectRoot}/${dir}`;
}
else {
return `{workspaceRoot}/${projectRoot}/${dir}`;
}
}
function getNextConfig(configFilePath, context) {
const resolvedPath = (0, path_1.join)(context.workspaceRoot, configFilePath);
return (0, internal_1.loadConfigFile)(resolvedPath);
}
async function filterNextConfigs(configFiles, context) {
const preErrors = [];
const candidates = await Promise.all(configFiles.map(async (configFile) => {
try {
const projectRoot = (0, path_1.dirname)(configFile);
const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot));
if (!siblingFiles.includes('package.json') &&
!siblingFiles.includes('project.json')) {
return null;
}
return { configFile, projectRoot };
}
catch (e) {
preErrors.push([configFile, e]);
return null;
}
}));
return {
entries: candidates.filter((c) => c !== null),
preErrors,
};
}
function normalizeOptions(options) {
options ??= {};
options.buildTargetName ??= 'build';
options.devTargetName ??= 'dev';
options.startTargetName ??= 'start';
options.serveStaticTargetName ??= 'serve-static';
return options;
}
function getInputs(namedInputs) {
return [
...('production' in namedInputs
? ['default', '^default']
: ['default', '^default']),
{
externalDependencies: ['next'],
},
{
dependentTasksOutputFiles: '**/*.d.ts',
transitive: true,
},
];
}