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

177 lines (176 loc) • 7.48 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.createNodes = exports.createNodesV2 = exports.createDependencies = void 0; const devkit_1 = require("@nx/devkit"); const path_1 = require("path"); const get_named_inputs_1 = require("@nx/devkit/src/utils/get-named-inputs"); const fs_1 = require("fs"); const cache_directory_1 = require("nx/src/utils/cache-directory"); const calculate_hash_for_create_nodes_1 = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes"); const js_1 = require("@nx/js"); const config_utils_1 = require("@nx/devkit/src/utils/config-utils"); const devkit_internals_1 = require("nx/src/devkit-internals"); const util_1 = require("@nx/js/src/plugins/typescript/util"); 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.createNodesV2 = [ 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); try { return await (0, devkit_1.createNodesFromFiles)((configFile, options, context) => createNodesInternal(configFile, options, context, targetsCache), configFiles, options, context); } finally { writeTargetsToCache(cachePath, targetsCache); } }, ]; /** * @deprecated This is replaced with {@link createNodesV2}. Update your plugin to export its own `createNodesV2` function that wraps this one instead. * This function will change to the v2 function in Nx 21. */ exports.createNodes = [ nextConfigBlob, async (configFilePath, options, context) => { devkit_1.logger.warn('`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 21, this will change to the createNodesV2 API.'); 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 result = await createNodesInternal(configFilePath, options, context, targetsCache); writeTargetsToCache(cachePath, targetsCache); return result; }, ]; async function createNodesInternal(configFilePath, options, context, targetsCache) { 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); return { projects: { [projectRoot]: { root: projectRoot, targets: targetsCache[hash], }, }, }; } async function buildNextTargets(nextConfigPath, projectRoot, options, context) { 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); targets[options.devTargetName] = getDevTargetConfig(projectRoot); 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) { 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; return targetConfig; } function getDevTargetConfig(projectRoot) { const targetConfig = { continuous: true, command: `next dev`, options: { cwd: projectRoot, }, }; 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'], }, ]; }