UNPKG

@nx/next

Version:

The Next.js plugin for Nx contains executors and generators for managing Next.js applications and libraries within an Nx workspace. It provides: - Scaffolding for creating, building, serving, linting, and testing Next.js applications. - Integration wit

170 lines (169 loc) • 7.14 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createNodesV2 = exports.createNodes = exports.createDependencies = void 0; const devkit_1 = require("@nx/devkit"); const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes"); const config_utils_1 = require("@nx/devkit/src/utils/config-utils"); const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs"); const js_1 = require("@nx/js"); const util_1 = require("@nx/js/src/plugins/typescript/util"); const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup"); 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 pmc = (0, devkit_1.getPackageManagerCommand)(); const nextConfigBlob = '**/next.config.{ts,js,cjs,mjs}'; function readTargetsCache(cachePath) { return (0, fs_1.existsSync)(cachePath) ? (0, devkit_1.readJsonFile)(cachePath) : {}; } function writeTargetsToCache(cachePath, targetsCache) { const oldCache = readTargetsCache(cachePath); (0, devkit_1.writeJsonFile)(cachePath, { ...oldCache, ...targetsCache, }); } /** * @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 = readTargetsCache(cachePath); const isTsSolutionSetup = (0, ts_solution_setup_1.isUsingTsSolutionSetup)(); try { return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => createNodesInternal(configFile, options, context, targetsCache, isTsSolutionSetup), configFiles, options, context); } finally { writeTargetsToCache(cachePath, targetsCache); } }, ]; exports.createNodesV2 = exports.createNodes; async function createNodesInternal(configFilePath, options, context, targetsCache, isTsSolutionSetup) { const projectRoot = (0, path_1.dirname)(configFilePath); // Do not create a project if package.json and project.json isn't there. const siblingFiles = (0, fs_1.readdirSync)((0, path_1.join)(context.workspaceRoot, projectRoot)); if (!siblingFiles.includes('package.json') && !siblingFiles.includes('project.json')) { return {}; } options = normalizeOptions(options); const hash = await (0, calculate_hash_for_create_nodes_1.calculateHashForCreateNodes)(projectRoot, options, context, [(0, js_1.getLockFileName)((0, devkit_1.detectPackageManager)(context.workspaceRoot))]); targetsCache[hash] ??= await buildNextTargets(configFilePath, projectRoot, options, context, isTsSolutionSetup); return { projects: { [projectRoot]: { root: projectRoot, targets: targetsCache[hash], }, }, }; } async function buildNextTargets(nextConfigPath, projectRoot, options, context, isTsSolutionSetup) { const nextConfig = await getNextConfig(nextConfigPath, context); const namedInputs = (0, get_named_inputs_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, util_1.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)`], }; // TODO(ndcunningham): Update this to be consider different versions of next.js which is running // This doesn't actually need to be tty, but next.js has a bug, https://github.com/vercel/next.js/issues/62906, where it exits 0 when SIGINT is sent. 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, config_utils_1.loadConfigFile)(resolvedPath); } 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', '^production'] : ['default', '^default']), { externalDependencies: ['next'], }, ]; }