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

executors.mddocs/

Task Execution

Task execution system for running executors, parsing targets, and integrating with Nx's task graph for intelligent build orchestration.

Capabilities

Executor Execution

Run executors programmatically with full context and option support.

/**
 * Run an executor with the specified target and options
 * @param targetDescription - Target specification (project:target:configuration)
 * @param options - Executor options
 * @param context - Execution context
 * @returns Async iterator of execution results
 */
function runExecutor<T = any>(
  targetDescription: Target,
  options: T,
  context: ExecutorContext
): Promise<AsyncIterableIterator<any>>;

/**
 * Target specification interface
 */
interface Target {
  /** Project name */
  project: string;
  /** Target name within the project */
  target: string;
  /** Optional configuration variant */
  configuration?: string;
}

/**
 * Context provided to executors during execution
 */
interface ExecutorContext {
  /** Workspace root directory */
  root: string;
  /** Current working directory */
  cwd: string;
  /** Complete workspace configuration */
  workspace: WorkspaceJsonConfiguration;
  /** Whether verbose logging is enabled */
  isVerbose: boolean;
  /** Currently executing project name */
  projectName?: string;
  /** Currently executing target name */
  targetName?: string;
  /** Currently executing configuration name */
  configurationName?: string;
  /** Project graph for dependency analysis */
  projectGraph?: ProjectGraph;
  /** Name of the task runner being used */
  taskRunner?: string;
}

Usage Examples:

import { runExecutor, ExecutorContext } from "@nx/devkit";

async function buildProject(context: ExecutorContext) {
  const target = {
    project: "my-app",
    target: "build",
    configuration: "production"
  };
  
  const options = {
    outputPath: "dist/my-app",
    optimization: true,
    sourceMap: false
  };
  
  // Run the build executor
  const result = await runExecutor(target, options, context);
  
  // Process results
  for await (const res of result) {
    if (res.success) {
      console.log("Build succeeded");
    } else {
      console.error("Build failed:", res.error);
    }
  }
}

Target String Parsing

Parse and format target strings for programmatic target manipulation.

/**
 * Parse a target string into component parts
 * @param targetString - String in format "project:target:configuration"
 * @param executorContext - Execution context for project validation
 * @returns Parsed target object
 */
function parseTargetString(
  targetString: string,
  executorContext: ExecutorContext
): Target;

/**
 * Convert target object to string representation
 * @param target - Target object to convert
 * @returns String in format "project:target:configuration"
 */
function targetToTargetString(target: Target): string;

Usage Examples:

import { parseTargetString, targetToTargetString, ExecutorContext } from "@nx/devkit";

function processTargets(context: ExecutorContext) {
  // Parse target strings
  const buildTarget = parseTargetString("my-app:build:production", context);
  console.log(buildTarget); // { project: "my-app", target: "build", configuration: "production" }
  
  const testTarget = parseTargetString("my-lib:test", context);
  console.log(testTarget); // { project: "my-lib", target: "test" }
  
  // Convert back to strings
  const buildString = targetToTargetString(buildTarget);
  console.log(buildString); // "my-app:build:production"
  
  const testString = targetToTargetString(testTarget);
  console.log(testString); // "my-lib:test"
}

Target Options Resolution

Read and resolve target options with configuration merging and inheritance.

/**
 * Read and combine options for a given target
 * Merges default options with configuration-specific options
 * @param target - Target specification
 * @param context - Execution context
 * @returns Resolved target options
 */
function readTargetOptions<T = any>(
  target: Target,
  context: ExecutorContext
): T;

Usage Examples:

import { readTargetOptions, ExecutorContext, Target } from "@nx/devkit";

function getResolvedOptions(context: ExecutorContext) {
  const target: Target = {
    project: "my-app", 
    target: "build",
    configuration: "production"
  };
  
  // Get merged options for the target
  const options = readTargetOptions(target, context);
  
  console.log("Resolved build options:", options);
  // Result includes:
  // - Base options from target.options
  // - Configuration-specific options from target.configurations.production
  // - Any inherited or computed values
}

Executor Types

Core Executor Interfaces

/**
 * Standard executor function signature
 * Returns iterator of execution results
 */
type Executor<T = any> = (
  options: T,
  context: ExecutorContext
) => Promise<{ success: boolean; [key: string]: any }> | AsyncIterableIterator<{ success: boolean; [key: string]: any }>;

/**
 * Promise-based executor signature
 * Returns single result promise
 */
type PromiseExecutor<T = any> = (
  options: T,
  context: ExecutorContext
) => Promise<{ success: boolean; [key: string]: any }>;

/**
 * Async iterator executor signature
 * Yields multiple results during execution
 */
type AsyncIteratorExecutor<T = any> = (
  options: T,
  context: ExecutorContext
) => AsyncIterableIterator<{ success: boolean; [key: string]: any }>;

/**
 * Task graph-aware executor signature
 * Has access to the complete task graph
 */
type TaskGraphExecutor<T = any> = (
  taskGraph: TaskGraph,
  options: Record<string, T>,
  overrides: T,
  context: ExecutorContext
) => Promise<Record<string, { success: boolean; [key: string]: any }>>;

Executor Configuration

/**
 * Schema definition for executors.json
 */
interface ExecutorsJson {
  executors?: Record<string, ExecutorDescription>;
  builders?: Record<string, ExecutorDescription>; // Legacy support
}

interface ExecutorDescription {
  /** Path to executor implementation */
  implementation?: string;
  /** Path to schema JSON file */
  schema?: string;
  /** Whether executor is hidden from help */
  hidden?: boolean;
  /** Description of the executor */
  description?: string;
}

Custom Hashing

/**
 * Custom hasher interface for cache key generation
 */
interface CustomHasher {
  (task: Task, context: HasherContext): Promise<Hash> | Hash;
}

/**
 * Context provided to custom hashers
 */
interface HasherContext {
  hasher: Hasher;
  projectGraph: ProjectGraph;
  taskGraph: TaskGraph;
  workspaceConfig: WorkspaceJsonConfiguration;
}

type Hash = string;

Framework Integration

/**
 * Convert Nx executor to Angular DevKit builder
 * @param executor - Nx executor function
 * @returns Angular DevKit builder
 */
function convertNxExecutor(executor: Executor): any;

Advanced Executor Patterns

Streaming Results

// Example executor that yields multiple results
export default async function* myExecutor(
  options: MyExecutorOptions,
  context: ExecutorContext
): AsyncIterableIterator<{ success: boolean; [key: string]: any }> {
  
  yield { success: false, message: "Starting compilation..." };
  
  try {
    // Perform compilation steps
    const compilationResult = await compile(options);
    yield { success: true, message: "Compilation complete" };
    
    // Perform additional steps
    const optimizationResult = await optimize(compilationResult);
    yield { success: true, message: "Optimization complete", artifacts: optimizationResult };
    
  } catch (error) {
    yield { success: false, error: error.message };
  }
}

Task Dependencies

// Example using task dependencies in executor context
export default async function myExecutor(
  options: MyExecutorOptions,
  context: ExecutorContext
): Promise<{ success: boolean }> {
  
  // Access project graph for dependency analysis
  const projectGraph = context.projectGraph;
  const dependencies = projectGraph?.dependencies[context.projectName!] || [];
  
  // Run dependency targets first
  for (const dep of dependencies) {
    const depTarget = { project: dep.target, target: "build" };
    await runExecutor(depTarget, {}, context);
  }
  
  // Run main task
  const result = await performMainTask(options);
  return { success: result.success };
}

Configuration Inheritance

// Example of complex option resolution
function resolveExecutorOptions(
  target: Target, 
  context: ExecutorContext
): ResolvedOptions {
  
  const baseOptions = readTargetOptions(target, context);
  
  // Apply environment-specific overrides
  const envOverrides = process.env.NODE_ENV === 'production' 
    ? { optimize: true, minify: true }
    : { sourceMap: true, watch: true };
    
  return {
    ...baseOptions,
    ...envOverrides
  };
}

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