CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nx--devkit

The Nx Devkit provides utilities for creating custom generators, executors, and plugins to extend the Nx build system for different technologies and use cases.

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

package-management.mddocs/

Package Management

Package management utilities for adding dependencies, managing package.json files, and ensuring required packages are available across npm, yarn, and pnpm.

Capabilities

Dependency Management

Add and remove dependencies from package.json with intelligent version resolution and conflict handling.

/**
 * Add dependencies and devDependencies to package.json
 * Handles version conflicts and prevents duplicate dependencies
 * @param tree - File system tree
 * @param dependencies - Production dependencies to add
 * @param devDependencies - Development dependencies to add  
 * @param packageJsonPath - Path to package.json (defaults to root)
 * @param keepExistingVersions - Prevent upgrading existing packages
 * @returns Callback to install packages
 */
function addDependenciesToPackageJson(
  tree: Tree,
  dependencies: Record<string, string>,
  devDependencies: Record<string, string>,
  packageJsonPath?: string,
  keepExistingVersions?: boolean
): GeneratorCallback;

/**
 * Remove dependencies from package.json
 * @param tree - File system tree
 * @param dependencies - Production dependencies to remove
 * @param devDependencies - Development dependencies to remove
 * @param packageJsonPath - Path to package.json (defaults to root)
 * @returns Callback to run package manager operations
 */
function removeDependenciesFromPackageJson(
  tree: Tree,
  dependencies: string[],
  devDependencies: string[],
  packageJsonPath?: string
): GeneratorCallback;

Usage Examples:

import { 
  Tree,
  addDependenciesToPackageJson,
  removeDependenciesFromPackageJson,
  GeneratorCallback
} from "@nx/devkit";

export default function myGenerator(tree: Tree): GeneratorCallback {
  // Add React dependencies
  const addDepsTask = addDependenciesToPackageJson(
    tree,
    {
      "react": "^18.2.0",
      "react-dom": "^18.2.0"
    },
    {
      "@types/react": "^18.0.15",
      "@types/react-dom": "^18.0.6",
      "@testing-library/react": "^13.3.0"
    }
  );

  // Remove old dependencies
  const removeDepsTask = removeDependenciesFromPackageJson(
    tree,
    ["lodash"], // Remove from dependencies
    ["@types/lodash"] // Remove from devDependencies
  );

  // Return combined task
  return async () => {
    await addDepsTask();
    await removeDepsTask();
  };
}

Package Installation

Manage package installation tasks and ensure required packages are available.

/**
 * Create a task to install packages using the detected package manager
 * @param tree - File system tree
 * @param alwaysRun - Force installation even if no changes detected
 * @param cwd - Working directory for installation
 * @param packageManager - Specific package manager to use
 */
function installPackagesTask(
  tree: Tree,
  alwaysRun?: boolean,
  cwd?: string,
  packageManager?: PackageManager
): void;

/**
 * Ensure a package is installed and available for use
 * Installs the package temporarily if not found
 * @param pkg - Package name to ensure
 * @param version - Version to install if missing
 * @returns The required package module or null for ESM packages
 */
function ensurePackage<T = any>(pkg: string, version: string): T;

/**
 * Current version of Nx being used
 */
const NX_VERSION: string;

Usage Examples:

import { 
  Tree,
  installPackagesTask,
  ensurePackage,
  NX_VERSION
} from "@nx/devkit";

export default function myGenerator(tree: Tree) {
  // Schedule package installation
  installPackagesTask(tree);
  
  // Ensure a specific package is available
  try {
    const chalk = ensurePackage("chalk", "^4.1.0");
    console.log(chalk.green("Package is available!"));
  } catch (error) {
    console.error("Failed to ensure package:", error.message);
  }
  
  // Use current Nx version
  console.log(`Using Nx version: ${NX_VERSION}`);
}

Package Manager Detection

Detect and work with different package managers (npm, yarn, pnpm).

/**
 * Detect which package manager is being used in the workspace
 * @param dir - Directory to check (defaults to workspace root)
 * @returns Detected package manager
 */
function detectPackageManager(dir?: string): PackageManager;

/**
 * Get commands for the specified package manager
 * @param packageManager - Package manager to get commands for
 * @returns Object with package manager commands
 */
function getPackageManagerCommand(packageManager?: PackageManager): {
  install: string;
  add: string;
  addDev: string;
  rm: string;
  exec: string;
  dlx: string;
  list: string;
  run: (script: string, args?: string) => string;
  preInstall?: string;
};

/**
 * Get version of the specified package manager
 * @param packageManager - Package manager to check
 * @returns Version string
 */
function getPackageManagerVersion(packageManager?: PackageManager): string;

/**
 * Check if workspaces are enabled for the package manager
 * @param packageManager - Package manager to check
 * @param root - Workspace root directory
 * @returns Whether workspaces are enabled
 */
function isWorkspacesEnabled(
  packageManager: PackageManager,
  root: string
): boolean;

/**
 * Supported package managers
 */
type PackageManager = "npm" | "yarn" | "pnpm";

Usage Examples:

import {
  detectPackageManager,
  getPackageManagerCommand,
  getPackageManagerVersion,
  isWorkspacesEnabled,
  workspaceRoot
} from "@nx/devkit";

function setupPackageManager() {
  // Detect current package manager
  const pm = detectPackageManager();
  console.log(`Using package manager: ${pm}`);
  
  // Get package manager commands
  const commands = getPackageManagerCommand(pm);
  console.log(`Install command: ${commands.install}`);
  console.log(`Add dev dependency: ${commands.addDev}`);
  
  // Check version
  const version = getPackageManagerVersion(pm);
  console.log(`${pm} version: ${version}`);
  
  // Check workspace support
  const workspacesEnabled = isWorkspacesEnabled(pm, workspaceRoot);
  console.log(`Workspaces enabled: ${workspacesEnabled}`);
  
  // Run package manager commands
  const { execSync } = require("child_process");
  
  // Install dependencies
  execSync(commands.install, { cwd: workspaceRoot, stdio: "inherit" });
  
  // Add a new dependency
  execSync(`${commands.add} lodash@^4.17.21`, { 
    cwd: workspaceRoot, 
    stdio: "inherit" 
  });
  
  // Run a script
  const testCommand = commands.run("test", "--coverage");
  execSync(testCommand, { cwd: workspaceRoot, stdio: "inherit" });
}

Advanced Package Management

Version Resolution Strategy

The dependency management functions use intelligent version resolution:

  1. Conflict Prevention: Dependencies in devDependencies won't be added to dependencies if they already exist
  2. Version Upgrading: By default, higher versions replace lower versions
  3. Version Preservation: Use keepExistingVersions: true to prevent version bumps
  4. Semver Handling: Supports standard semver ranges and special tags like "latest", "next"
// Example of complex dependency management
export default function myGenerator(tree: Tree) {
  const addDepsTask = addDependenciesToPackageJson(
    tree,
    {
      "react": "^18.2.0",      // Will upgrade from ^17.x.x
      "lodash": "latest",      // Uses latest tag
      "moment": "~2.29.0"      // Patch-level updates only
    },
    {
      "@types/react": "^18.0.15",
      "typescript": "next"      // Uses next tag
    },
    "package.json",
    false // Allow version upgrades
  );
  
  return addDepsTask;
}

Monorepo Package Management

Working with packages in monorepo environments:

// Add dependencies to a specific project
export default function addToProject(tree: Tree, options: { project: string }) {
  const projectConfig = readProjectConfiguration(tree, options.project);
  const packageJsonPath = `${projectConfig.root}/package.json`;
  
  const addDepsTask = addDependenciesToPackageJson(
    tree,
    { "axios": "^1.0.0" },
    { "@types/axios": "^1.0.0" },
    packageJsonPath // Project-specific package.json
  );
  
  return addDepsTask;
}

Package Manager Configuration

// Configure package manager behavior
function configurePackageManager(tree: Tree, packageManager: PackageManager) {
  const nxJson = readNxJson(tree);
  
  updateNxJson(tree, {
    ...nxJson,
    cli: {
      ...nxJson?.cli,
      packageManager: packageManager
    }
  });
  
  // Create package manager specific configuration files
  switch (packageManager) {
    case "yarn":
      if (getPackageManagerVersion("yarn").startsWith("3.")) {
        tree.write(".yarnrc.yml", "nodeLinker: node-modules\nenableScripts: false");
      }
      break;
    case "pnpm":
      tree.write(".npmrc", "shamefully-hoist=true");
      break;
  }
}

Dynamic Package Loading

// Dynamically load packages with fallback handling
async function loadPackageDynamic<T>(packageName: string, version: string): Promise<T | null> {
  try {
    // Try to require the package
    return require(packageName);
  } catch (error) {
    if (error.code === 'MODULE_NOT_FOUND') {
      // Package not found, ensure it's available
      const pkg = ensurePackage<T>(packageName, version);
      return pkg;
    } else if (error.code === 'ERR_REQUIRE_ESM') {
      // ESM package, use dynamic import
      const pkg = await import(packageName);
      return pkg.default || pkg;
    }
    throw error;
  }
}

// Usage example
export default async function myGenerator(tree: Tree) {
  // Load chalk dynamically
  const chalk = await loadPackageDynamic("chalk", "^4.1.0");
  if (chalk) {
    console.log(chalk.green("Successfully loaded chalk!"));
  }
  
  // Load an ESM package
  const prettier = await loadPackageDynamic("prettier", "^2.8.0");
  if (prettier) {
    const formatted = await prettier.format("const x=1;", { parser: "typescript" });
    console.log("Formatted code:", formatted);
  }
}

Install with Tessl CLI

npx tessl i tessl/npm-nx--devkit

docs

executors.md

generators.md

index.md

package-management.md

plugin-development.md

project-graph.md

tree-operations.md

utilities.md

workspace-configuration.md

tile.json