The Nx Devkit provides utilities for creating custom generators, executors, and plugins to extend the Nx build system for different technologies and use cases.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Task execution system for running executors, parsing targets, and integrating with Nx's task graph for intelligent build orchestration.
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);
}
}
}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"
}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
}/**
* 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 }>>;/**
* 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 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;/**
* Convert Nx executor to Angular DevKit builder
* @param executor - Nx executor function
* @returns Angular DevKit builder
*/
function convertNxExecutor(executor: Executor): any;// 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 };
}
}// 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 };
}// 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