0
# Workspace Management
1
2
Comprehensive workspace discovery, project configuration parsing, and workspace utilities. Provides the core functionality for reading, parsing, and managing Nx workspace configurations and project structures.
3
4
## Capabilities
5
6
### Workspaces Class
7
8
Main class for workspace management operations including configuration reading and project discovery.
9
10
```typescript { .api }
11
/**
12
* Main workspace management class
13
*/
14
export class Workspaces {
15
/**
16
* Create a new Workspaces instance
17
* @param root - Root directory of the workspace
18
*/
19
constructor(root: string);
20
21
/**
22
* Get relative path from workspace root to current working directory
23
* @param cwd - Current working directory
24
* @returns Relative path or null if outside workspace
25
*/
26
relativeCwd(cwd: string): string | null;
27
28
/**
29
* Calculate default project name based on current directory
30
* @param cwd - Current working directory
31
* @param projects - Projects configuration
32
* @param nxJson - Nx configuration
33
* @returns Default project name
34
*/
35
calculateDefaultProjectName(cwd: string, projects: ProjectsConfigurations, nxJson: NxJsonConfiguration): string;
36
37
/**
38
* Read all project configurations from the workspace
39
* @param opts - Options for reading configurations
40
* @returns Complete projects configuration
41
*/
42
readProjectsConfigurations(opts?: {
43
_ignorePluginInference?: boolean;
44
_includeProjectsFromAngularJson?: boolean;
45
}): ProjectsConfigurations;
46
47
/**
48
* @deprecated Use readProjectsConfigurations instead
49
* Read workspace configuration (projects + nx.json combined)
50
*/
51
readWorkspaceConfiguration(opts?: any): ProjectsConfigurations & NxJsonConfiguration;
52
53
/**
54
* Check if an executor is an Nx executor
55
* @param nodeModule - Node module name
56
* @param executor - Executor name
57
* @returns True if it's an Nx executor
58
*/
59
isNxExecutor(nodeModule: string, executor: string): boolean;
60
61
/**
62
* Check if a generator is an Nx generator
63
* @param collectionName - Collection name
64
* @param generatorName - Generator name
65
* @returns True if it's an Nx generator
66
*/
67
isNxGenerator(collectionName: string, generatorName: string): boolean;
68
69
/**
70
* Read executor configuration
71
* @param nodeModule - Node module name
72
* @param executor - Executor name
73
* @returns Executor configuration with compatibility info
74
*/
75
readExecutor(nodeModule: string, executor: string): ExecutorConfig & { isNgCompat: boolean };
76
77
/**
78
* Read generator information
79
* @param collectionName - Collection name
80
* @param generatorName - Generator name
81
* @returns Generator information
82
*/
83
readGenerator(collectionName: string, generatorName: string): GeneratorInfo;
84
85
/**
86
* Check if workspace has nx.json file
87
* @returns True if nx.json exists
88
*/
89
hasNxJson(): boolean;
90
91
/**
92
* Read nx.json configuration
93
* @returns Nx configuration object
94
*/
95
readNxJson(): NxJsonConfiguration;
96
}
97
```
98
99
### Project Discovery Functions
100
101
Functions for finding and organizing project files within the workspace.
102
103
```typescript { .api }
104
/**
105
* Convert file path to project name
106
* @param fileName - File path to convert
107
* @returns Project name derived from path
108
*/
109
export function toProjectName(fileName: string): string;
110
111
/**
112
* @deprecated Use getGlobPatternsFromPluginsAsync instead
113
* Get glob patterns from configured plugins
114
* @param nxJson - Nx configuration
115
* @param paths - Paths to search
116
* @param root - Workspace root
117
* @returns Array of glob patterns
118
*/
119
export function getGlobPatternsFromPlugins(
120
nxJson: NxJsonConfiguration,
121
paths: string[],
122
root?: string
123
): string[];
124
125
/**
126
* Get glob patterns from configured plugins (async version)
127
* @param nxJson - Nx configuration
128
* @param paths - Paths to search
129
* @param root - Workspace root
130
* @returns Promise resolving to array of glob patterns
131
*/
132
export function getGlobPatternsFromPluginsAsync(
133
nxJson: NxJsonConfiguration,
134
paths: string[],
135
root?: string
136
): Promise<string[]>;
137
138
/**
139
* Get glob patterns from package manager workspace configurations
140
* @param root - Workspace root directory
141
* @returns Array of glob patterns from package.json workspaces
142
*/
143
export function getGlobPatternsFromPackageManagerWorkspaces(root: string): string[];
144
145
/**
146
* Find project files using glob patterns
147
* @param root - Workspace root
148
* @param pluginsGlobPatterns - Glob patterns from plugins
149
* @param nxJson - Nx configuration (optional)
150
* @returns Array of project file paths
151
*/
152
export function globForProjectFiles(
153
root: string,
154
pluginsGlobPatterns: string[],
155
nxJson?: NxJsonConfiguration
156
): string[];
157
158
/**
159
* Remove duplicate project files from array
160
* @param files - Array of file paths
161
* @returns Array with duplicates removed
162
*/
163
export function deduplicateProjectFiles(files: string[]): string[];
164
```
165
166
### Configuration Processing
167
168
Functions for processing and merging project configurations.
169
170
```typescript { .api }
171
/**
172
* Infer project configuration from non-standard project files
173
* @param file - File path to analyze
174
* @returns Project configuration with name
175
*/
176
export function inferProjectFromNonStandardFile(file: string): ProjectConfiguration & { name: string };
177
178
/**
179
* Build project configurations from glob results
180
* @param nxJson - Nx configuration
181
* @param projectFiles - Array of project files
182
* @param readProjectConfiguration - Function to read project config
183
* @param root - Workspace root
184
* @returns Complete projects configuration
185
*/
186
export function buildProjectsConfigurationsFromGlobs(
187
nxJson: NxJsonConfiguration,
188
projectFiles: string[],
189
readProjectConfiguration: (path: string) => ProjectConfiguration & { name: string },
190
root: string
191
): ProjectsConfigurations;
192
193
/**
194
* Merge target configurations with defaults
195
* @param project - Project configuration
196
* @param targetName - Name of the target
197
* @param target - Target configuration
198
* @param projectDefaults - Project-level defaults
199
* @param executor - Executor name
200
* @returns Merged target configuration
201
*/
202
export function mergeTargetConfigurations(
203
project: ProjectConfiguration,
204
targetName: string,
205
target: TargetConfiguration,
206
projectDefaults: TargetDefaults | undefined,
207
executor: string
208
): TargetConfiguration;
209
210
/**
211
* Read target defaults for a specific target
212
* @param targetName - Name of the target
213
* @param targetDefaults - Target defaults configuration
214
* @param executor - Executor name
215
* @returns Target defaults for the specified target
216
*/
217
export function readTargetDefaultsForTarget(
218
targetName: string,
219
targetDefaults: TargetDefaults | undefined,
220
executor: string
221
): TargetDefaults[string];
222
```
223
224
### Utility Functions
225
226
General utility functions for workspace operations.
227
228
```typescript { .api }
229
/**
230
* Rename object property while preserving key order
231
* @param obj - Object to modify
232
* @param from - Current property name
233
* @param to - New property name
234
*/
235
export function renamePropertyWithStableKeys(obj: any, from: string, to: string): void;
236
```
237
238
## Usage Examples
239
240
### Basic Workspace Operations
241
242
```typescript
243
import { Workspaces } from "@nrwl/tao/shared/workspace";
244
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
245
246
// Create workspace instance
247
const workspaces = new Workspaces(workspaceRoot);
248
249
// Check if this is an Nx workspace
250
if (workspaces.hasNxJson()) {
251
console.log('This is an Nx workspace');
252
253
// Read configurations
254
const nxConfig = workspaces.readNxJson();
255
const projects = workspaces.readProjectsConfigurations();
256
257
console.log(`Workspace scope: ${nxConfig.npmScope}`);
258
console.log(`Found ${Object.keys(projects.projects).length} projects`);
259
260
// List all projects
261
Object.entries(projects.projects).forEach(([name, config]) => {
262
console.log(` ${name} (${config.projectType || 'unknown'}) - ${config.root}`);
263
});
264
} else {
265
console.log('Not an Nx workspace');
266
}
267
```
268
269
### Project Discovery and Analysis
270
271
```typescript
272
import {
273
Workspaces,
274
globForProjectFiles,
275
getGlobPatternsFromPackageManagerWorkspaces,
276
toProjectName
277
} from "@nrwl/tao/shared/workspace";
278
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
279
280
const workspaces = new Workspaces(workspaceRoot);
281
const nxJson = workspaces.readNxJson();
282
283
// Get glob patterns from different sources
284
const pmPatterns = getGlobPatternsFromPackageManagerWorkspaces(workspaceRoot);
285
console.log('Package manager patterns:', pmPatterns);
286
287
// Find all project files
288
const projectFiles = globForProjectFiles(workspaceRoot, pmPatterns, nxJson);
289
console.log(`Found ${projectFiles.length} project files`);
290
291
// Convert file paths to project names
292
const projectNames = projectFiles.map(toProjectName);
293
console.log('Inferred project names:', projectNames);
294
```
295
296
### Working with Executors and Generators
297
298
```typescript
299
import { Workspaces } from "@nrwl/tao/shared/workspace";
300
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
301
302
const workspaces = new Workspaces(workspaceRoot);
303
304
// Check executor types
305
const isBuildExecutorNx = workspaces.isNxExecutor('@nx/webpack', 'webpack');
306
const isLintExecutorNx = workspaces.isNxExecutor('@angular-eslint/builder', 'lint');
307
308
console.log(`@nx/webpack:webpack is Nx executor: ${isBuildExecutorNx}`);
309
console.log(`@angular-eslint/builder:lint is Nx executor: ${isLintExecutorNx}`);
310
311
// Read executor configuration
312
if (isBuildExecutorNx) {
313
const executorConfig = workspaces.readExecutor('@nx/webpack', 'webpack');
314
console.log('Webpack executor config:', executorConfig);
315
}
316
317
// Check generators
318
const isNxGenerator = workspaces.isNxGenerator('@nx/react', 'component');
319
console.log(`@nx/react:component is Nx generator: ${isNxGenerator}`);
320
321
if (isNxGenerator) {
322
const generatorInfo = workspaces.readGenerator('@nx/react', 'component');
323
console.log('React component generator info:', generatorInfo);
324
}
325
```
326
327
### Default Project Calculation
328
329
```typescript
330
import { Workspaces } from "@nrwl/tao/shared/workspace";
331
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
332
333
const workspaces = new Workspaces(workspaceRoot);
334
const nxJson = workspaces.readNxJson();
335
const projects = workspaces.readProjectsConfigurations();
336
337
// Calculate default project based on current directory
338
const cwd = process.cwd();
339
const defaultProject = workspaces.calculateDefaultProjectName(cwd, projects, nxJson);
340
341
console.log(`Current directory: ${cwd}`);
342
console.log(`Relative to workspace: ${workspaces.relativeCwd(cwd)}`);
343
console.log(`Default project: ${defaultProject}`);
344
345
// This is useful for CLI commands that need to infer which project to operate on
346
if (defaultProject) {
347
console.log(`Operating on project: ${defaultProject}`);
348
} else {
349
console.log('No default project could be determined');
350
}
351
```
352
353
### Configuration Merging
354
355
```typescript
356
import {
357
mergeTargetConfigurations,
358
readTargetDefaultsForTarget,
359
type TargetConfiguration,
360
type TargetDefaults
361
} from "@nrwl/tao/shared/workspace";
362
363
// Example target defaults
364
const targetDefaults: TargetDefaults = {
365
build: {
366
cache: true,
367
inputs: ['production', '^production']
368
},
369
test: {
370
cache: true,
371
inputs: ['default', '^production', { externalDependencies: ['jest'] }]
372
}
373
};
374
375
// Project-specific target configuration
376
const projectConfig = {
377
name: 'my-app',
378
root: 'apps/my-app',
379
targets: {
380
build: {
381
executor: '@nx/webpack:webpack',
382
options: {
383
outputPath: 'dist/apps/my-app'
384
}
385
}
386
}
387
};
388
389
// Get defaults for build target
390
const buildDefaults = readTargetDefaultsForTarget('build', targetDefaults, '@nx/webpack:webpack');
391
console.log('Build target defaults:', buildDefaults);
392
393
// Merge project target with defaults
394
const mergedBuildTarget = mergeTargetConfigurations(
395
projectConfig,
396
'build',
397
projectConfig.targets.build,
398
targetDefaults,
399
'@nx/webpack:webpack'
400
);
401
402
console.log('Merged build target:', mergedBuildTarget);
403
```
404
405
### Advanced Project Configuration
406
407
```typescript
408
import {
409
buildProjectsConfigurationsFromGlobs,
410
inferProjectFromNonStandardFile,
411
deduplicateProjectFiles
412
} from "@nrwl/tao/shared/workspace";
413
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
414
415
// Custom project file discovery
416
const customProjectFiles = [
417
'apps/web/project.json',
418
'libs/shared/package.json',
419
'tools/custom-project.config.js'
420
];
421
422
// Remove duplicates
423
const uniqueFiles = deduplicateProjectFiles(customProjectFiles);
424
425
// Infer project configurations from non-standard files
426
const inferredProjects = uniqueFiles.map(file => {
427
try {
428
return inferProjectFromNonStandardFile(file);
429
} catch (error) {
430
console.warn(`Could not infer project from ${file}:`, error.message);
431
return null;
432
}
433
}).filter(Boolean);
434
435
console.log('Inferred projects:', inferredProjects);
436
437
// Build complete configuration (this is a simplified example)
438
// In real usage, you'd provide a proper readProjectConfiguration function
439
function readProjectConfiguration(path: string) {
440
// This would read and parse the actual project file
441
return inferProjectFromNonStandardFile(path);
442
}
443
444
const projectsConfig = buildProjectsConfigurationsFromGlobs(
445
{ npmScope: 'myorg' }, // minimal nx.json
446
uniqueFiles,
447
readProjectConfiguration,
448
workspaceRoot
449
);
450
451
console.log('Built projects configuration:', projectsConfig);
452
```
453
454
## Integration with Other APIs
455
456
Workspace management integrates closely with other @nrwl/tao APIs:
457
458
```typescript
459
import { Workspaces } from "@nrwl/tao/shared/workspace";
460
import { detectPackageManager } from "@nrwl/tao/shared/package-manager";
461
import { logger } from "@nrwl/tao/shared/logger";
462
import { workspaceRoot } from "@nrwl/tao/utils/app-root";
463
464
function setupWorkspace() {
465
const workspaces = new Workspaces(workspaceRoot);
466
467
if (!workspaces.hasNxJson()) {
468
logger.error('This is not an Nx workspace');
469
return;
470
}
471
472
const nxJson = workspaces.readNxJson();
473
const projects = workspaces.readProjectsConfigurations();
474
475
// Ensure package manager is configured
476
const detectedPm = detectPackageManager(workspaceRoot);
477
if (!nxJson.cli?.packageManager) {
478
nxJson.cli = { ...nxJson.cli, packageManager: detectedPm };
479
logger.info(`Configured package manager: ${detectedPm}`);
480
}
481
482
// Log workspace information
483
logger.info(`Workspace: ${nxJson.npmScope || 'unnamed'}`);
484
logger.info(`Projects: ${Object.keys(projects.projects).length}`);
485
logger.info(`Package manager: ${nxJson.cli?.packageManager || detectedPm}`);
486
487
return { nxJson, projects, packageManager: detectedPm };
488
}
489
```