CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-nrwl--tao

CLI compatibility layer for older Nx workspaces that serves as a bridge to core nx functionality

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

workspace-root.mddocs/

Workspace Root

Utilities for finding and working with workspace root directories. Provides reliable detection of Nx workspace boundaries and root path resolution.

Capabilities

Workspace Root Constant

Pre-calculated workspace root directory for the current process.

/**
 * The root directory of the current workspace
 * Automatically detected by looking for nx.json, workspace.json, or nx executable
 */
export const workspaceRoot: string;

Usage Examples:

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

console.log('Current workspace root:', workspaceRoot);

// Use in file operations
const nxJsonPath = `${workspaceRoot}/nx.json`;
const packageJsonPath = `${workspaceRoot}/package.json`;

// Use with other APIs
import { Workspaces } from "@nrwl/tao/shared/workspace";
const workspaces = new Workspaces(workspaceRoot);

Workspace Root Detection

Internal function for finding workspace root directories.

/**
 * Internal function to find workspace root by looking for nx.json, nx, or nx.bat files
 * @param dir - Directory to start searching from
 * @param candidateRoot - Previously found candidate root (for recursion)
 * @returns Path to the workspace root directory
 */
export function workspaceRootInner(dir: string, candidateRoot: string | null): string;

Usage Examples:

import { workspaceRootInner } from "@nrwl/tao/utils/app-root";

// Find workspace root starting from specific directory
const rootFromPath = workspaceRootInner('/path/to/some/nested/directory', null);
console.log('Workspace root:', rootFromPath);

// Find workspace root with candidate (useful for optimization)
const rootWithCandidate = workspaceRootInner(
  '/path/to/nested/dir', 
  '/path/to/potential/root'
);

Detection Logic

The workspace root detection follows this priority order:

  1. nx.json file - Primary indicator of an Nx workspace
  2. nx executable - Unix/Linux nx binary in the directory
  3. nx.bat file - Windows nx batch file in the directory
  4. Traversal - Recursively searches parent directories until found

Usage Examples

Basic Workspace Operations

import { workspaceRoot } from "@nrwl/tao/utils/app-root";
import { existsSync, readFileSync } from 'fs';
import { join } from 'path';

// Check if we're in an Nx workspace
function isNxWorkspace(): boolean {
  return existsSync(join(workspaceRoot, 'nx.json'));
}

// Read workspace package.json
function getWorkspacePackageJson() {
  const packageJsonPath = join(workspaceRoot, 'package.json');
  
  if (existsSync(packageJsonPath)) {
    return JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
  }
  
  return null;
}

// Get relative path from workspace root
function getRelativePath(absolutePath: string): string {
  return absolutePath.replace(workspaceRoot, '').replace(/^\//, '');
}

console.log('Is Nx workspace:', isNxWorkspace());
console.log('Workspace package.json:', getWorkspacePackageJson());
console.log('Current relative path:', getRelativePath(process.cwd()));

Path Resolution Utilities

import { workspaceRoot } from "@nrwl/tao/utils/app-root";
import { join, relative, resolve } from 'path';

class WorkspacePathUtils {
  static resolveFromRoot(...paths: string[]): string {
    return join(workspaceRoot, ...paths);
  }
  
  static resolveToRoot(path: string): string {
    return resolve(workspaceRoot, path);
  }
  
  static getRelativeToRoot(absolutePath: string): string {
    return relative(workspaceRoot, absolutePath);
  }
  
  static isInWorkspace(path: string): boolean {
    const relativePath = this.getRelativeToRoot(path);
    return !relativePath.startsWith('../');
  }
}

// Usage examples
const appPath = WorkspacePathUtils.resolveFromRoot('apps', 'my-app');
const libPath = WorkspacePathUtils.resolveFromRoot('libs', 'shared', 'ui');
const configPath = WorkspacePathUtils.resolveFromRoot('nx.json');

console.log('App path:', appPath);
console.log('Lib path:', libPath);
console.log('Config path:', configPath);

// Check if paths are within workspace
console.log('Is app in workspace:', WorkspacePathUtils.isInWorkspace(appPath));
console.log('Is external path in workspace:', WorkspacePathUtils.isInWorkspace('/tmp/external'));

Custom Workspace Detection

import { workspaceRootInner } from "@nrwl/tao/utils/app-root";
import { existsSync } from 'fs';
import { dirname } from 'path';

function findWorkspaceRoot(startPath: string): string | null {
  try {
    return workspaceRootInner(startPath, null);
  } catch (error) {
    return null;
  }
}

function findNearestWorkspace(filePath: string): string | null {
  let currentDir = dirname(filePath);
  
  // Search up the directory tree
  while (currentDir !== dirname(currentDir)) {
    const workspaceRoot = findWorkspaceRoot(currentDir);
    if (workspaceRoot) {
      return workspaceRoot;
    }
    currentDir = dirname(currentDir);
  }
  
  return null;
}

// Usage
const fileInProject = '/path/to/deep/nested/file.ts';
const nearestWorkspace = findNearestWorkspace(fileInProject);

if (nearestWorkspace) {
  console.log(`Found workspace: ${nearestWorkspace}`);
} else {
  console.log('No workspace found');
}

Multi-Workspace Support

import { workspaceRootInner } from "@nrwl/tao/utils/app-root";
import { readdirSync, statSync } from 'fs';
import { join } from 'path';

class MultiWorkspaceManager {
  private workspaces: Map<string, string> = new Map();
  
  constructor(private searchRoot: string) {
    this.discoverWorkspaces();
  }
  
  private discoverWorkspaces(): void {
    this.searchDirectory(this.searchRoot);
  }
  
  private searchDirectory(dir: string): void {
    try {
      const entries = readdirSync(dir);
      
      for (const entry of entries) {
        const fullPath = join(dir, entry);
        
        if (statSync(fullPath).isDirectory()) {
          // Try to find workspace in this directory
          try {
            const workspaceRoot = workspaceRootInner(fullPath, null);
            if (workspaceRoot && !this.workspaces.has(workspaceRoot)) {
              this.workspaces.set(entry, workspaceRoot);
            }
          } catch {
            // Not a workspace, continue searching subdirectories
            this.searchDirectory(fullPath);
          }
        }
      }
    } catch (error) {
      // Directory might not be accessible
    }
  }
  
  getWorkspaces(): Map<string, string> {
    return new Map(this.workspaces);
  }
  
  getWorkspaceByName(name: string): string | undefined {
    return this.workspaces.get(name);
  }
  
  getAllWorkspaceRoots(): string[] {
    return Array.from(this.workspaces.values());
  }
}

// Usage
const manager = new MultiWorkspaceManager('/path/to/monorepo');
const workspaces = manager.getWorkspaces();

console.log('Discovered workspaces:');
workspaces.forEach((root, name) => {
  console.log(`  ${name}: ${root}`);
});

Environment Integration

import { workspaceRoot } from "@nrwl/tao/utils/app-root";

function setupWorkspaceEnvironment() {
  // Set environment variables for tools
  process.env.NX_WORKSPACE_ROOT = workspaceRoot;
  process.env.WORKSPACE_ROOT = workspaceRoot;
  
  // Add workspace bin to PATH
  const workspaceBin = `${workspaceRoot}/node_modules/.bin`;
  if (!process.env.PATH?.includes(workspaceBin)) {
    process.env.PATH = `${workspaceBin}:${process.env.PATH}`;
  }
  
  // Set working directory to workspace root if needed
  if (process.cwd() !== workspaceRoot) {
    console.log(`Changing directory to workspace root: ${workspaceRoot}`);
    process.chdir(workspaceRoot);
  }
}

// Validate workspace environment
function validateWorkspaceEnvironment(): boolean {
  const checks = [
    { name: 'Workspace root exists', check: () => existsSync(workspaceRoot) },
    { name: 'nx.json exists', check: () => existsSync(`${workspaceRoot}/nx.json`) },
    { name: 'package.json exists', check: () => existsSync(`${workspaceRoot}/package.json`) },
    { name: 'node_modules exists', check: () => existsSync(`${workspaceRoot}/node_modules`) }
  ];
  
  let allValid = true;
  
  checks.forEach(({ name, check }) => {
    const isValid = check();
    console.log(`${isValid ? '✓' : '✗'} ${name}`);
    if (!isValid) allValid = false;
  });
  
  return allValid;
}

// Usage
setupWorkspaceEnvironment();
const isValid = validateWorkspaceEnvironment();

if (!isValid) {
  console.error('Workspace environment validation failed');
  process.exit(1);
}

Integration with Other APIs

The workspace root utilities integrate with all other @nrwl/tao APIs:

import { workspaceRoot } from "@nrwl/tao/utils/app-root";
import { Workspaces } from "@nrwl/tao/shared/workspace";
import { detectPackageManager } from "@nrwl/tao/shared/package-manager";
import { FsTree } from "@nrwl/tao/shared/tree";
import { logger } from "@nrwl/tao/shared/logger";

function initializeWorkspaceTools() {
  logger.info(`Initializing tools for workspace: ${workspaceRoot}`);
  
  // Initialize workspace management
  const workspaces = new Workspaces(workspaceRoot);
  const hasNxJson = workspaces.hasNxJson();
  
  if (!hasNxJson) {
    logger.error('Not a valid Nx workspace');
    return null;
  }
  
  // Initialize package manager detection
  const packageManager = detectPackageManager(workspaceRoot);
  logger.info(`Detected package manager: ${packageManager}`);
  
  // Initialize virtual file system
  const tree = new FsTree(workspaceRoot);
  
  // Read workspace configuration
  const nxJson = workspaces.readNxJson();
  const projects = workspaces.readProjectsConfigurations();
  
  logger.info(`Workspace '${nxJson.npmScope || 'unnamed'}' initialized`);
  logger.info(`Found ${Object.keys(projects.projects).length} projects`);
  
  return {
    root: workspaceRoot,
    workspaces,
    packageManager,
    tree,
    nxJson,
    projects
  };
}

// Usage
const tools = initializeWorkspaceTools();
if (tools) {
  console.log('Workspace tools initialized successfully');
  console.log(`Working in: ${tools.root}`);
}

Install with Tessl CLI

npx tessl i tessl/npm-nrwl--tao

docs

angular-cli-adapter.md

configuration.md

index.md

logging.md

package-manager.md

project-graph.md

tree-api.md

workspace-management.md

workspace-root.md

tile.json