From 1a31018ea2bc9f415268636b2ad834ff02a8d147 Mon Sep 17 00:00:00 2001 From: Victor Savkin Date: Wed, 17 Aug 2022 14:45:02 -0400 Subject: [PATCH] feat(core): add daemon to the context provided to task runners --- docs/generated/devkit/index.md | 1 + docs/generated/packages/devkit.json | 2 +- package.json | 2 +- packages/nx/src/daemon/client/client.ts | 123 ++++++++++++------ .../server/handle-process-in-background.ts | 27 ++++ .../server/handle-request-project-graph.ts | 63 +++++++++ packages/nx/src/daemon/server/server.ts | 113 ++++------------ .../nx/src/daemon/server/shutdown-utils.ts | 33 ++++- .../nx/src/project-graph/project-graph.ts | 55 +------- packages/nx/src/tasks-runner/run-command.ts | 2 + packages/nx/src/tasks-runner/tasks-runner.ts | 2 + yarn.lock | 8 +- 12 files changed, 247 insertions(+), 184 deletions(-) create mode 100644 packages/nx/src/daemon/server/handle-process-in-background.ts create mode 100644 packages/nx/src/daemon/server/handle-request-project-graph.ts diff --git a/docs/generated/devkit/index.md b/docs/generated/devkit/index.md index 12c957b4c2..6d097a62ac 100644 --- a/docs/generated/devkit/index.md +++ b/docs/generated/devkit/index.md @@ -942,6 +942,7 @@ stored in the daemon process. To reset both run: `nx reset`. | `tasks` | [`Task`](../../devkit/index#task)[] | | `options` | [`DefaultTasksRunnerOptions`](../../devkit/index#defaulttasksrunneroptions) | | `context?` | `Object` | +| `context.daemon?` | `DaemonClient` | | `context.hasher?` | [`Hasher`](../../devkit/index#hasher) | | `context.initiatingProject?` | `string` | | `context.nxArgs` | `NxArgs` | diff --git a/docs/generated/packages/devkit.json b/docs/generated/packages/devkit.json index 765fc7048e..b143779eda 100644 --- a/docs/generated/packages/devkit.json +++ b/docs/generated/packages/devkit.json @@ -10,7 +10,7 @@ "id": "index", "name": "Overview", "file": "generated/devkit/index", - "content": "# Module: index\n\nThe Nx Devkit is the underlying technology used to customize Nx to support\ndifferent technologies and custom use-cases. It contains many utility\nfunctions for reading and writing files, updating configuration,\nworking with Abstract Syntax Trees(ASTs), and more.\n\nAs with most things in Nx, the core of Nx Devkit is very simple.\nIt only uses language primitives and immutable objects\n(the tree being the only exception).\n\n## Table of contents\n\n### Project Graph Enumerations\n\n- [DependencyType](../../devkit/index#dependencytype)\n\n### Utils Enumerations\n\n- [ChangeType](../../devkit/index#changetype)\n\n### Project Graph Classes\n\n- [ProjectGraphBuilder](../../devkit/index#projectgraphbuilder)\n\n### Utils Classes\n\n- [Hasher](../../devkit/index#hasher)\n\n### Workspace Classes\n\n- [Workspaces](../../devkit/index#workspaces)\n\n### Commands Interfaces\n\n- [Target](../../devkit/index#target)\n\n### Other Interfaces\n\n- [NxPlugin](../../devkit/index#nxplugin)\n\n### Project Graph Interfaces\n\n- [FileData](../../devkit/index#filedata)\n- [ProjectFileMap](../../devkit/index#projectfilemap)\n- [ProjectGraph](../../devkit/index#projectgraph)\n- [ProjectGraphDependency](../../devkit/index#projectgraphdependency)\n- [ProjectGraphExternalNode](../../devkit/index#projectgraphexternalnode)\n- [ProjectGraphProcessorContext](../../devkit/index#projectgraphprocessorcontext)\n- [ProjectGraphProjectNode](../../devkit/index#projectgraphprojectnode)\n- [ProjectGraphV4](../../devkit/index#projectgraphv4)\n\n### Tree Interfaces\n\n- [FileChange](../../devkit/index#filechange)\n- [Tree](../../devkit/index#tree)\n\n### Utils Interfaces\n\n- [DefaultTasksRunnerOptions](../../devkit/index#defaulttasksrunneroptions)\n- [Hash](../../devkit/index#hash)\n- [JsonParseOptions](../../devkit/index#jsonparseoptions)\n- [JsonSerializeOptions](../../devkit/index#jsonserializeoptions)\n- [RemoteCache](../../devkit/index#remotecache)\n- [StringDeletion](../../devkit/index#stringdeletion)\n- [StringInsertion](../../devkit/index#stringinsertion)\n\n### Workspace Interfaces\n\n- [ExecutorContext](../../devkit/index#executorcontext)\n- [ExecutorsJson](../../devkit/index#executorsjson)\n- [GeneratorsJson](../../devkit/index#generatorsjson)\n- [HasherContext](../../devkit/index#hashercontext)\n- [ImplicitJsonSubsetDependency](../../devkit/index#implicitjsonsubsetdependency)\n- [MigrationsJson](../../devkit/index#migrationsjson)\n- [NxAffectedConfig](../../devkit/index#nxaffectedconfig)\n- [NxJsonConfiguration](../../devkit/index#nxjsonconfiguration)\n- [ProjectConfiguration](../../devkit/index#projectconfiguration)\n- [ProjectsConfigurations](../../devkit/index#projectsconfigurations)\n- [TargetConfiguration](../../devkit/index#targetconfiguration)\n- [TargetDependencyConfig](../../devkit/index#targetdependencyconfig)\n- [Task](../../devkit/index#task)\n- [TaskGraph](../../devkit/index#taskgraph)\n- [Workspace](../../devkit/index#workspace)\n\n### Generators Type aliases\n\n- [WorkspaceConfiguration](../../devkit/index#workspaceconfiguration)\n\n### Other Type aliases\n\n- [ProjectTargetConfigurator](../../devkit/index#projecttargetconfigurator)\n\n### Package Manager Type aliases\n\n- [PackageManager](../../devkit/index#packagemanager)\n\n### Project Graph Type aliases\n\n- [ProjectGraphNode](../../devkit/index#projectgraphnode)\n\n### Utils Type aliases\n\n- [StringChange](../../devkit/index#stringchange)\n\n### Workspace Type aliases\n\n- [CustomHasher](../../devkit/index#customhasher)\n- [Executor](../../devkit/index#executor)\n- [Generator](../../devkit/index#generator)\n- [GeneratorCallback](../../devkit/index#generatorcallback)\n- [ImplicitDependencyEntry](../../devkit/index#implicitdependencyentry)\n- [ProjectType](../../devkit/index#projecttype)\n- [TaskGraphExecutor](../../devkit/index#taskgraphexecutor)\n- [WorkspaceJsonConfiguration](../../devkit/index#workspacejsonconfiguration)\n\n### Logger Variables\n\n- [logger](../../devkit/index#logger)\n\n### Utils Variables\n\n- [appRootPath](../../devkit/index#approotpath)\n- [cacheDir](../../devkit/index#cachedir)\n- [output](../../devkit/index#output)\n- [workspaceRoot](../../devkit/index#workspaceroot)\n\n### Functions\n\n- [addDependenciesToPackageJson](../../devkit/index#adddependenciestopackagejson)\n- [addProjectConfiguration](../../devkit/index#addprojectconfiguration)\n- [applyChangesToString](../../devkit/index#applychangestostring)\n- [convertNxExecutor](../../devkit/index#convertnxexecutor)\n- [convertNxGenerator](../../devkit/index#convertnxgenerator)\n- [createProjectGraphAsync](../../devkit/index#createprojectgraphasync)\n- [defaultTasksRunner](../../devkit/index#defaulttasksrunner)\n- [detectPackageManager](../../devkit/index#detectpackagemanager)\n- [detectWorkspaceScope](../../devkit/index#detectworkspacescope)\n- [formatFiles](../../devkit/index#formatfiles)\n- [generateFiles](../../devkit/index#generatefiles)\n- [getImportPath](../../devkit/index#getimportpath)\n- [getOutputsForTargetAndConfiguration](../../devkit/index#getoutputsfortargetandconfiguration)\n- [getPackageManagerCommand](../../devkit/index#getpackagemanagercommand)\n- [getPackageManagerVersion](../../devkit/index#getpackagemanagerversion)\n- [getProjects](../../devkit/index#getprojects)\n- [getWorkspaceLayout](../../devkit/index#getworkspacelayout)\n- [getWorkspacePath](../../devkit/index#getworkspacepath)\n- [installPackagesTask](../../devkit/index#installpackagestask)\n- [isStandaloneProject](../../devkit/index#isstandaloneproject)\n- [joinPathFragments](../../devkit/index#joinpathfragments)\n- [moveFilesToNewDirectory](../../devkit/index#movefilestonewdirectory)\n- [names](../../devkit/index#names)\n- [normalizePath](../../devkit/index#normalizepath)\n- [offsetFromRoot](../../devkit/index#offsetfromroot)\n- [parseJson](../../devkit/index#parsejson)\n- [parseTargetString](../../devkit/index#parsetargetstring)\n- [readAllWorkspaceConfiguration](../../devkit/index#readallworkspaceconfiguration)\n- [readCachedProjectGraph](../../devkit/index#readcachedprojectgraph)\n- [readJson](../../devkit/index#readjson)\n- [readJsonFile](../../devkit/index#readjsonfile)\n- [readNxJson](../../devkit/index#readnxjson)\n- [readProjectConfiguration](../../devkit/index#readprojectconfiguration)\n- [readTargetOptions](../../devkit/index#readtargetoptions)\n- [readWorkspaceConfiguration](../../devkit/index#readworkspaceconfiguration)\n- [removeDependenciesFromPackageJson](../../devkit/index#removedependenciesfrompackagejson)\n- [removeProjectConfiguration](../../devkit/index#removeprojectconfiguration)\n- [reverse](../../devkit/index#reverse)\n- [runExecutor](../../devkit/index#runexecutor)\n- [serializeJson](../../devkit/index#serializejson)\n- [stripIndents](../../devkit/index#stripindents)\n- [stripJsonComments](../../devkit/index#stripjsoncomments)\n- [targetToTargetString](../../devkit/index#targettotargetstring)\n- [toJS](../../devkit/index#tojs)\n- [updateJson](../../devkit/index#updatejson)\n- [updateProjectConfiguration](../../devkit/index#updateprojectconfiguration)\n- [updateTsConfigsToJs](../../devkit/index#updatetsconfigstojs)\n- [updateWorkspaceConfiguration](../../devkit/index#updateworkspaceconfiguration)\n- [visitNotIgnoredFiles](../../devkit/index#visitnotignoredfiles)\n- [workspaceLayout](../../devkit/index#workspacelayout)\n- [writeJson](../../devkit/index#writejson)\n- [writeJsonFile](../../devkit/index#writejsonfile)\n\n## Project Graph Enumerations\n\n### DependencyType\n\n• **DependencyType**: `Object`\n\n---\n\n## Utils Enumerations\n\n### ChangeType\n\n• **ChangeType**: `Object`\n\n## Project Graph Classes\n\n### ProjectGraphBuilder\n\n• **ProjectGraphBuilder**: `Object`\n\n---\n\n## Utils Classes\n\n### Hasher\n\n• **Hasher**: `Object`\n\n---\n\n## Workspace Classes\n\n### Workspaces\n\n• **Workspaces**: `Object`\n\n## Commands Interfaces\n\n### Target\n\n• **Target**: `Object`\n\n---\n\n## Other Interfaces\n\n### NxPlugin\n\n• **NxPlugin**: `Object`\n\nA plugin for Nx\n\n---\n\n## Project Graph Interfaces\n\n### FileData\n\n• **FileData**: `Object`\n\n---\n\n### ProjectFileMap\n\n• **ProjectFileMap**: `Object`\n\n---\n\n### ProjectGraph\n\n• **ProjectGraph**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n### ProjectGraphDependency\n\n• **ProjectGraphDependency**: `Object`\n\n---\n\n### ProjectGraphExternalNode\n\n• **ProjectGraphExternalNode**: `Object`\n\n---\n\n### ProjectGraphProcessorContext\n\n• **ProjectGraphProcessorContext**: `Object`\n\n---\n\n### ProjectGraphProjectNode\n\n• **ProjectGraphProjectNode**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n### ProjectGraphV4\n\n• **ProjectGraphV4**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n## Tree Interfaces\n\n### FileChange\n\n• **FileChange**: `Object`\n\n---\n\n### Tree\n\n• **Tree**: `Object`\n\n---\n\n## Utils Interfaces\n\n### DefaultTasksRunnerOptions\n\n• **DefaultTasksRunnerOptions**: `Object`\n\n---\n\n### Hash\n\n• **Hash**: `Object`\n\n---\n\n### JsonParseOptions\n\n• **JsonParseOptions**: `Object`\n\n---\n\n### JsonSerializeOptions\n\n• **JsonSerializeOptions**: `Object`\n\n---\n\n### RemoteCache\n\n• **RemoteCache**: `Object`\n\n---\n\n### StringDeletion\n\n• **StringDeletion**: `Object`\n\n---\n\n### StringInsertion\n\n• **StringInsertion**: `Object`\n\n---\n\n## Workspace Interfaces\n\n### ExecutorContext\n\n• **ExecutorContext**: `Object`\n\n---\n\n### ExecutorsJson\n\n• **ExecutorsJson**: `Object`\n\n---\n\n### GeneratorsJson\n\n• **GeneratorsJson**: `Object`\n\n---\n\n### HasherContext\n\n• **HasherContext**: `Object`\n\n---\n\n### ImplicitJsonSubsetDependency\n\n• **ImplicitJsonSubsetDependency**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :------------------ |\n| `T` | `\"*\"` \\| `string`[] |\n\n---\n\n### MigrationsJson\n\n• **MigrationsJson**: `Object`\n\n---\n\n### NxAffectedConfig\n\n• **NxAffectedConfig**: `Object`\n\n---\n\n### NxJsonConfiguration\n\n• **NxJsonConfiguration**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :------------------ |\n| `T` | `\"*\"` \\| `string`[] |\n\n---\n\n### ProjectConfiguration\n\n• **ProjectConfiguration**: `Object`\n\n---\n\n### ProjectsConfigurations\n\n• **ProjectsConfigurations**: `Object`\n\n---\n\n### TargetConfiguration\n\n• **TargetConfiguration**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n### TargetDependencyConfig\n\n• **TargetDependencyConfig**: `Object`\n\n---\n\n### Task\n\n• **Task**: `Object`\n\n---\n\n### TaskGraph\n\n• **TaskGraph**: `Object`\n\n---\n\n### Workspace\n\n• **Workspace**: `Object`\n\n## Generators Type aliases\n\n### WorkspaceConfiguration\n\nƬ **WorkspaceConfiguration**: `Omit`<[`ProjectsConfigurations`](../../devkit/index#projectsconfigurations), `\"projects\"`\\> & `Partial`<[`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\\>\n\n---\n\n## Other Type aliases\n\n### ProjectTargetConfigurator\n\nƬ **ProjectTargetConfigurator**: (`file`: `string`) => `Record`<`string`, [`TargetConfiguration`](../../devkit/index#targetconfiguration)\\>\n\n#### Type declaration\n\n▸ (`file`): `Record`<`string`, [`TargetConfiguration`](../../devkit/index#targetconfiguration)\\>\n\n##### Parameters\n\n| Name | Type |\n| :----- | :------- |\n| `file` | `string` |\n\n##### Returns\n\n`Record`<`string`, [`TargetConfiguration`](../../devkit/index#targetconfiguration)\\>\n\n---\n\n## Package Manager Type aliases\n\n### PackageManager\n\nƬ **PackageManager**: `\"yarn\"` \\| `\"pnpm\"` \\| `\"npm\"`\n\n---\n\n## Project Graph Type aliases\n\n### ProjectGraphNode\n\nƬ **ProjectGraphNode**<`T`\\>: [`ProjectGraphProjectNode`](../../devkit/index#projectgraphprojectnode)<`T`\\> \\| [`ProjectGraphExternalNode`](../../devkit/index#projectgraphexternalnode)\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n## Utils Type aliases\n\n### StringChange\n\nƬ **StringChange**: [`StringInsertion`](../../devkit/index#stringinsertion) \\| [`StringDeletion`](../../devkit/index#stringdeletion)\n\n---\n\n## Workspace Type aliases\n\n### CustomHasher\n\nƬ **CustomHasher**: (`task`: [`Task`](../../devkit/index#task), `context`: [`HasherContext`](../../devkit/index#hashercontext)) => `Promise`<[`Hash`](../../devkit/index#hash)\\>\n\n#### Type declaration\n\n▸ (`task`, `context`): `Promise`<[`Hash`](../../devkit/index#hash)\\>\n\n##### Parameters\n\n| Name | Type |\n| :-------- | :-------------------------------------------------- |\n| `task` | [`Task`](../../devkit/index#task) |\n| `context` | [`HasherContext`](../../devkit/index#hashercontext) |\n\n##### Returns\n\n`Promise`<[`Hash`](../../devkit/index#hash)\\>\n\n---\n\n### Executor\n\nƬ **Executor**<`T`\\>: (`options`: `T`, `context`: [`ExecutorContext`](../../devkit/index#executorcontext)) => `Promise`<`Object`\\> \\| `AsyncIterableIterator`<`Object`\\>\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Type declaration\n\n▸ (`options`, `context`): `Promise`<`Object`\\> \\| `AsyncIterableIterator`<`Object`\\>\n\nImplementation of a target of a project\n\n##### Parameters\n\n| Name | Type |\n| :-------- | :------------------------------------------------------ |\n| `options` | `T` |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n##### Returns\n\n`Promise`<`Object`\\> \\| `AsyncIterableIterator`<`Object`\\>\n\n---\n\n### Generator\n\nƬ **Generator**<`T`\\>: (`tree`: `any`, `schema`: `T`) => `void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback) \\| `Promise`<`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback)\\>\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------- |\n| `T` | `unknown` |\n\n#### Type declaration\n\n▸ (`tree`, `schema`): `void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback) \\| `Promise`<`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback)\\>\n\nA function that schedules updates to the filesystem to be done atomically\n\n##### Parameters\n\n| Name | Type |\n| :------- | :---- |\n| `tree` | `any` |\n| `schema` | `T` |\n\n##### Returns\n\n`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback) \\| `Promise`<`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback)\\>\n\n---\n\n### GeneratorCallback\n\nƬ **GeneratorCallback**: () => `void` \\| `Promise`<`void`\\>\n\n#### Type declaration\n\n▸ (): `void` \\| `Promise`<`void`\\>\n\nA callback function that is executed after changes are made to the file system\n\n##### Returns\n\n`void` \\| `Promise`<`void`\\>\n\n---\n\n### ImplicitDependencyEntry\n\nƬ **ImplicitDependencyEntry**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :------------------ |\n| `T` | `\"*\"` \\| `string`[] |\n\n#### Index signature\n\n▪ [key: `string`]: `T` \\| [`ImplicitJsonSubsetDependency`](../../devkit/index#implicitjsonsubsetdependency)<`T`\\>\n\n---\n\n### ProjectType\n\nƬ **ProjectType**: `\"library\"` \\| `\"application\"`\n\n---\n\n### TaskGraphExecutor\n\nƬ **TaskGraphExecutor**<`T`\\>: (`taskGraph`: [`TaskGraph`](../../devkit/index#taskgraph), `options`: `Record`<`string`, `T`\\>, `overrides`: `T`, `context`: [`ExecutorContext`](../../devkit/index#executorcontext)) => `Promise`<`Record`<`string`, `Object`\\>\\>\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Type declaration\n\n▸ (`taskGraph`, `options`, `overrides`, `context`): `Promise`<`Record`<`string`, `Object`\\>\\>\n\nImplementation of a target of a project that handles multiple projects to be batched\n\n##### Parameters\n\n| Name | Type |\n| :---------- | :------------------------------------------------------ |\n| `taskGraph` | [`TaskGraph`](../../devkit/index#taskgraph) |\n| `options` | `Record`<`string`, `T`\\> |\n| `overrides` | `T` |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n##### Returns\n\n`Promise`<`Record`<`string`, `Object`\\>\\>\n\n---\n\n### WorkspaceJsonConfiguration\n\nƬ **WorkspaceJsonConfiguration**: [`ProjectsConfigurations`](../../devkit/index#projectsconfigurations)\n\n## Logger Variables\n\n### logger\n\n• **logger**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :------ | :-------------------------- |\n| `debug` | (...`s`: `any`[]) => `void` |\n| `error` | (`s`: `any`) => `void` |\n| `fatal` | (...`s`: `any`[]) => `void` |\n| `info` | (`s`: `any`) => `void` |\n| `log` | (...`s`: `any`[]) => `void` |\n| `warn` | (`s`: `any`) => `void` |\n\n---\n\n## Utils Variables\n\n### appRootPath\n\n• **appRootPath**: `string` = `workspaceRoot`\n\n---\n\n### cacheDir\n\n• **cacheDir**: `string`\n\n---\n\n### output\n\n• **output**: `CLIOutput`\n\n---\n\n### workspaceRoot\n\n• **workspaceRoot**: `string`\n\n## Functions\n\n### addDependenciesToPackageJson\n\n▸ **addDependenciesToPackageJson**(`tree`, `dependencies`, `devDependencies`, `packageJsonPath?`): [`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nAdd Dependencies and Dev Dependencies to package.json\n\nFor example:\n\n```typescript\naddDependenciesToPackageJson(tree, { react: 'latest' }, { jest: 'latest' });\n```\n\nThis will **add** `react` and `jest` to the dependencies and devDependencies sections of package.json respectively.\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :---------------- | :-------------------------------- | :--------------- | :---------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` | Tree representing file system to modify |\n| `dependencies` | `Record`<`string`, `string`\\> | `undefined` | Dependencies to be added to the dependencies section of package.json |\n| `devDependencies` | `Record`<`string`, `string`\\> | `undefined` | Dependencies to be added to the devDependencies section of package.json |\n| `packageJsonPath` | `string` | `'package.json'` | Path to package.json |\n\n#### Returns\n\n[`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nCallback to install dependencies only if necessary. undefined is returned if changes are not necessary.\n\n---\n\n### addProjectConfiguration\n\n▸ **addProjectConfiguration**(`tree`, `projectName`, `projectConfiguration`, `standalone?`): `void`\n\nAdds project configuration to the Nx workspace.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will update either files.\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------------------- | :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `projectName` | `string` | unique name. Often directories are part of the name (e.g., mydir-mylib) |\n| `projectConfiguration` | [`ProjectConfiguration`](../../devkit/index#projectconfiguration) | project configuration |\n| `standalone?` | `boolean` | should the project use package.json? If false, the project config is inside workspace.json |\n\n#### Returns\n\n`void`\n\n---\n\n### applyChangesToString\n\n▸ **applyChangesToString**(`text`, `changes`): `string`\n\nApplies a list of changes to a string's original value.\n\nThis is useful when working with ASTs.\n\nFor Example, to rename a property in a method's options:\n\n```typescript\nconst code = `bootstrap({\n target: document.querySelector('#app')\n})`;\n\nconst indexOfPropertyName = 13; // Usually determined by analyzing an AST.\nconst updatedCode = applyChangesToString(code, [\n {\n type: ChangeType.Insert,\n index: indexOfPropertyName,\n text: 'element',\n },\n {\n type: ChangeType.Delete,\n start: indexOfPropertyName,\n length: 6,\n },\n]);\n\nbootstrap({\n element: document.querySelector('#app'),\n});\n```\n\n#### Parameters\n\n| Name | Type |\n| :-------- | :-------------------------------------------------- |\n| `text` | `string` |\n| `changes` | [`StringChange`](../../devkit/index#stringchange)[] |\n\n#### Returns\n\n`string`\n\n---\n\n### convertNxExecutor\n\n▸ **convertNxExecutor**(`executor`): `any`\n\nConvert an Nx Executor into an Angular Devkit Builder\n\nUse this to expose a compatible Angular Builder\n\n#### Parameters\n\n| Name | Type |\n| :--------- | :------------------------------------------------ |\n| `executor` | [`Executor`](../../devkit/index#executor)<`any`\\> |\n\n#### Returns\n\n`any`\n\n---\n\n### convertNxGenerator\n\n▸ **convertNxGenerator**<`T`\\>(`generator`, `skipWritingConfigInOldFormat?`): (`generatorOptions`: `T`) => (`tree`: `any`, `context`: `any`) => `Promise`<`any`\\>\n\nConvert an Nx Generator into an Angular Devkit Schematic.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :----------------------------- | :------------------------------------------------ | :------------ | :------------------------------------------------------------------------------------------------ |\n| `generator` | [`Generator`](../../devkit/index#generator)<`T`\\> | `undefined` | The Nx generator to convert to an Angular Devkit Schematic. |\n| `skipWritingConfigInOldFormat` | `boolean` | `false` | Whether to skip writing the configuration in the old format (the one used by the Angular DevKit). |\n\n#### Returns\n\n`fn`\n\n▸ (`generatorOptions`): (`tree`: `any`, `context`: `any`) => `Promise`<`any`\\>\n\n##### Parameters\n\n| Name | Type |\n| :----------------- | :--- |\n| `generatorOptions` | `T` |\n\n##### Returns\n\n`fn`\n\n▸ (`tree`, `context`): `Promise`<`any`\\>\n\n##### Parameters\n\n| Name | Type |\n| :-------- | :---- |\n| `tree` | `any` |\n| `context` | `any` |\n\n##### Returns\n\n`Promise`<`any`\\>\n\n---\n\n### createProjectGraphAsync\n\n▸ **createProjectGraphAsync**(): `Promise`<[`ProjectGraph`](../../devkit/index#projectgraph)\\>\n\nComputes and returns a ProjectGraph.\n\nNx will compute the graph either in a daemon process or in the current process.\n\nNx will compute it in the current process if:\n\n- The process is running in CI (CI env variable is to true or other common variables used by CI providers are set).\n- It is running in the docker container.\n- The daemon process is disabled because of the previous error when starting the daemon.\n- `NX_DAEMON` is set to `false`.\n- `useDaemon` is set to false in `nx.json`\n\n`NX_DAEMON` env variable takes precedence:\n\n- If it is set to true, the daemon will always be used.\n- If it is set to false, the graph will always be computed in the current process.\n\nTip: If you want to debug project graph creation, run your command with NX_DAEMON=false.\n\nNx uses two layers of caching: the information about explicit dependencies stored on the disk and the information\nstored in the daemon process. To reset both run: `nx reset`.\n\n#### Returns\n\n`Promise`<[`ProjectGraph`](../../devkit/index#projectgraph)\\>\n\n---\n\n### defaultTasksRunner\n\n▸ `Const` **defaultTasksRunner**(`tasks`, `options`, `context?`): `any`\n\n#### Parameters\n\n| Name | Type |\n| :--------------------------- | :------------------------------------------------------------------------------------ |\n| `tasks` | [`Task`](../../devkit/index#task)[] |\n| `options` | [`DefaultTasksRunnerOptions`](../../devkit/index#defaulttasksrunneroptions) |\n| `context?` | `Object` |\n| `context.hasher?` | [`Hasher`](../../devkit/index#hasher) |\n| `context.initiatingProject?` | `string` |\n| `context.nxArgs` | `NxArgs` |\n| `context.nxJson` | [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)<`string`[] \\| `\"*\"`\\> |\n| `context.projectGraph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> |\n| `context.target?` | `string` |\n| `context.taskGraph?` | [`TaskGraph`](../../devkit/index#taskgraph) |\n\n#### Returns\n\n`any`\n\n---\n\n### detectPackageManager\n\n▸ **detectPackageManager**(`dir?`): [`PackageManager`](../../devkit/index#packagemanager)\n\nDetects which package manager is used in the workspace based on the lock file.\n\n#### Parameters\n\n| Name | Type | Default value |\n| :---- | :------- | :------------ |\n| `dir` | `string` | `''` |\n\n#### Returns\n\n[`PackageManager`](../../devkit/index#packagemanager)\n\n---\n\n### detectWorkspaceScope\n\n▸ **detectWorkspaceScope**(`packageName`): `string`\n\nDetect workspace scope from the package.json name\n\n#### Parameters\n\n| Name | Type |\n| :------------ | :------- |\n| `packageName` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### formatFiles\n\n▸ **formatFiles**(`tree`): `Promise`<`void`\\>\n\nFormats all the created or updated files using Prettier\n\n#### Parameters\n\n| Name | Type | Description |\n| :----- | :-------------------------------- | :------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n\n#### Returns\n\n`Promise`<`void`\\>\n\n---\n\n### generateFiles\n\n▸ **generateFiles**(`tree`, `srcFolder`, `target`, `substitutions`): `void`\n\nGenerates a folder of files based on provided templates.\n\nWhile doing so it performs two substitutions:\n\n- Substitutes segments of file names surrounded by \\_\\_\n- Uses ejs to substitute values in templates\n\nExamples:\n\n```typescript\ngenerateFiles(tree, path.join(__dirname, 'files'), './tools/scripts', {\n tmpl: '',\n name: 'myscript',\n});\n```\n\nThis command will take all the files from the `files` directory next to the place where the command is invoked from.\nIt will replace all `__tmpl__` with '' and all `__name__` with 'myscript' in the file names, and will replace all\n`<%= name %>` with `myscript` in the files themselves.\n`tmpl: ''` is a common pattern. With it you can name files like this: `index.ts__tmpl__`, so your editor\ndoesn't get confused about incorrect TypeScript files.\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------------- | :-------------------------------- | :-------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `srcFolder` | `string` | the source folder of files (absolute path) |\n| `target` | `string` | the target folder (relative to the tree root) |\n| `substitutions` | `Object` | an object of key-value pairs |\n\n#### Returns\n\n`void`\n\n---\n\n### getImportPath\n\n▸ **getImportPath**(`npmScope`, `projectDirectory`): `string`\n\nPrefixes project name with npm scope\n\n#### Parameters\n\n| Name | Type |\n| :----------------- | :------- |\n| `npmScope` | `string` |\n| `projectDirectory` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### getOutputsForTargetAndConfiguration\n\n▸ **getOutputsForTargetAndConfiguration**(`task`, `node`): `any`\n\nReturns the list of outputs that will be cached.\n\n#### Parameters\n\n| Name | Type | Description |\n| :----- | :------------------------------------------------------------------------------ | :-------------------------------------------------------- |\n| `task` | `Pick`<[`Task`](../../devkit/index#task), `\"target\"` \\| `\"overrides\"`\\> | target + overrides |\n| `node` | [`ProjectGraphProjectNode`](../../devkit/index#projectgraphprojectnode)<`any`\\> | ProjectGraphProjectNode object that the task runs against |\n\n#### Returns\n\n`any`\n\n---\n\n### getPackageManagerCommand\n\n▸ **getPackageManagerCommand**(`packageManager?`): `PackageManagerCommands`\n\nReturns commands for the package manager used in the workspace.\nBy default, the package manager is derived based on the lock file,\nbut it can also be passed in explicitly.\n\nExample:\n\n```javascript\nexecSync(`${getPackageManagerCommand().addDev} my-dev-package`);\n```\n\n#### Parameters\n\n| Name | Type |\n| :--------------- | :---------------------------------------------------- |\n| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) |\n\n#### Returns\n\n`PackageManagerCommands`\n\n---\n\n### getPackageManagerVersion\n\n▸ **getPackageManagerVersion**(`packageManager?`): `string`\n\nReturns the version of the package manager used in the workspace.\nBy default, the package manager is derived based on the lock file,\nbut it can also be passed in explicitly.\n\n#### Parameters\n\n| Name | Type |\n| :--------------- | :---------------------------------------------------- |\n| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) |\n\n#### Returns\n\n`string`\n\n---\n\n### getProjects\n\n▸ **getProjects**(`tree`): `Map`<`string`, [`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\nGet a map of all projects in a workspace.\n\nUse [readProjectConfiguration](../../devkit/index#readprojectconfiguration) if only one project is needed.\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n`Map`<`string`, [`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\n---\n\n### getWorkspaceLayout\n\n▸ **getWorkspaceLayout**(`tree`): `Object`\n\nReturns workspace defaults. It includes defaults folders for apps and libs,\nand the default scope.\n\nExample:\n\n```typescript\n{ appsDir: 'apps', libsDir: 'libs', npmScope: 'myorg' }\n```\n\n#### Parameters\n\n| Name | Type | Description |\n| :----- | :-------------------------------- | :--------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | file system tree |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :-------------------- | :-------- |\n| `appsDir` | `string` |\n| `libsDir` | `string` |\n| `npmScope` | `string` |\n| `standaloneAsDefault` | `boolean` |\n\n---\n\n### getWorkspacePath\n\n▸ **getWorkspacePath**(`tree`): `\"/angular.json\"` \\| `\"/workspace.json\"` \\| `null`\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n`\"/angular.json\"` \\| `\"/workspace.json\"` \\| `null`\n\n---\n\n### installPackagesTask\n\n▸ **installPackagesTask**(`tree`, `alwaysRun?`, `cwd?`, `packageManager?`): `void`\n\nRuns `npm install` or `yarn install`. It will skip running the install if\n`package.json` hasn't changed at all or it hasn't changed since the last invocation.\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :--------------- | :---------------------------------------------------- | :------------ | :------------------------------------------------------------ |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` | the file system tree |\n| `alwaysRun` | `boolean` | `false` | always run the command even if `package.json` hasn't changed. |\n| `cwd` | `string` | `''` | - |\n| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) | `undefined` | - |\n\n#### Returns\n\n`void`\n\n---\n\n### isStandaloneProject\n\n▸ **isStandaloneProject**(`tree`, `project`): `boolean`\n\nReturns if a project has a standalone configuration (project.json).\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------- | :-------------------------------- | :------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `project` | `string` | the project name |\n\n#### Returns\n\n`boolean`\n\n---\n\n### joinPathFragments\n\n▸ **joinPathFragments**(...`fragments`): `string`\n\nNormalized path fragments and joins them\n\n#### Parameters\n\n| Name | Type |\n| :------------- | :--------- |\n| `...fragments` | `string`[] |\n\n#### Returns\n\n`string`\n\n---\n\n### moveFilesToNewDirectory\n\n▸ **moveFilesToNewDirectory**(`tree`, `oldDir`, `newDir`): `void`\n\nAnalogous to cp -r oldDir newDir\n\n#### Parameters\n\n| Name | Type |\n| :------- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `oldDir` | `string` |\n| `newDir` | `string` |\n\n#### Returns\n\n`void`\n\n---\n\n### names\n\n▸ **names**(`name`): `Object`\n\nUtil function to generate different strings based off the provided name.\n\nExamples:\n\n```typescript\nnames('my-name'); // {name: 'my-name', className: 'MyName', propertyName: 'myName', constantName: 'MY_NAME', fileName: 'my-name'}\nnames('myName'); // {name: 'myName', className: 'MyName', propertyName: 'myName', constantName: 'MY_NAME', fileName: 'my-name'}\n```\n\n#### Parameters\n\n| Name | Type |\n| :----- | :------- |\n| `name` | `string` |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :------------- | :------- |\n| `className` | `string` |\n| `constantName` | `string` |\n| `fileName` | `string` |\n| `name` | `string` |\n| `propertyName` | `string` |\n\n---\n\n### normalizePath\n\n▸ **normalizePath**(`osSpecificPath`): `string`\n\nCoverts an os specific path to a unix style path\n\n#### Parameters\n\n| Name | Type |\n| :--------------- | :------- |\n| `osSpecificPath` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### offsetFromRoot\n\n▸ **offsetFromRoot**(`fullPathToDir`): `string`\n\nCalculates an offset from the root of the workspace, which is useful for\nconstructing relative URLs.\n\nExamples:\n\n```typescript\noffsetFromRoot('apps/mydir/myapp/'); // returns \"../../../\"\n```\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------------- | :------- | :------------- |\n| `fullPathToDir` | `string` | directory path |\n\n#### Returns\n\n`string`\n\n---\n\n### parseJson\n\n▸ **parseJson**<`T`\\>(`input`, `options?`): `T`\n\nParses the given JSON string and returns the object the JSON content represents.\nBy default javascript-style comments are allowed.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :-------------------------------------------------------- | :--------------------- |\n| `input` | `string` | JSON content as string |\n| `options?` | [`JsonParseOptions`](../../devkit/index#jsonparseoptions) | JSON parse options |\n\n#### Returns\n\n`T`\n\nObject the JSON content represents\n\n---\n\n### parseTargetString\n\n▸ **parseTargetString**(`targetString`): [`Target`](../../devkit/index#target)\n\nParses a target string into {project, target, configuration}\n\nExamples:\n\n```typescript\nparseTargetString('proj:test'); // returns { project: \"proj\", target: \"test\" }\nparseTargetString('proj:test:production'); // returns { project: \"proj\", target: \"test\", configuration: \"production\" }\n```\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------- | :------- | :--------------- |\n| `targetString` | `string` | target reference |\n\n#### Returns\n\n[`Target`](../../devkit/index#target)\n\n---\n\n### readAllWorkspaceConfiguration\n\n▸ **readAllWorkspaceConfiguration**(): [`ProjectsConfigurations`](../../devkit/index#projectsconfigurations) & [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n**`deprecated`** Use readProjectsConfigurationFromProjectGraph(await createProjectGraphAsync())\n\n#### Returns\n\n[`ProjectsConfigurations`](../../devkit/index#projectsconfigurations) & [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n---\n\n### readCachedProjectGraph\n\n▸ **readCachedProjectGraph**(): [`ProjectGraph`](../../devkit/index#projectgraph)<[`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\nSynchronously reads the latest cached copy of the workspace's ProjectGraph.\n\n**`throws`** {Error} if there is no cached ProjectGraph to read from\n\n#### Returns\n\n[`ProjectGraph`](../../devkit/index#projectgraph)<[`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\n---\n\n### readJson\n\n▸ **readJson**<`T`\\>(`tree`, `path`, `options?`): `T`\n\nReads a json file, removes all comments and parses JSON.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :-------------------------------------------------------- | :-------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | file system tree |\n| `path` | `string` | file path |\n| `options?` | [`JsonParseOptions`](../../devkit/index#jsonparseoptions) | Optional JSON Parse Options |\n\n#### Returns\n\n`T`\n\n---\n\n### readJsonFile\n\n▸ **readJsonFile**<`T`\\>(`path`, `options?`): `T`\n\nReads a JSON file and returns the object the JSON content represents.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------- | :----------------- |\n| `path` | `string` | A path to a file. |\n| `options?` | `JsonReadOptions` | JSON parse options |\n\n#### Returns\n\n`T`\n\nObject the JSON content of the file represents\n\n---\n\n### readNxJson\n\n▸ **readNxJson**(): [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n#### Returns\n\n[`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n---\n\n### readProjectConfiguration\n\n▸ **readProjectConfiguration**(`tree`, `projectName`): [`ProjectConfiguration`](../../devkit/index#projectconfiguration)\n\nReads a project configuration.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will read from either file.\n\n**`throws`** If supplied projectName cannot be found\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------ | :-------------------------------- | :---------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `projectName` | `string` | unique name. Often directories are part of the name (e.g., mydir-mylib) |\n\n#### Returns\n\n[`ProjectConfiguration`](../../devkit/index#projectconfiguration)\n\n---\n\n### readTargetOptions\n\n▸ **readTargetOptions**<`T`\\>(`__namedParameters`, `context`): `T`\n\nReads and combines options for a given target.\n\nWorks as if you invoked the target yourself without passing any command lint overrides.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Parameters\n\n| Name | Type |\n| :------------------ | :------------------------------------------------------ |\n| `__namedParameters` | [`Target`](../../devkit/index#target) |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n#### Returns\n\n`T`\n\n---\n\n### readWorkspaceConfiguration\n\n▸ **readWorkspaceConfiguration**(`tree`): [`WorkspaceConfiguration`](../../devkit/index#workspaceconfiguration)\n\nRead general workspace configuration such as the default project or cli settings\n\nThis does _not_ provide projects configuration, use [readProjectConfiguration](../../devkit/index#readprojectconfiguration) instead.\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n[`WorkspaceConfiguration`](../../devkit/index#workspaceconfiguration)\n\n---\n\n### removeDependenciesFromPackageJson\n\n▸ **removeDependenciesFromPackageJson**(`tree`, `dependencies`, `devDependencies`, `packageJsonPath?`): [`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nRemove Dependencies and Dev Dependencies from package.json\n\nFor example:\n\n```typescript\nremoveDependenciesFromPackageJson(tree, ['react'], ['jest']);\n```\n\nThis will **remove** `react` and `jest` from the dependencies and devDependencies sections of package.json respectively.\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :---------------- | :-------------------------------- | :--------------- | :-------------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` | - |\n| `dependencies` | `string`[] | `undefined` | Dependencies to be removed from the dependencies section of package.json |\n| `devDependencies` | `string`[] | `undefined` | Dependencies to be removed from the devDependencies section of package.json |\n| `packageJsonPath` | `string` | `'package.json'` | - |\n\n#### Returns\n\n[`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nCallback to uninstall dependencies only if necessary. undefined is returned if changes are not necessary.\n\n---\n\n### removeProjectConfiguration\n\n▸ **removeProjectConfiguration**(`tree`, `projectName`): `void`\n\nRemoves the configuration of an existing project.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will update either file.\n\n#### Parameters\n\n| Name | Type |\n| :------------ | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `projectName` | `string` |\n\n#### Returns\n\n`void`\n\n---\n\n### reverse\n\n▸ **reverse**(`graph`): [`ProjectGraph`](../../devkit/index#projectgraph)\n\nReturns a new project graph where all the edges are reversed.\n\nFor instance, if project A depends on B, in the reversed graph\nB will depend on A.\n\n#### Parameters\n\n| Name | Type |\n| :------ | :-------------------------------------------------------- |\n| `graph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> |\n\n#### Returns\n\n[`ProjectGraph`](../../devkit/index#projectgraph)\n\n---\n\n### runExecutor\n\n▸ **runExecutor**<`T`\\>(`targetDescription`, `overrides`, `context`): `Promise`<`AsyncIterableIterator`<`T`\\>\\>\n\nLoads and invokes executor.\n\nThis is analogous to invoking executor from the terminal, with the exception\nthat the params aren't parsed from the string, but instead provided parsed already.\n\nApart from that, it works the same way:\n\n- it will load the workspace configuration\n- it will resolve the target\n- it will load the executor and the schema\n- it will load the options for the appropriate configuration\n- it will run the validations and will set the default\n- and, of course, it will invoke the executor\n\nExample:\n\n```typescript\nfor await (const s of await runExecutor(\n { project: 'myproj', target: 'serve' },\n { watch: true },\n context\n)) {\n // s.success\n}\n```\n\nNote that the return value is a promise of an iterator, so you need to await before iterating over it.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :--------------- |\n| `T` | extends `Object` |\n\n#### Parameters\n\n| Name | Type |\n| :--------------------------------- | :------------------------------------------------------ |\n| `targetDescription` | `Object` |\n| `targetDescription.configuration?` | `string` |\n| `targetDescription.project` | `string` |\n| `targetDescription.target` | `string` |\n| `overrides` | `Object` |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n#### Returns\n\n`Promise`<`AsyncIterableIterator`<`T`\\>\\>\n\n---\n\n### serializeJson\n\n▸ **serializeJson**<`T`\\>(`input`, `options?`): `string`\n\nSerializes the given data to a JSON string.\nBy default the JSON string is formatted with a 2 space intendation to be easy readable.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------------------------- |\n| `T` | extends `object` = `object` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------------------------------------------------------- | :---------------------------------------- |\n| `input` | `T` | Object which should be serialized to JSON |\n| `options?` | [`JsonSerializeOptions`](../../devkit/index#jsonserializeoptions) | JSON serialize options |\n\n#### Returns\n\n`string`\n\nthe formatted JSON representation of the object\n\n---\n\n### stripIndents\n\n▸ **stripIndents**(`strings`, ...`values`): `string`\n\nRemoves indents, which is useful for printing warning and messages.\n\nExample:\n\n```typescript\nstripIndents`\n Options:\n - option1\n - option2\n`;\n```\n\n#### Parameters\n\n| Name | Type |\n| :---------- | :--------------------- |\n| `strings` | `TemplateStringsArray` |\n| `...values` | `any`[] |\n\n#### Returns\n\n`string`\n\n---\n\n### stripJsonComments\n\n▸ `Const` **stripJsonComments**(`text`, `replaceCh?`): `string`\n\nTakes JSON with JavaScript-style comments and remove\nthem. Optionally replaces every none-newline character\nof comments with a replaceCharacter\n\n#### Parameters\n\n| Name | Type |\n| :----------- | :------- |\n| `text` | `string` |\n| `replaceCh?` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### targetToTargetString\n\n▸ **targetToTargetString**(`target`): `string`\n\nReturns a string in the format \"project:target[:configuration]\" for the target\n\n#### Parameters\n\n| Name | Type | Description |\n| :------- | :------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `target` | [`Target`](../../devkit/index#target) | target object Examples: `typescript targetToTargetString({ project: \"proj\", target: \"test\" }) // returns \"proj:test\" targetToTargetString({ project: \"proj\", target: \"test\", configuration: \"production\" }) // returns \"proj:test:production\" ` |\n\n#### Returns\n\n`string`\n\n---\n\n### toJS\n\n▸ **toJS**(`tree`): `void`\n\nRename and transpile any new typescript files created to javascript files\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n`void`\n\n---\n\n### updateJson\n\n▸ **updateJson**<`T`, `U`\\>(`tree`, `path`, `updater`, `options?`): `void`\n\nUpdates a JSON value to the file system tree\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n| `U` | extends `object` = `T` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | File system tree |\n| `path` | `string` | Path of JSON file in the Tree |\n| `updater` | (`value`: `T`) => `U` | Function that maps the current value of a JSON document to a new value to be written to the document |\n| `options?` | [`JsonParseOptions`](../../devkit/index#jsonparseoptions) & [`JsonSerializeOptions`](../../devkit/index#jsonserializeoptions) | Optional JSON Parse and Serialize Options |\n\n#### Returns\n\n`void`\n\n---\n\n### updateProjectConfiguration\n\n▸ **updateProjectConfiguration**(`tree`, `projectName`, `projectConfiguration`): `void`\n\nUpdates the configuration of an existing project.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will update either files.\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------------------- | :---------------------------------------------------------------- | :---------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `projectName` | `string` | unique name. Often directories are part of the name (e.g., mydir-mylib) |\n| `projectConfiguration` | [`ProjectConfiguration`](../../devkit/index#projectconfiguration) | project configuration |\n\n#### Returns\n\n`void`\n\n---\n\n### updateTsConfigsToJs\n\n▸ **updateTsConfigsToJs**(`tree`, `options`): `void`\n\n#### Parameters\n\n| Name | Type |\n| :-------------------- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `options` | `Object` |\n| `options.projectRoot` | `string` |\n\n#### Returns\n\n`void`\n\n---\n\n### updateWorkspaceConfiguration\n\n▸ **updateWorkspaceConfiguration**(`tree`, `workspaceConfig`): `void`\n\nUpdate general workspace configuration such as the default project or cli settings.\n\nThis does _not_ update projects configuration, use [updateProjectConfiguration](../../devkit/index#updateprojectconfiguration) or [addProjectConfiguration](../../devkit/index#addprojectconfiguration) instead.\n\n#### Parameters\n\n| Name | Type |\n| :---------------- | :-------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `workspaceConfig` | [`WorkspaceConfiguration`](../../devkit/index#workspaceconfiguration) |\n\n#### Returns\n\n`void`\n\n---\n\n### visitNotIgnoredFiles\n\n▸ **visitNotIgnoredFiles**(`tree`, `dirPath?`, `visitor`): `void`\n\nUtility to act on all files in a tree that are not ignored by git.\n\n#### Parameters\n\n| Name | Type | Default value |\n| :-------- | :-------------------------------- | :------------ |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` |\n| `dirPath` | `string` | `tree.root` |\n| `visitor` | (`path`: `string`) => `void` | `undefined` |\n\n#### Returns\n\n`void`\n\n---\n\n### workspaceLayout\n\n▸ **workspaceLayout**(): `Object`\n\nReturns information about where apps and libs will be created.\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :-------- | :------- |\n| `appsDir` | `string` |\n| `libsDir` | `string` |\n\n---\n\n### writeJson\n\n▸ **writeJson**<`T`\\>(`tree`, `path`, `value`, `options?`): `void`\n\nWrites a JSON value to the file system tree\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------------------------- |\n| `T` | extends `object` = `object` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------------------------------------------------------- | :------------------------------ |\n| `tree` | [`Tree`](../../devkit/index#tree) | File system tree |\n| `path` | `string` | Path of JSON file in the Tree |\n| `value` | `T` | Serializable value to write |\n| `options?` | [`JsonSerializeOptions`](../../devkit/index#jsonserializeoptions) | Optional JSON Serialize Options |\n\n#### Returns\n\n`void`\n\n---\n\n### writeJsonFile\n\n▸ **writeJsonFile**<`T`\\>(`path`, `data`, `options?`): `void`\n\nSerializes the given data to JSON and writes it to a file.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------------------------- |\n| `T` | extends `object` = `object` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :----------------- | :-------------------------------------------------------------- |\n| `path` | `string` | A path to a file. |\n| `data` | `T` | data which should be serialized to JSON and written to the file |\n| `options?` | `JsonWriteOptions` | JSON serialize options |\n\n#### Returns\n\n`void`\n" + "content": "# Module: index\n\nThe Nx Devkit is the underlying technology used to customize Nx to support\ndifferent technologies and custom use-cases. It contains many utility\nfunctions for reading and writing files, updating configuration,\nworking with Abstract Syntax Trees(ASTs), and more.\n\nAs with most things in Nx, the core of Nx Devkit is very simple.\nIt only uses language primitives and immutable objects\n(the tree being the only exception).\n\n## Table of contents\n\n### Project Graph Enumerations\n\n- [DependencyType](../../devkit/index#dependencytype)\n\n### Utils Enumerations\n\n- [ChangeType](../../devkit/index#changetype)\n\n### Project Graph Classes\n\n- [ProjectGraphBuilder](../../devkit/index#projectgraphbuilder)\n\n### Utils Classes\n\n- [Hasher](../../devkit/index#hasher)\n\n### Workspace Classes\n\n- [Workspaces](../../devkit/index#workspaces)\n\n### Commands Interfaces\n\n- [Target](../../devkit/index#target)\n\n### Other Interfaces\n\n- [NxPlugin](../../devkit/index#nxplugin)\n\n### Project Graph Interfaces\n\n- [FileData](../../devkit/index#filedata)\n- [ProjectFileMap](../../devkit/index#projectfilemap)\n- [ProjectGraph](../../devkit/index#projectgraph)\n- [ProjectGraphDependency](../../devkit/index#projectgraphdependency)\n- [ProjectGraphExternalNode](../../devkit/index#projectgraphexternalnode)\n- [ProjectGraphProcessorContext](../../devkit/index#projectgraphprocessorcontext)\n- [ProjectGraphProjectNode](../../devkit/index#projectgraphprojectnode)\n- [ProjectGraphV4](../../devkit/index#projectgraphv4)\n\n### Tree Interfaces\n\n- [FileChange](../../devkit/index#filechange)\n- [Tree](../../devkit/index#tree)\n\n### Utils Interfaces\n\n- [DefaultTasksRunnerOptions](../../devkit/index#defaulttasksrunneroptions)\n- [Hash](../../devkit/index#hash)\n- [JsonParseOptions](../../devkit/index#jsonparseoptions)\n- [JsonSerializeOptions](../../devkit/index#jsonserializeoptions)\n- [RemoteCache](../../devkit/index#remotecache)\n- [StringDeletion](../../devkit/index#stringdeletion)\n- [StringInsertion](../../devkit/index#stringinsertion)\n\n### Workspace Interfaces\n\n- [ExecutorContext](../../devkit/index#executorcontext)\n- [ExecutorsJson](../../devkit/index#executorsjson)\n- [GeneratorsJson](../../devkit/index#generatorsjson)\n- [HasherContext](../../devkit/index#hashercontext)\n- [ImplicitJsonSubsetDependency](../../devkit/index#implicitjsonsubsetdependency)\n- [MigrationsJson](../../devkit/index#migrationsjson)\n- [NxAffectedConfig](../../devkit/index#nxaffectedconfig)\n- [NxJsonConfiguration](../../devkit/index#nxjsonconfiguration)\n- [ProjectConfiguration](../../devkit/index#projectconfiguration)\n- [ProjectsConfigurations](../../devkit/index#projectsconfigurations)\n- [TargetConfiguration](../../devkit/index#targetconfiguration)\n- [TargetDependencyConfig](../../devkit/index#targetdependencyconfig)\n- [Task](../../devkit/index#task)\n- [TaskGraph](../../devkit/index#taskgraph)\n- [Workspace](../../devkit/index#workspace)\n\n### Generators Type aliases\n\n- [WorkspaceConfiguration](../../devkit/index#workspaceconfiguration)\n\n### Other Type aliases\n\n- [ProjectTargetConfigurator](../../devkit/index#projecttargetconfigurator)\n\n### Package Manager Type aliases\n\n- [PackageManager](../../devkit/index#packagemanager)\n\n### Project Graph Type aliases\n\n- [ProjectGraphNode](../../devkit/index#projectgraphnode)\n\n### Utils Type aliases\n\n- [StringChange](../../devkit/index#stringchange)\n\n### Workspace Type aliases\n\n- [CustomHasher](../../devkit/index#customhasher)\n- [Executor](../../devkit/index#executor)\n- [Generator](../../devkit/index#generator)\n- [GeneratorCallback](../../devkit/index#generatorcallback)\n- [ImplicitDependencyEntry](../../devkit/index#implicitdependencyentry)\n- [ProjectType](../../devkit/index#projecttype)\n- [TaskGraphExecutor](../../devkit/index#taskgraphexecutor)\n- [WorkspaceJsonConfiguration](../../devkit/index#workspacejsonconfiguration)\n\n### Logger Variables\n\n- [logger](../../devkit/index#logger)\n\n### Utils Variables\n\n- [appRootPath](../../devkit/index#approotpath)\n- [cacheDir](../../devkit/index#cachedir)\n- [output](../../devkit/index#output)\n- [workspaceRoot](../../devkit/index#workspaceroot)\n\n### Functions\n\n- [addDependenciesToPackageJson](../../devkit/index#adddependenciestopackagejson)\n- [addProjectConfiguration](../../devkit/index#addprojectconfiguration)\n- [applyChangesToString](../../devkit/index#applychangestostring)\n- [convertNxExecutor](../../devkit/index#convertnxexecutor)\n- [convertNxGenerator](../../devkit/index#convertnxgenerator)\n- [createProjectGraphAsync](../../devkit/index#createprojectgraphasync)\n- [defaultTasksRunner](../../devkit/index#defaulttasksrunner)\n- [detectPackageManager](../../devkit/index#detectpackagemanager)\n- [detectWorkspaceScope](../../devkit/index#detectworkspacescope)\n- [formatFiles](../../devkit/index#formatfiles)\n- [generateFiles](../../devkit/index#generatefiles)\n- [getImportPath](../../devkit/index#getimportpath)\n- [getOutputsForTargetAndConfiguration](../../devkit/index#getoutputsfortargetandconfiguration)\n- [getPackageManagerCommand](../../devkit/index#getpackagemanagercommand)\n- [getPackageManagerVersion](../../devkit/index#getpackagemanagerversion)\n- [getProjects](../../devkit/index#getprojects)\n- [getWorkspaceLayout](../../devkit/index#getworkspacelayout)\n- [getWorkspacePath](../../devkit/index#getworkspacepath)\n- [installPackagesTask](../../devkit/index#installpackagestask)\n- [isStandaloneProject](../../devkit/index#isstandaloneproject)\n- [joinPathFragments](../../devkit/index#joinpathfragments)\n- [moveFilesToNewDirectory](../../devkit/index#movefilestonewdirectory)\n- [names](../../devkit/index#names)\n- [normalizePath](../../devkit/index#normalizepath)\n- [offsetFromRoot](../../devkit/index#offsetfromroot)\n- [parseJson](../../devkit/index#parsejson)\n- [parseTargetString](../../devkit/index#parsetargetstring)\n- [readAllWorkspaceConfiguration](../../devkit/index#readallworkspaceconfiguration)\n- [readCachedProjectGraph](../../devkit/index#readcachedprojectgraph)\n- [readJson](../../devkit/index#readjson)\n- [readJsonFile](../../devkit/index#readjsonfile)\n- [readNxJson](../../devkit/index#readnxjson)\n- [readProjectConfiguration](../../devkit/index#readprojectconfiguration)\n- [readTargetOptions](../../devkit/index#readtargetoptions)\n- [readWorkspaceConfiguration](../../devkit/index#readworkspaceconfiguration)\n- [removeDependenciesFromPackageJson](../../devkit/index#removedependenciesfrompackagejson)\n- [removeProjectConfiguration](../../devkit/index#removeprojectconfiguration)\n- [reverse](../../devkit/index#reverse)\n- [runExecutor](../../devkit/index#runexecutor)\n- [serializeJson](../../devkit/index#serializejson)\n- [stripIndents](../../devkit/index#stripindents)\n- [stripJsonComments](../../devkit/index#stripjsoncomments)\n- [targetToTargetString](../../devkit/index#targettotargetstring)\n- [toJS](../../devkit/index#tojs)\n- [updateJson](../../devkit/index#updatejson)\n- [updateProjectConfiguration](../../devkit/index#updateprojectconfiguration)\n- [updateTsConfigsToJs](../../devkit/index#updatetsconfigstojs)\n- [updateWorkspaceConfiguration](../../devkit/index#updateworkspaceconfiguration)\n- [visitNotIgnoredFiles](../../devkit/index#visitnotignoredfiles)\n- [workspaceLayout](../../devkit/index#workspacelayout)\n- [writeJson](../../devkit/index#writejson)\n- [writeJsonFile](../../devkit/index#writejsonfile)\n\n## Project Graph Enumerations\n\n### DependencyType\n\n• **DependencyType**: `Object`\n\n---\n\n## Utils Enumerations\n\n### ChangeType\n\n• **ChangeType**: `Object`\n\n## Project Graph Classes\n\n### ProjectGraphBuilder\n\n• **ProjectGraphBuilder**: `Object`\n\n---\n\n## Utils Classes\n\n### Hasher\n\n• **Hasher**: `Object`\n\n---\n\n## Workspace Classes\n\n### Workspaces\n\n• **Workspaces**: `Object`\n\n## Commands Interfaces\n\n### Target\n\n• **Target**: `Object`\n\n---\n\n## Other Interfaces\n\n### NxPlugin\n\n• **NxPlugin**: `Object`\n\nA plugin for Nx\n\n---\n\n## Project Graph Interfaces\n\n### FileData\n\n• **FileData**: `Object`\n\n---\n\n### ProjectFileMap\n\n• **ProjectFileMap**: `Object`\n\n---\n\n### ProjectGraph\n\n• **ProjectGraph**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n### ProjectGraphDependency\n\n• **ProjectGraphDependency**: `Object`\n\n---\n\n### ProjectGraphExternalNode\n\n• **ProjectGraphExternalNode**: `Object`\n\n---\n\n### ProjectGraphProcessorContext\n\n• **ProjectGraphProcessorContext**: `Object`\n\n---\n\n### ProjectGraphProjectNode\n\n• **ProjectGraphProjectNode**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n### ProjectGraphV4\n\n• **ProjectGraphV4**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n## Tree Interfaces\n\n### FileChange\n\n• **FileChange**: `Object`\n\n---\n\n### Tree\n\n• **Tree**: `Object`\n\n---\n\n## Utils Interfaces\n\n### DefaultTasksRunnerOptions\n\n• **DefaultTasksRunnerOptions**: `Object`\n\n---\n\n### Hash\n\n• **Hash**: `Object`\n\n---\n\n### JsonParseOptions\n\n• **JsonParseOptions**: `Object`\n\n---\n\n### JsonSerializeOptions\n\n• **JsonSerializeOptions**: `Object`\n\n---\n\n### RemoteCache\n\n• **RemoteCache**: `Object`\n\n---\n\n### StringDeletion\n\n• **StringDeletion**: `Object`\n\n---\n\n### StringInsertion\n\n• **StringInsertion**: `Object`\n\n---\n\n## Workspace Interfaces\n\n### ExecutorContext\n\n• **ExecutorContext**: `Object`\n\n---\n\n### ExecutorsJson\n\n• **ExecutorsJson**: `Object`\n\n---\n\n### GeneratorsJson\n\n• **GeneratorsJson**: `Object`\n\n---\n\n### HasherContext\n\n• **HasherContext**: `Object`\n\n---\n\n### ImplicitJsonSubsetDependency\n\n• **ImplicitJsonSubsetDependency**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :------------------ |\n| `T` | `\"*\"` \\| `string`[] |\n\n---\n\n### MigrationsJson\n\n• **MigrationsJson**: `Object`\n\n---\n\n### NxAffectedConfig\n\n• **NxAffectedConfig**: `Object`\n\n---\n\n### NxJsonConfiguration\n\n• **NxJsonConfiguration**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :------------------ |\n| `T` | `\"*\"` \\| `string`[] |\n\n---\n\n### ProjectConfiguration\n\n• **ProjectConfiguration**: `Object`\n\n---\n\n### ProjectsConfigurations\n\n• **ProjectsConfigurations**: `Object`\n\n---\n\n### TargetConfiguration\n\n• **TargetConfiguration**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n### TargetDependencyConfig\n\n• **TargetDependencyConfig**: `Object`\n\n---\n\n### Task\n\n• **Task**: `Object`\n\n---\n\n### TaskGraph\n\n• **TaskGraph**: `Object`\n\n---\n\n### Workspace\n\n• **Workspace**: `Object`\n\n## Generators Type aliases\n\n### WorkspaceConfiguration\n\nƬ **WorkspaceConfiguration**: `Omit`<[`ProjectsConfigurations`](../../devkit/index#projectsconfigurations), `\"projects\"`\\> & `Partial`<[`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\\>\n\n---\n\n## Other Type aliases\n\n### ProjectTargetConfigurator\n\nƬ **ProjectTargetConfigurator**: (`file`: `string`) => `Record`<`string`, [`TargetConfiguration`](../../devkit/index#targetconfiguration)\\>\n\n#### Type declaration\n\n▸ (`file`): `Record`<`string`, [`TargetConfiguration`](../../devkit/index#targetconfiguration)\\>\n\n##### Parameters\n\n| Name | Type |\n| :----- | :------- |\n| `file` | `string` |\n\n##### Returns\n\n`Record`<`string`, [`TargetConfiguration`](../../devkit/index#targetconfiguration)\\>\n\n---\n\n## Package Manager Type aliases\n\n### PackageManager\n\nƬ **PackageManager**: `\"yarn\"` \\| `\"pnpm\"` \\| `\"npm\"`\n\n---\n\n## Project Graph Type aliases\n\n### ProjectGraphNode\n\nƬ **ProjectGraphNode**<`T`\\>: [`ProjectGraphProjectNode`](../../devkit/index#projectgraphprojectnode)<`T`\\> \\| [`ProjectGraphExternalNode`](../../devkit/index#projectgraphexternalnode)\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n---\n\n## Utils Type aliases\n\n### StringChange\n\nƬ **StringChange**: [`StringInsertion`](../../devkit/index#stringinsertion) \\| [`StringDeletion`](../../devkit/index#stringdeletion)\n\n---\n\n## Workspace Type aliases\n\n### CustomHasher\n\nƬ **CustomHasher**: (`task`: [`Task`](../../devkit/index#task), `context`: [`HasherContext`](../../devkit/index#hashercontext)) => `Promise`<[`Hash`](../../devkit/index#hash)\\>\n\n#### Type declaration\n\n▸ (`task`, `context`): `Promise`<[`Hash`](../../devkit/index#hash)\\>\n\n##### Parameters\n\n| Name | Type |\n| :-------- | :-------------------------------------------------- |\n| `task` | [`Task`](../../devkit/index#task) |\n| `context` | [`HasherContext`](../../devkit/index#hashercontext) |\n\n##### Returns\n\n`Promise`<[`Hash`](../../devkit/index#hash)\\>\n\n---\n\n### Executor\n\nƬ **Executor**<`T`\\>: (`options`: `T`, `context`: [`ExecutorContext`](../../devkit/index#executorcontext)) => `Promise`<`Object`\\> \\| `AsyncIterableIterator`<`Object`\\>\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Type declaration\n\n▸ (`options`, `context`): `Promise`<`Object`\\> \\| `AsyncIterableIterator`<`Object`\\>\n\nImplementation of a target of a project\n\n##### Parameters\n\n| Name | Type |\n| :-------- | :------------------------------------------------------ |\n| `options` | `T` |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n##### Returns\n\n`Promise`<`Object`\\> \\| `AsyncIterableIterator`<`Object`\\>\n\n---\n\n### Generator\n\nƬ **Generator**<`T`\\>: (`tree`: `any`, `schema`: `T`) => `void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback) \\| `Promise`<`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback)\\>\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------- |\n| `T` | `unknown` |\n\n#### Type declaration\n\n▸ (`tree`, `schema`): `void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback) \\| `Promise`<`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback)\\>\n\nA function that schedules updates to the filesystem to be done atomically\n\n##### Parameters\n\n| Name | Type |\n| :------- | :---- |\n| `tree` | `any` |\n| `schema` | `T` |\n\n##### Returns\n\n`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback) \\| `Promise`<`void` \\| [`GeneratorCallback`](../../devkit/index#generatorcallback)\\>\n\n---\n\n### GeneratorCallback\n\nƬ **GeneratorCallback**: () => `void` \\| `Promise`<`void`\\>\n\n#### Type declaration\n\n▸ (): `void` \\| `Promise`<`void`\\>\n\nA callback function that is executed after changes are made to the file system\n\n##### Returns\n\n`void` \\| `Promise`<`void`\\>\n\n---\n\n### ImplicitDependencyEntry\n\nƬ **ImplicitDependencyEntry**<`T`\\>: `Object`\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :------------------ |\n| `T` | `\"*\"` \\| `string`[] |\n\n#### Index signature\n\n▪ [key: `string`]: `T` \\| [`ImplicitJsonSubsetDependency`](../../devkit/index#implicitjsonsubsetdependency)<`T`\\>\n\n---\n\n### ProjectType\n\nƬ **ProjectType**: `\"library\"` \\| `\"application\"`\n\n---\n\n### TaskGraphExecutor\n\nƬ **TaskGraphExecutor**<`T`\\>: (`taskGraph`: [`TaskGraph`](../../devkit/index#taskgraph), `options`: `Record`<`string`, `T`\\>, `overrides`: `T`, `context`: [`ExecutorContext`](../../devkit/index#executorcontext)) => `Promise`<`Record`<`string`, `Object`\\>\\>\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Type declaration\n\n▸ (`taskGraph`, `options`, `overrides`, `context`): `Promise`<`Record`<`string`, `Object`\\>\\>\n\nImplementation of a target of a project that handles multiple projects to be batched\n\n##### Parameters\n\n| Name | Type |\n| :---------- | :------------------------------------------------------ |\n| `taskGraph` | [`TaskGraph`](../../devkit/index#taskgraph) |\n| `options` | `Record`<`string`, `T`\\> |\n| `overrides` | `T` |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n##### Returns\n\n`Promise`<`Record`<`string`, `Object`\\>\\>\n\n---\n\n### WorkspaceJsonConfiguration\n\nƬ **WorkspaceJsonConfiguration**: [`ProjectsConfigurations`](../../devkit/index#projectsconfigurations)\n\n## Logger Variables\n\n### logger\n\n• **logger**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :------ | :-------------------------- |\n| `debug` | (...`s`: `any`[]) => `void` |\n| `error` | (`s`: `any`) => `void` |\n| `fatal` | (...`s`: `any`[]) => `void` |\n| `info` | (`s`: `any`) => `void` |\n| `log` | (...`s`: `any`[]) => `void` |\n| `warn` | (`s`: `any`) => `void` |\n\n---\n\n## Utils Variables\n\n### appRootPath\n\n• **appRootPath**: `string` = `workspaceRoot`\n\n---\n\n### cacheDir\n\n• **cacheDir**: `string`\n\n---\n\n### output\n\n• **output**: `CLIOutput`\n\n---\n\n### workspaceRoot\n\n• **workspaceRoot**: `string`\n\n## Functions\n\n### addDependenciesToPackageJson\n\n▸ **addDependenciesToPackageJson**(`tree`, `dependencies`, `devDependencies`, `packageJsonPath?`): [`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nAdd Dependencies and Dev Dependencies to package.json\n\nFor example:\n\n```typescript\naddDependenciesToPackageJson(tree, { react: 'latest' }, { jest: 'latest' });\n```\n\nThis will **add** `react` and `jest` to the dependencies and devDependencies sections of package.json respectively.\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :---------------- | :-------------------------------- | :--------------- | :---------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` | Tree representing file system to modify |\n| `dependencies` | `Record`<`string`, `string`\\> | `undefined` | Dependencies to be added to the dependencies section of package.json |\n| `devDependencies` | `Record`<`string`, `string`\\> | `undefined` | Dependencies to be added to the devDependencies section of package.json |\n| `packageJsonPath` | `string` | `'package.json'` | Path to package.json |\n\n#### Returns\n\n[`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nCallback to install dependencies only if necessary. undefined is returned if changes are not necessary.\n\n---\n\n### addProjectConfiguration\n\n▸ **addProjectConfiguration**(`tree`, `projectName`, `projectConfiguration`, `standalone?`): `void`\n\nAdds project configuration to the Nx workspace.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will update either files.\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------------------- | :---------------------------------------------------------------- | :----------------------------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `projectName` | `string` | unique name. Often directories are part of the name (e.g., mydir-mylib) |\n| `projectConfiguration` | [`ProjectConfiguration`](../../devkit/index#projectconfiguration) | project configuration |\n| `standalone?` | `boolean` | should the project use package.json? If false, the project config is inside workspace.json |\n\n#### Returns\n\n`void`\n\n---\n\n### applyChangesToString\n\n▸ **applyChangesToString**(`text`, `changes`): `string`\n\nApplies a list of changes to a string's original value.\n\nThis is useful when working with ASTs.\n\nFor Example, to rename a property in a method's options:\n\n```typescript\nconst code = `bootstrap({\n target: document.querySelector('#app')\n})`;\n\nconst indexOfPropertyName = 13; // Usually determined by analyzing an AST.\nconst updatedCode = applyChangesToString(code, [\n {\n type: ChangeType.Insert,\n index: indexOfPropertyName,\n text: 'element',\n },\n {\n type: ChangeType.Delete,\n start: indexOfPropertyName,\n length: 6,\n },\n]);\n\nbootstrap({\n element: document.querySelector('#app'),\n});\n```\n\n#### Parameters\n\n| Name | Type |\n| :-------- | :-------------------------------------------------- |\n| `text` | `string` |\n| `changes` | [`StringChange`](../../devkit/index#stringchange)[] |\n\n#### Returns\n\n`string`\n\n---\n\n### convertNxExecutor\n\n▸ **convertNxExecutor**(`executor`): `any`\n\nConvert an Nx Executor into an Angular Devkit Builder\n\nUse this to expose a compatible Angular Builder\n\n#### Parameters\n\n| Name | Type |\n| :--------- | :------------------------------------------------ |\n| `executor` | [`Executor`](../../devkit/index#executor)<`any`\\> |\n\n#### Returns\n\n`any`\n\n---\n\n### convertNxGenerator\n\n▸ **convertNxGenerator**<`T`\\>(`generator`, `skipWritingConfigInOldFormat?`): (`generatorOptions`: `T`) => (`tree`: `any`, `context`: `any`) => `Promise`<`any`\\>\n\nConvert an Nx Generator into an Angular Devkit Schematic.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :----------------------------- | :------------------------------------------------ | :------------ | :------------------------------------------------------------------------------------------------ |\n| `generator` | [`Generator`](../../devkit/index#generator)<`T`\\> | `undefined` | The Nx generator to convert to an Angular Devkit Schematic. |\n| `skipWritingConfigInOldFormat` | `boolean` | `false` | Whether to skip writing the configuration in the old format (the one used by the Angular DevKit). |\n\n#### Returns\n\n`fn`\n\n▸ (`generatorOptions`): (`tree`: `any`, `context`: `any`) => `Promise`<`any`\\>\n\n##### Parameters\n\n| Name | Type |\n| :----------------- | :--- |\n| `generatorOptions` | `T` |\n\n##### Returns\n\n`fn`\n\n▸ (`tree`, `context`): `Promise`<`any`\\>\n\n##### Parameters\n\n| Name | Type |\n| :-------- | :---- |\n| `tree` | `any` |\n| `context` | `any` |\n\n##### Returns\n\n`Promise`<`any`\\>\n\n---\n\n### createProjectGraphAsync\n\n▸ **createProjectGraphAsync**(): `Promise`<[`ProjectGraph`](../../devkit/index#projectgraph)\\>\n\nComputes and returns a ProjectGraph.\n\nNx will compute the graph either in a daemon process or in the current process.\n\nNx will compute it in the current process if:\n\n- The process is running in CI (CI env variable is to true or other common variables used by CI providers are set).\n- It is running in the docker container.\n- The daemon process is disabled because of the previous error when starting the daemon.\n- `NX_DAEMON` is set to `false`.\n- `useDaemon` is set to false in `nx.json`\n\n`NX_DAEMON` env variable takes precedence:\n\n- If it is set to true, the daemon will always be used.\n- If it is set to false, the graph will always be computed in the current process.\n\nTip: If you want to debug project graph creation, run your command with NX_DAEMON=false.\n\nNx uses two layers of caching: the information about explicit dependencies stored on the disk and the information\nstored in the daemon process. To reset both run: `nx reset`.\n\n#### Returns\n\n`Promise`<[`ProjectGraph`](../../devkit/index#projectgraph)\\>\n\n---\n\n### defaultTasksRunner\n\n▸ `Const` **defaultTasksRunner**(`tasks`, `options`, `context?`): `any`\n\n#### Parameters\n\n| Name | Type |\n| :--------------------------- | :------------------------------------------------------------------------------------ |\n| `tasks` | [`Task`](../../devkit/index#task)[] |\n| `options` | [`DefaultTasksRunnerOptions`](../../devkit/index#defaulttasksrunneroptions) |\n| `context?` | `Object` |\n| `context.daemon?` | `DaemonClient` |\n| `context.hasher?` | [`Hasher`](../../devkit/index#hasher) |\n| `context.initiatingProject?` | `string` |\n| `context.nxArgs` | `NxArgs` |\n| `context.nxJson` | [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)<`string`[] \\| `\"*\"`\\> |\n| `context.projectGraph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> |\n| `context.target?` | `string` |\n| `context.taskGraph?` | [`TaskGraph`](../../devkit/index#taskgraph) |\n\n#### Returns\n\n`any`\n\n---\n\n### detectPackageManager\n\n▸ **detectPackageManager**(`dir?`): [`PackageManager`](../../devkit/index#packagemanager)\n\nDetects which package manager is used in the workspace based on the lock file.\n\n#### Parameters\n\n| Name | Type | Default value |\n| :---- | :------- | :------------ |\n| `dir` | `string` | `''` |\n\n#### Returns\n\n[`PackageManager`](../../devkit/index#packagemanager)\n\n---\n\n### detectWorkspaceScope\n\n▸ **detectWorkspaceScope**(`packageName`): `string`\n\nDetect workspace scope from the package.json name\n\n#### Parameters\n\n| Name | Type |\n| :------------ | :------- |\n| `packageName` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### formatFiles\n\n▸ **formatFiles**(`tree`): `Promise`<`void`\\>\n\nFormats all the created or updated files using Prettier\n\n#### Parameters\n\n| Name | Type | Description |\n| :----- | :-------------------------------- | :------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n\n#### Returns\n\n`Promise`<`void`\\>\n\n---\n\n### generateFiles\n\n▸ **generateFiles**(`tree`, `srcFolder`, `target`, `substitutions`): `void`\n\nGenerates a folder of files based on provided templates.\n\nWhile doing so it performs two substitutions:\n\n- Substitutes segments of file names surrounded by \\_\\_\n- Uses ejs to substitute values in templates\n\nExamples:\n\n```typescript\ngenerateFiles(tree, path.join(__dirname, 'files'), './tools/scripts', {\n tmpl: '',\n name: 'myscript',\n});\n```\n\nThis command will take all the files from the `files` directory next to the place where the command is invoked from.\nIt will replace all `__tmpl__` with '' and all `__name__` with 'myscript' in the file names, and will replace all\n`<%= name %>` with `myscript` in the files themselves.\n`tmpl: ''` is a common pattern. With it you can name files like this: `index.ts__tmpl__`, so your editor\ndoesn't get confused about incorrect TypeScript files.\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------------- | :-------------------------------- | :-------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `srcFolder` | `string` | the source folder of files (absolute path) |\n| `target` | `string` | the target folder (relative to the tree root) |\n| `substitutions` | `Object` | an object of key-value pairs |\n\n#### Returns\n\n`void`\n\n---\n\n### getImportPath\n\n▸ **getImportPath**(`npmScope`, `projectDirectory`): `string`\n\nPrefixes project name with npm scope\n\n#### Parameters\n\n| Name | Type |\n| :----------------- | :------- |\n| `npmScope` | `string` |\n| `projectDirectory` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### getOutputsForTargetAndConfiguration\n\n▸ **getOutputsForTargetAndConfiguration**(`task`, `node`): `any`\n\nReturns the list of outputs that will be cached.\n\n#### Parameters\n\n| Name | Type | Description |\n| :----- | :------------------------------------------------------------------------------ | :-------------------------------------------------------- |\n| `task` | `Pick`<[`Task`](../../devkit/index#task), `\"target\"` \\| `\"overrides\"`\\> | target + overrides |\n| `node` | [`ProjectGraphProjectNode`](../../devkit/index#projectgraphprojectnode)<`any`\\> | ProjectGraphProjectNode object that the task runs against |\n\n#### Returns\n\n`any`\n\n---\n\n### getPackageManagerCommand\n\n▸ **getPackageManagerCommand**(`packageManager?`): `PackageManagerCommands`\n\nReturns commands for the package manager used in the workspace.\nBy default, the package manager is derived based on the lock file,\nbut it can also be passed in explicitly.\n\nExample:\n\n```javascript\nexecSync(`${getPackageManagerCommand().addDev} my-dev-package`);\n```\n\n#### Parameters\n\n| Name | Type |\n| :--------------- | :---------------------------------------------------- |\n| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) |\n\n#### Returns\n\n`PackageManagerCommands`\n\n---\n\n### getPackageManagerVersion\n\n▸ **getPackageManagerVersion**(`packageManager?`): `string`\n\nReturns the version of the package manager used in the workspace.\nBy default, the package manager is derived based on the lock file,\nbut it can also be passed in explicitly.\n\n#### Parameters\n\n| Name | Type |\n| :--------------- | :---------------------------------------------------- |\n| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) |\n\n#### Returns\n\n`string`\n\n---\n\n### getProjects\n\n▸ **getProjects**(`tree`): `Map`<`string`, [`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\nGet a map of all projects in a workspace.\n\nUse [readProjectConfiguration](../../devkit/index#readprojectconfiguration) if only one project is needed.\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n`Map`<`string`, [`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\n---\n\n### getWorkspaceLayout\n\n▸ **getWorkspaceLayout**(`tree`): `Object`\n\nReturns workspace defaults. It includes defaults folders for apps and libs,\nand the default scope.\n\nExample:\n\n```typescript\n{ appsDir: 'apps', libsDir: 'libs', npmScope: 'myorg' }\n```\n\n#### Parameters\n\n| Name | Type | Description |\n| :----- | :-------------------------------- | :--------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | file system tree |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :-------------------- | :-------- |\n| `appsDir` | `string` |\n| `libsDir` | `string` |\n| `npmScope` | `string` |\n| `standaloneAsDefault` | `boolean` |\n\n---\n\n### getWorkspacePath\n\n▸ **getWorkspacePath**(`tree`): `\"/angular.json\"` \\| `\"/workspace.json\"` \\| `null`\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n`\"/angular.json\"` \\| `\"/workspace.json\"` \\| `null`\n\n---\n\n### installPackagesTask\n\n▸ **installPackagesTask**(`tree`, `alwaysRun?`, `cwd?`, `packageManager?`): `void`\n\nRuns `npm install` or `yarn install`. It will skip running the install if\n`package.json` hasn't changed at all or it hasn't changed since the last invocation.\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :--------------- | :---------------------------------------------------- | :------------ | :------------------------------------------------------------ |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` | the file system tree |\n| `alwaysRun` | `boolean` | `false` | always run the command even if `package.json` hasn't changed. |\n| `cwd` | `string` | `''` | - |\n| `packageManager` | [`PackageManager`](../../devkit/index#packagemanager) | `undefined` | - |\n\n#### Returns\n\n`void`\n\n---\n\n### isStandaloneProject\n\n▸ **isStandaloneProject**(`tree`, `project`): `boolean`\n\nReturns if a project has a standalone configuration (project.json).\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------- | :-------------------------------- | :------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `project` | `string` | the project name |\n\n#### Returns\n\n`boolean`\n\n---\n\n### joinPathFragments\n\n▸ **joinPathFragments**(...`fragments`): `string`\n\nNormalized path fragments and joins them\n\n#### Parameters\n\n| Name | Type |\n| :------------- | :--------- |\n| `...fragments` | `string`[] |\n\n#### Returns\n\n`string`\n\n---\n\n### moveFilesToNewDirectory\n\n▸ **moveFilesToNewDirectory**(`tree`, `oldDir`, `newDir`): `void`\n\nAnalogous to cp -r oldDir newDir\n\n#### Parameters\n\n| Name | Type |\n| :------- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `oldDir` | `string` |\n| `newDir` | `string` |\n\n#### Returns\n\n`void`\n\n---\n\n### names\n\n▸ **names**(`name`): `Object`\n\nUtil function to generate different strings based off the provided name.\n\nExamples:\n\n```typescript\nnames('my-name'); // {name: 'my-name', className: 'MyName', propertyName: 'myName', constantName: 'MY_NAME', fileName: 'my-name'}\nnames('myName'); // {name: 'myName', className: 'MyName', propertyName: 'myName', constantName: 'MY_NAME', fileName: 'my-name'}\n```\n\n#### Parameters\n\n| Name | Type |\n| :----- | :------- |\n| `name` | `string` |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :------------- | :------- |\n| `className` | `string` |\n| `constantName` | `string` |\n| `fileName` | `string` |\n| `name` | `string` |\n| `propertyName` | `string` |\n\n---\n\n### normalizePath\n\n▸ **normalizePath**(`osSpecificPath`): `string`\n\nCoverts an os specific path to a unix style path\n\n#### Parameters\n\n| Name | Type |\n| :--------------- | :------- |\n| `osSpecificPath` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### offsetFromRoot\n\n▸ **offsetFromRoot**(`fullPathToDir`): `string`\n\nCalculates an offset from the root of the workspace, which is useful for\nconstructing relative URLs.\n\nExamples:\n\n```typescript\noffsetFromRoot('apps/mydir/myapp/'); // returns \"../../../\"\n```\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------------- | :------- | :------------- |\n| `fullPathToDir` | `string` | directory path |\n\n#### Returns\n\n`string`\n\n---\n\n### parseJson\n\n▸ **parseJson**<`T`\\>(`input`, `options?`): `T`\n\nParses the given JSON string and returns the object the JSON content represents.\nBy default javascript-style comments are allowed.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :-------------------------------------------------------- | :--------------------- |\n| `input` | `string` | JSON content as string |\n| `options?` | [`JsonParseOptions`](../../devkit/index#jsonparseoptions) | JSON parse options |\n\n#### Returns\n\n`T`\n\nObject the JSON content represents\n\n---\n\n### parseTargetString\n\n▸ **parseTargetString**(`targetString`): [`Target`](../../devkit/index#target)\n\nParses a target string into {project, target, configuration}\n\nExamples:\n\n```typescript\nparseTargetString('proj:test'); // returns { project: \"proj\", target: \"test\" }\nparseTargetString('proj:test:production'); // returns { project: \"proj\", target: \"test\", configuration: \"production\" }\n```\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------- | :------- | :--------------- |\n| `targetString` | `string` | target reference |\n\n#### Returns\n\n[`Target`](../../devkit/index#target)\n\n---\n\n### readAllWorkspaceConfiguration\n\n▸ **readAllWorkspaceConfiguration**(): [`ProjectsConfigurations`](../../devkit/index#projectsconfigurations) & [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n**`deprecated`** Use readProjectsConfigurationFromProjectGraph(await createProjectGraphAsync())\n\n#### Returns\n\n[`ProjectsConfigurations`](../../devkit/index#projectsconfigurations) & [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n---\n\n### readCachedProjectGraph\n\n▸ **readCachedProjectGraph**(): [`ProjectGraph`](../../devkit/index#projectgraph)<[`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\nSynchronously reads the latest cached copy of the workspace's ProjectGraph.\n\n**`throws`** {Error} if there is no cached ProjectGraph to read from\n\n#### Returns\n\n[`ProjectGraph`](../../devkit/index#projectgraph)<[`ProjectConfiguration`](../../devkit/index#projectconfiguration)\\>\n\n---\n\n### readJson\n\n▸ **readJson**<`T`\\>(`tree`, `path`, `options?`): `T`\n\nReads a json file, removes all comments and parses JSON.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :-------------------------------------------------------- | :-------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | file system tree |\n| `path` | `string` | file path |\n| `options?` | [`JsonParseOptions`](../../devkit/index#jsonparseoptions) | Optional JSON Parse Options |\n\n#### Returns\n\n`T`\n\n---\n\n### readJsonFile\n\n▸ **readJsonFile**<`T`\\>(`path`, `options?`): `T`\n\nReads a JSON file and returns the object the JSON content represents.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------- | :----------------- |\n| `path` | `string` | A path to a file. |\n| `options?` | `JsonReadOptions` | JSON parse options |\n\n#### Returns\n\n`T`\n\nObject the JSON content of the file represents\n\n---\n\n### readNxJson\n\n▸ **readNxJson**(): [`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n#### Returns\n\n[`NxJsonConfiguration`](../../devkit/index#nxjsonconfiguration)\n\n---\n\n### readProjectConfiguration\n\n▸ **readProjectConfiguration**(`tree`, `projectName`): [`ProjectConfiguration`](../../devkit/index#projectconfiguration)\n\nReads a project configuration.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will read from either file.\n\n**`throws`** If supplied projectName cannot be found\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------ | :-------------------------------- | :---------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `projectName` | `string` | unique name. Often directories are part of the name (e.g., mydir-mylib) |\n\n#### Returns\n\n[`ProjectConfiguration`](../../devkit/index#projectconfiguration)\n\n---\n\n### readTargetOptions\n\n▸ **readTargetOptions**<`T`\\>(`__namedParameters`, `context`): `T`\n\nReads and combines options for a given target.\n\nWorks as if you invoked the target yourself without passing any command lint overrides.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :---- |\n| `T` | `any` |\n\n#### Parameters\n\n| Name | Type |\n| :------------------ | :------------------------------------------------------ |\n| `__namedParameters` | [`Target`](../../devkit/index#target) |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n#### Returns\n\n`T`\n\n---\n\n### readWorkspaceConfiguration\n\n▸ **readWorkspaceConfiguration**(`tree`): [`WorkspaceConfiguration`](../../devkit/index#workspaceconfiguration)\n\nRead general workspace configuration such as the default project or cli settings\n\nThis does _not_ provide projects configuration, use [readProjectConfiguration](../../devkit/index#readprojectconfiguration) instead.\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n[`WorkspaceConfiguration`](../../devkit/index#workspaceconfiguration)\n\n---\n\n### removeDependenciesFromPackageJson\n\n▸ **removeDependenciesFromPackageJson**(`tree`, `dependencies`, `devDependencies`, `packageJsonPath?`): [`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nRemove Dependencies and Dev Dependencies from package.json\n\nFor example:\n\n```typescript\nremoveDependenciesFromPackageJson(tree, ['react'], ['jest']);\n```\n\nThis will **remove** `react` and `jest` from the dependencies and devDependencies sections of package.json respectively.\n\n#### Parameters\n\n| Name | Type | Default value | Description |\n| :---------------- | :-------------------------------- | :--------------- | :-------------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` | - |\n| `dependencies` | `string`[] | `undefined` | Dependencies to be removed from the dependencies section of package.json |\n| `devDependencies` | `string`[] | `undefined` | Dependencies to be removed from the devDependencies section of package.json |\n| `packageJsonPath` | `string` | `'package.json'` | - |\n\n#### Returns\n\n[`GeneratorCallback`](../../devkit/index#generatorcallback)\n\nCallback to uninstall dependencies only if necessary. undefined is returned if changes are not necessary.\n\n---\n\n### removeProjectConfiguration\n\n▸ **removeProjectConfiguration**(`tree`, `projectName`): `void`\n\nRemoves the configuration of an existing project.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will update either file.\n\n#### Parameters\n\n| Name | Type |\n| :------------ | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `projectName` | `string` |\n\n#### Returns\n\n`void`\n\n---\n\n### reverse\n\n▸ **reverse**(`graph`): [`ProjectGraph`](../../devkit/index#projectgraph)\n\nReturns a new project graph where all the edges are reversed.\n\nFor instance, if project A depends on B, in the reversed graph\nB will depend on A.\n\n#### Parameters\n\n| Name | Type |\n| :------ | :-------------------------------------------------------- |\n| `graph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> |\n\n#### Returns\n\n[`ProjectGraph`](../../devkit/index#projectgraph)\n\n---\n\n### runExecutor\n\n▸ **runExecutor**<`T`\\>(`targetDescription`, `overrides`, `context`): `Promise`<`AsyncIterableIterator`<`T`\\>\\>\n\nLoads and invokes executor.\n\nThis is analogous to invoking executor from the terminal, with the exception\nthat the params aren't parsed from the string, but instead provided parsed already.\n\nApart from that, it works the same way:\n\n- it will load the workspace configuration\n- it will resolve the target\n- it will load the executor and the schema\n- it will load the options for the appropriate configuration\n- it will run the validations and will set the default\n- and, of course, it will invoke the executor\n\nExample:\n\n```typescript\nfor await (const s of await runExecutor(\n { project: 'myproj', target: 'serve' },\n { watch: true },\n context\n)) {\n // s.success\n}\n```\n\nNote that the return value is a promise of an iterator, so you need to await before iterating over it.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :--------------- |\n| `T` | extends `Object` |\n\n#### Parameters\n\n| Name | Type |\n| :--------------------------------- | :------------------------------------------------------ |\n| `targetDescription` | `Object` |\n| `targetDescription.configuration?` | `string` |\n| `targetDescription.project` | `string` |\n| `targetDescription.target` | `string` |\n| `overrides` | `Object` |\n| `context` | [`ExecutorContext`](../../devkit/index#executorcontext) |\n\n#### Returns\n\n`Promise`<`AsyncIterableIterator`<`T`\\>\\>\n\n---\n\n### serializeJson\n\n▸ **serializeJson**<`T`\\>(`input`, `options?`): `string`\n\nSerializes the given data to a JSON string.\nBy default the JSON string is formatted with a 2 space intendation to be easy readable.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------------------------- |\n| `T` | extends `object` = `object` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------------------------------------------------------- | :---------------------------------------- |\n| `input` | `T` | Object which should be serialized to JSON |\n| `options?` | [`JsonSerializeOptions`](../../devkit/index#jsonserializeoptions) | JSON serialize options |\n\n#### Returns\n\n`string`\n\nthe formatted JSON representation of the object\n\n---\n\n### stripIndents\n\n▸ **stripIndents**(`strings`, ...`values`): `string`\n\nRemoves indents, which is useful for printing warning and messages.\n\nExample:\n\n```typescript\nstripIndents`\n Options:\n - option1\n - option2\n`;\n```\n\n#### Parameters\n\n| Name | Type |\n| :---------- | :--------------------- |\n| `strings` | `TemplateStringsArray` |\n| `...values` | `any`[] |\n\n#### Returns\n\n`string`\n\n---\n\n### stripJsonComments\n\n▸ `Const` **stripJsonComments**(`text`, `replaceCh?`): `string`\n\nTakes JSON with JavaScript-style comments and remove\nthem. Optionally replaces every none-newline character\nof comments with a replaceCharacter\n\n#### Parameters\n\n| Name | Type |\n| :----------- | :------- |\n| `text` | `string` |\n| `replaceCh?` | `string` |\n\n#### Returns\n\n`string`\n\n---\n\n### targetToTargetString\n\n▸ **targetToTargetString**(`target`): `string`\n\nReturns a string in the format \"project:target[:configuration]\" for the target\n\n#### Parameters\n\n| Name | Type | Description |\n| :------- | :------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `target` | [`Target`](../../devkit/index#target) | target object Examples: `typescript targetToTargetString({ project: \"proj\", target: \"test\" }) // returns \"proj:test\" targetToTargetString({ project: \"proj\", target: \"test\", configuration: \"production\" }) // returns \"proj:test:production\" ` |\n\n#### Returns\n\n`string`\n\n---\n\n### toJS\n\n▸ **toJS**(`tree`): `void`\n\nRename and transpile any new typescript files created to javascript files\n\n#### Parameters\n\n| Name | Type |\n| :----- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n\n#### Returns\n\n`void`\n\n---\n\n### updateJson\n\n▸ **updateJson**<`T`, `U`\\>(`tree`, `path`, `updater`, `options?`): `void`\n\nUpdates a JSON value to the file system tree\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :----------------------- |\n| `T` | extends `object` = `any` |\n| `U` | extends `object` = `T` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | File system tree |\n| `path` | `string` | Path of JSON file in the Tree |\n| `updater` | (`value`: `T`) => `U` | Function that maps the current value of a JSON document to a new value to be written to the document |\n| `options?` | [`JsonParseOptions`](../../devkit/index#jsonparseoptions) & [`JsonSerializeOptions`](../../devkit/index#jsonserializeoptions) | Optional JSON Parse and Serialize Options |\n\n#### Returns\n\n`void`\n\n---\n\n### updateProjectConfiguration\n\n▸ **updateProjectConfiguration**(`tree`, `projectName`, `projectConfiguration`): `void`\n\nUpdates the configuration of an existing project.\n\nThe project configuration is stored in workspace.json or the associated project.json file.\nThe utility will update either files.\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------------------- | :---------------------------------------------------------------- | :---------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `projectName` | `string` | unique name. Often directories are part of the name (e.g., mydir-mylib) |\n| `projectConfiguration` | [`ProjectConfiguration`](../../devkit/index#projectconfiguration) | project configuration |\n\n#### Returns\n\n`void`\n\n---\n\n### updateTsConfigsToJs\n\n▸ **updateTsConfigsToJs**(`tree`, `options`): `void`\n\n#### Parameters\n\n| Name | Type |\n| :-------------------- | :-------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `options` | `Object` |\n| `options.projectRoot` | `string` |\n\n#### Returns\n\n`void`\n\n---\n\n### updateWorkspaceConfiguration\n\n▸ **updateWorkspaceConfiguration**(`tree`, `workspaceConfig`): `void`\n\nUpdate general workspace configuration such as the default project or cli settings.\n\nThis does _not_ update projects configuration, use [updateProjectConfiguration](../../devkit/index#updateprojectconfiguration) or [addProjectConfiguration](../../devkit/index#addprojectconfiguration) instead.\n\n#### Parameters\n\n| Name | Type |\n| :---------------- | :-------------------------------------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) |\n| `workspaceConfig` | [`WorkspaceConfiguration`](../../devkit/index#workspaceconfiguration) |\n\n#### Returns\n\n`void`\n\n---\n\n### visitNotIgnoredFiles\n\n▸ **visitNotIgnoredFiles**(`tree`, `dirPath?`, `visitor`): `void`\n\nUtility to act on all files in a tree that are not ignored by git.\n\n#### Parameters\n\n| Name | Type | Default value |\n| :-------- | :-------------------------------- | :------------ |\n| `tree` | [`Tree`](../../devkit/index#tree) | `undefined` |\n| `dirPath` | `string` | `tree.root` |\n| `visitor` | (`path`: `string`) => `void` | `undefined` |\n\n#### Returns\n\n`void`\n\n---\n\n### workspaceLayout\n\n▸ **workspaceLayout**(): `Object`\n\nReturns information about where apps and libs will be created.\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :-------- | :------- |\n| `appsDir` | `string` |\n| `libsDir` | `string` |\n\n---\n\n### writeJson\n\n▸ **writeJson**<`T`\\>(`tree`, `path`, `value`, `options?`): `void`\n\nWrites a JSON value to the file system tree\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------------------------- |\n| `T` | extends `object` = `object` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :---------------------------------------------------------------- | :------------------------------ |\n| `tree` | [`Tree`](../../devkit/index#tree) | File system tree |\n| `path` | `string` | Path of JSON file in the Tree |\n| `value` | `T` | Serializable value to write |\n| `options?` | [`JsonSerializeOptions`](../../devkit/index#jsonserializeoptions) | Optional JSON Serialize Options |\n\n#### Returns\n\n`void`\n\n---\n\n### writeJsonFile\n\n▸ **writeJsonFile**<`T`\\>(`path`, `data`, `options?`): `void`\n\nSerializes the given data to JSON and writes it to a file.\n\n#### Type parameters\n\n| Name | Type |\n| :--- | :-------------------------- |\n| `T` | extends `object` = `object` |\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :----------------- | :-------------------------------------------------------------- |\n| `path` | `string` | A path to a file. |\n| `data` | `T` | data which should be serialized to JSON and written to the file |\n| `options?` | `JsonWriteOptions` | JSON serialize options |\n\n#### Returns\n\n`void`\n" }, { "id": "ngcli_adapter", diff --git a/package.json b/package.json index 9c8783d2e5..e0259fad31 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@nrwl/eslint-plugin-nx": "14.6.0-beta.3", "@nrwl/jest": "14.6.0-beta.3", "@nrwl/next": "14.6.0-beta.3", - "@nrwl/nx-cloud": "14.4.1", + "@nrwl/nx-cloud": "14.4.2-beta.2", "@nrwl/react": "14.6.0-beta.3", "@nrwl/web": "14.6.0-beta.3", "@parcel/watcher": "2.0.4", diff --git a/packages/nx/src/daemon/client/client.ts b/packages/nx/src/daemon/client/client.ts index 9dba85aa82..88958ac16c 100644 --- a/packages/nx/src/daemon/client/client.ts +++ b/packages/nx/src/daemon/client/client.ts @@ -1,6 +1,6 @@ import { workspaceRoot } from '../../utils/workspace-root'; import { ChildProcess, spawn, spawnSync } from 'child_process'; -import { openSync, readFileSync } from 'fs'; +import { openSync, readFileSync, statSync } from 'fs'; import { ensureDirSync, ensureFileSync } from 'fs-extra'; import { connect } from 'net'; import { join } from 'path'; @@ -14,8 +14,12 @@ import { FULL_OS_SOCKET_PATH, killSocketOrPath } from '../socket-utils'; import { DAEMON_DIR_FOR_CURRENT_WORKSPACE, DAEMON_OUTPUT_LOG_FILE, + isDaemonDisabled, } from '../tmp-dir'; import { ProjectGraph } from '../../config/project-graph'; +import { isCI } from '../../utils/is-ci'; +import { readNxJson } from '../../config/configuration'; +import { NxJsonConfiguration } from 'nx/src/config/nx-json'; const DAEMON_ENV_SETTINGS = { ...process.env, @@ -23,6 +27,64 @@ const DAEMON_ENV_SETTINGS = { NX_CACHE_WORKSPACE_CONFIG: 'false', }; +export class DaemonClient { + constructor(private readonly nxJson: NxJsonConfiguration) {} + + enabled() { + const useDaemonProcessOption = + this.nxJson.tasksRunnerOptions?.['default']?.options?.useDaemonProcess; + const env = process.env.NX_DAEMON; + + // env takes precedence + // option=true,env=false => no daemon + // option=false,env=undefined => no daemon + // option=false,env=false => no daemon + + // option=undefined,env=undefined => daemon + // option=true,env=true => daemon + // option=false,env=true => daemon + if ( + isCI() || + isDocker() || + isDaemonDisabled() || + (useDaemonProcessOption === undefined && env === 'false') || + (useDaemonProcessOption === true && env === 'false') || + (useDaemonProcessOption === false && env === undefined) || + (useDaemonProcessOption === false && env === 'false') + ) { + return false; + } + return true; + } + + async getProjectGraph(): Promise { + if (!(await isServerAvailable())) { + await startInBackground(); + } + return sendMessageToDaemon({ type: 'REQUEST_PROJECT_GRAPH' }); + } + + async processInBackground(requirePath: string, data: any): Promise { + if (!(await isServerAvailable())) { + await startInBackground(); + } + return sendMessageToDaemon({ + type: 'PROCESS_IN_BACKGROUND', + requirePath, + data, + }); + } +} + +function isDocker() { + try { + statSync('/.dockerenv'); + return true; + } catch { + return false; + } +} + export async function startInBackground(): Promise { await safelyCleanUpExistingProcess(); ensureDirSync(DAEMON_DIR_FOR_CURRENT_WORKSPACE); @@ -136,19 +198,13 @@ export async function isServerAvailable(): Promise { }); } -/** - * Establishes a client connection to the daemon server for use in project graph - * creation utilities. - * - * All logs are performed by the devkit logger because this logic does not - * run "on the server" per se and therefore does not write to its log output. - * - * TODO: Gracefully handle a server shutdown (for whatever reason) while a client - * is connecting and querying it. - */ -export async function getProjectGraphFromServer(): Promise { +async function sendMessageToDaemon(message: { + type: string; + requirePath?: string; + data?: any; +}): Promise { return new Promise((resolve, reject) => { - performance.mark('getProjectGraphFromServer-start'); + performance.mark('sendMessageToDaemon-start'); const socket = connect(FULL_OS_SOCKET_PATH); socket.on('error', (err) => { @@ -156,7 +212,7 @@ export async function getProjectGraphFromServer(): Promise { return reject(err); } if (err.message.startsWith('LOCK-FILES-CHANGED')) { - return getProjectGraphFromServer().then(resolve, reject); + return sendMessageToDaemon(message).then(resolve, reject); } let error: any; if (err.message.startsWith('connect ENOENT')) { @@ -174,54 +230,47 @@ export async function getProjectGraphFromServer(): Promise { return reject(error || err); }); - /** - * Immediately after connecting to the server we send it the known project graph creation - * request payload. See the notes above createServer() for more context as to why we explicitly - * request the graph from the client like this. - */ socket.on('connect', () => { - socket.write('REQUEST_PROJECT_GRAPH_PAYLOAD'); + socket.write(JSON.stringify(message)); - let serializedProjectGraphResult = ''; + let serializedResult = ''; socket.on('data', (data) => { - serializedProjectGraphResult += data.toString(); + serializedResult += data.toString(); }); socket.on('end', () => { try { performance.mark('json-parse-start'); - const projectGraphResult = JSON.parse(serializedProjectGraphResult); + const parsedResult = JSON.parse(serializedResult); performance.mark('json-parse-end'); performance.measure( - 'deserialize graph result on the client', + 'deserialize daemon response', 'json-parse-start', 'json-parse-end' ); - if (projectGraphResult.error) { - reject(projectGraphResult.error); + if (parsedResult.error) { + reject(parsedResult.error); } else { performance.measure( - 'total for getProjectGraphFromServer()', - 'getProjectGraphFromServer-start', + 'total for sendMessageToDaemon()', + 'sendMessageToDaemon-start', 'json-parse-end' ); - return resolve(projectGraphResult.projectGraph); + return resolve(parsedResult.projectGraph); } } catch (e) { - const endOfGraph = - serializedProjectGraphResult.length > 300 - ? serializedProjectGraphResult.substring( - serializedProjectGraphResult.length - 300 - ) - : serializedProjectGraphResult; + const endOfResponse = + serializedResult.length > 300 + ? serializedResult.substring(serializedResult.length - 300) + : serializedResult; reject( daemonProcessException( [ - 'Could not deserialize project graph.', + 'Could not deserialize response from Nx deamon.', `Message: ${e.message}`, '\n', `Received:`, - endOfGraph, + endOfResponse, '\n', ].join('\n') ) diff --git a/packages/nx/src/daemon/server/handle-process-in-background.ts b/packages/nx/src/daemon/server/handle-process-in-background.ts new file mode 100644 index 0000000000..7412a197d5 --- /dev/null +++ b/packages/nx/src/daemon/server/handle-process-in-background.ts @@ -0,0 +1,27 @@ +import { respondWithErrorAndExit } from './shutdown-utils'; + +export async function handleProcessInBackground( + socket, + payload: { type: string; requirePath: string; data: any } +) { + let fn; + try { + fn = require(payload.requirePath); + } catch (e) { + await respondWithErrorAndExit( + socket, + `Unable to require ${payload.requirePath}`, + new Error(`Unable to require ${payload.requirePath}`) + ); + } + + try { + await fn(socket, payload.data); + } catch (e) { + await respondWithErrorAndExit( + socket, + `Error when processing ${payload.type}.`, + new Error(`Error when processing ${payload.type}. Message: ${e.message}`) + ); + } +} diff --git a/packages/nx/src/daemon/server/handle-request-project-graph.ts b/packages/nx/src/daemon/server/handle-request-project-graph.ts new file mode 100644 index 0000000000..91d42fb7ae --- /dev/null +++ b/packages/nx/src/daemon/server/handle-request-project-graph.ts @@ -0,0 +1,63 @@ +import { performance } from 'perf_hooks'; +import { serializeResult } from '../socket-utils'; +import { serverLogger } from './logger'; +import { getCachedSerializedProjectGraphPromise } from './project-graph-incremental-recomputation'; +import { respondWithErrorAndExit } from './shutdown-utils'; + +export async function handleRequestProjectGraph(socket) { + performance.mark('server-connection'); + serverLogger.requestLog('Client Request for Project Graph Received'); + + const result = await getCachedSerializedProjectGraphPromise(); + if (result.error) { + await respondWithErrorAndExit( + socket, + `Error when preparing serialized project graph.`, + result.error + ); + } + + const serializedResult = serializeResult( + result.error, + result.serializedProjectGraph + ); + if (!serializedResult) { + await respondWithErrorAndExit( + socket, + `Error when serializing project graph result.`, + new Error( + 'Critical error when serializing server result, check server logs' + ) + ); + } + + performance.mark('serialized-project-graph-ready'); + performance.measure( + 'total for creating and serializing project graph', + 'server-connection', + 'serialized-project-graph-ready' + ); + + socket.write(serializedResult, () => { + performance.mark('serialized-project-graph-written-to-client'); + performance.measure( + 'write project graph to socket', + 'serialized-project-graph-ready', + 'serialized-project-graph-written-to-client' + ); + // Close the connection once all data has been written so that the client knows when to read it. + socket.end(); + performance.measure( + 'total for server response', + 'server-connection', + 'serialized-project-graph-written-to-client' + ); + const bytesWritten = Buffer.byteLength( + result.serializedProjectGraph, + 'utf-8' + ); + serverLogger.requestLog( + `Closed Connection to Client (${bytesWritten} bytes transferred)` + ); + }); +} diff --git a/packages/nx/src/daemon/server/server.ts b/packages/nx/src/daemon/server/server.ts index 3300e95881..0444962ea5 100644 --- a/packages/nx/src/daemon/server/server.ts +++ b/packages/nx/src/daemon/server/server.ts @@ -1,7 +1,7 @@ import { workspaceRoot } from '../../utils/workspace-root'; import { createServer, Server, Socket } from 'net'; import { join } from 'path'; -import { performance, PerformanceObserver } from 'perf_hooks'; +import { PerformanceObserver } from 'perf_hooks'; import { FULL_OS_SOCKET_PATH, isWindows, @@ -12,6 +12,7 @@ import { serverLogger } from './logger'; import { handleServerProcessTermination, resetInactivityTimeout, + respondWithErrorAndExit, SERVER_INACTIVITY_TIMEOUT_MS, } from './shutdown-utils'; import { @@ -20,48 +21,17 @@ import { SubscribeToWorkspaceChangesCallback, WatcherSubscription, } from './watcher'; -import { - addUpdatedAndDeletedFiles, - getCachedSerializedProjectGraphPromise, -} from './project-graph-incremental-recomputation'; +import { addUpdatedAndDeletedFiles } from './project-graph-incremental-recomputation'; import { existsSync, statSync } from 'fs'; import { HashingImpl } from '../../hasher/hashing-impl'; import { defaultFileHasher } from '../../hasher/file-hasher'; - -function respondToClient(socket: Socket, message: string) { - return new Promise((res) => { - socket.write(message, () => { - // Close the connection once all data has been written so that the client knows when to read it. - socket.end(); - serverLogger.log(`Closed Connection to Client`); - res(null); - }); - }); -} +import { handleRequestProjectGraph } from './handle-request-project-graph'; +import { handleProcessInBackground } from './handle-process-in-background'; let watcherSubscription: WatcherSubscription | undefined; let performanceObserver: PerformanceObserver | undefined; let watcherError: Error | undefined; -async function respondWithErrorAndExit( - socket: Socket, - description: string, - error: Error -) { - // print some extra stuff in the error message - serverLogger.requestLog( - `Responding to the client with an error.`, - description, - error.message - ); - console.error(error); - - error.message = `${error.message}\n\nBecause of the error the Nx daemon process has exited. The next Nx command is going to restart the daemon process.\nIf the error persists, please run "nx reset".`; - - await respondToClient(socket, serializeResult(error, null)); - process.exit(1); -} - const server = createServer(async (socket) => { resetInactivityTimeout(handleInactivityTimeout); if (!performanceObserver) { @@ -90,70 +60,33 @@ const server = createServer(async (socket) => { resetInactivityTimeout(handleInactivityTimeout); - const payload = data.toString(); - if (payload !== 'REQUEST_PROJECT_GRAPH_PAYLOAD') { + const unparsedPayload = data.toString(); + let payload; + try { + payload = JSON.parse(unparsedPayload); + } catch (e) { await respondWithErrorAndExit( socket, `Invalid payload from the client`, - new Error(`Unsupported payload sent to daemon server: ${payload}`) - ); - } - - performance.mark('server-connection'); - serverLogger.requestLog('Client Request for Project Graph Received'); - - const result = await getCachedSerializedProjectGraphPromise(); - if (result.error) { - await respondWithErrorAndExit( - socket, - `Error when preparing serialized project graph.`, - result.error - ); - } - - const serializedResult = serializeResult( - result.error, - result.serializedProjectGraph - ); - if (!serializedResult) { - await respondWithErrorAndExit( - socket, - `Error when serializing project graph result.`, new Error( - 'Critical error when serializing server result, check server logs' + `Unsupported payload sent to daemon server: ${unparsedPayload}` ) ); } - performance.mark('serialized-project-graph-ready'); - performance.measure( - 'total for creating and serializing project graph', - 'server-connection', - 'serialized-project-graph-ready' - ); - - socket.write(serializedResult, () => { - performance.mark('serialized-project-graph-written-to-client'); - performance.measure( - 'write project graph to socket', - 'serialized-project-graph-ready', - 'serialized-project-graph-written-to-client' + if (payload.type === 'REQUEST_PROJECT_GRAPH') { + await handleRequestProjectGraph(socket); + } else if (payload.type === 'PROCESS_IN_BACKGROUND') { + await handleProcessInBackground(socket, payload); + } else { + await respondWithErrorAndExit( + socket, + `Invalid payload from the client`, + new Error( + `Unsupported payload sent to daemon server: ${unparsedPayload}` + ) ); - // Close the connection once all data has been written so that the client knows when to read it. - socket.end(); - performance.measure( - 'total for server response', - 'server-connection', - 'serialized-project-graph-written-to-client' - ); - const bytesWritten = Buffer.byteLength( - result.serializedProjectGraph, - 'utf-8' - ); - serverLogger.requestLog( - `Closed Connection to Client (${bytesWritten} bytes transferred)` - ); - }); + } }); }); diff --git a/packages/nx/src/daemon/server/shutdown-utils.ts b/packages/nx/src/daemon/server/shutdown-utils.ts index 6a6799b7ab..2a5767f645 100644 --- a/packages/nx/src/daemon/server/shutdown-utils.ts +++ b/packages/nx/src/daemon/server/shutdown-utils.ts @@ -1,7 +1,8 @@ import { workspaceRoot } from '../../utils/workspace-root'; -import type { Server } from 'net'; +import type { Server, Socket } from 'net'; import { serverLogger } from './logger'; import type { WatcherSubscription } from './watcher'; +import { serializeResult } from 'nx/src/daemon/socket-utils'; export const SERVER_INACTIVITY_TIMEOUT_MS = 10800000 as const; // 10800000 ms = 3 hours @@ -38,3 +39,33 @@ export function resetInactivityTimeout(cb: () => void): void { } serverInactivityTimerId = setTimeout(cb, SERVER_INACTIVITY_TIMEOUT_MS); } + +function respondToClient(socket: Socket, message: string) { + return new Promise((res) => { + socket.write(message, () => { + // Close the connection once all data has been written so that the client knows when to read it. + socket.end(); + serverLogger.log(`Closed Connection to Client`); + res(null); + }); + }); +} + +export async function respondWithErrorAndExit( + socket: Socket, + description: string, + error: Error +) { + // print some extra stuff in the error message + serverLogger.requestLog( + `Responding to the client with an error.`, + description, + error.message + ); + console.error(error); + + error.message = `${error.message}\n\nBecause of the error the Nx daemon process has exited. The next Nx command is going to restart the daemon process.\nIf the error persists, please run "nx reset".`; + + await respondToClient(socket, serializeResult(error, null)); + process.exit(1); +} diff --git a/packages/nx/src/project-graph/project-graph.ts b/packages/nx/src/project-graph/project-graph.ts index 3847b42b56..d9ab7b66d3 100644 --- a/packages/nx/src/project-graph/project-graph.ts +++ b/packages/nx/src/project-graph/project-graph.ts @@ -2,14 +2,8 @@ import { ProjectGraphCache, readCache } from './nx-deps-cache'; import { buildProjectGraph } from './build-project-graph'; import { workspaceFileName } from './file-utils'; import { output } from '../utils/output'; -import { isCI } from '../utils/is-ci'; import { defaultFileHasher } from '../hasher/file-hasher'; -import { - isDaemonDisabled, - markDaemonAsDisabled, - writeDaemonLogs, -} from '../daemon/tmp-dir'; -import { statSync } from 'fs'; +import { markDaemonAsDisabled, writeDaemonLogs } from '../daemon/tmp-dir'; import { ProjectGraph, ProjectGraphV4 } from '../config/project-graph'; import { stripIndents } from '../utils/strip-indents'; import { readNxJson } from '../config/configuration'; @@ -17,6 +11,7 @@ import { ProjectConfiguration, ProjectsConfigurations, } from '../config/workspace-json-project-json'; +import { DaemonClient } from '../daemon/client/client'; /** * Synchronously reads the latest cached copy of the workspace's ProjectGraph. @@ -108,35 +103,12 @@ async function buildProjectGraphWithoutDaemon() { */ export async function createProjectGraphAsync(): Promise { const nxJson = readNxJson(); - const useDaemonProcessOption = - nxJson.tasksRunnerOptions?.['default']?.options?.useDaemonProcess; - const env = process.env.NX_DAEMON; - - // env takes precedence - // option=true,env=false => no daemon - // option=false,env=undefined => no daemon - // option=false,env=false => no daemon - - // option=undefined,env=undefined => daemon - // option=true,env=true => daemon - // option=false,env=true => daemon - if ( - isCI() || - isDocker() || - isDaemonDisabled() || - (useDaemonProcessOption === undefined && env === 'false') || - (useDaemonProcessOption === true && env === 'false') || - (useDaemonProcessOption === false && env === undefined) || - (useDaemonProcessOption === false && env === 'false') - ) { + const daemon = new DaemonClient(nxJson); + if (!daemon.enabled()) { return await buildProjectGraphWithoutDaemon(); } else { try { - const daemonClient = require('../daemon/client/client'); - if (!(await daemonClient.isServerAvailable())) { - await daemonClient.startInBackground(); - } - return daemonClient.getProjectGraphFromServer(); + return daemon.getProjectGraph(); } catch (e) { if (e.message.indexOf('inotify_add_watch') > -1) { // common errors with the daemon due to OS settings (cannot watch all the files available) @@ -164,23 +136,6 @@ export async function createProjectGraphAsync(): Promise { } } -function isDocker() { - try { - statSync('/.dockerenv'); - return true; - } catch { - return false; - } -} - -function printErrorMessage(e: any) { - const lines = e.message.split('\n'); - output.error({ - title: lines[0], - bodyLines: lines.slice(1), - }); -} - /** * Backwards compatibility adapter for project graph * @param {string} sourceVersion diff --git a/packages/nx/src/tasks-runner/run-command.ts b/packages/nx/src/tasks-runner/run-command.ts index 1362f8f9d8..411376a64c 100644 --- a/packages/nx/src/tasks-runner/run-command.ts +++ b/packages/nx/src/tasks-runner/run-command.ts @@ -27,6 +27,7 @@ import { handleErrors } from '../utils/params'; import { Workspaces } from 'nx/src/config/workspaces'; import { Hasher } from 'nx/src/hasher/hasher'; import { hashDependsOnOtherTasks, hashTask } from 'nx/src/hasher/hash-task'; +import { DaemonClient } from '../daemon/client/client'; async function getTerminalOutputLifeCycle( initiatingProject: string, @@ -192,6 +193,7 @@ export async function runCommand( nxArgs, taskGraph, hasher, + daemon: new DaemonClient(nxJson), } ); let anyFailures; diff --git a/packages/nx/src/tasks-runner/tasks-runner.ts b/packages/nx/src/tasks-runner/tasks-runner.ts index a1beae5d14..d9daabc369 100644 --- a/packages/nx/src/tasks-runner/tasks-runner.ts +++ b/packages/nx/src/tasks-runner/tasks-runner.ts @@ -3,6 +3,7 @@ import { ProjectGraph } from '../config/project-graph'; import { Task, TaskGraph } from '../config/task-graph'; import { NxArgs } from '../utils/command-line-utils'; import { Hasher } from '../hasher/hasher'; +import { DaemonClient } from '../daemon/client/client'; export type TaskStatus = | 'success' @@ -27,5 +28,6 @@ export type TasksRunner = ( nxArgs: NxArgs; taskGraph?: TaskGraph; hasher?: Hasher; + daemon?: DaemonClient; } ) => any | Promise<{ [id: string]: TaskStatus }>; diff --git a/yarn.lock b/yarn.lock index 593417e78e..4000b1b921 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3738,10 +3738,10 @@ url-loader "^4.1.1" webpack-merge "^5.8.0" -"@nrwl/nx-cloud@14.4.1": - version "14.4.1" - resolved "https://registry.yarnpkg.com/@nrwl/nx-cloud/-/nx-cloud-14.4.1.tgz#a4d8e9ce6e5bbb753916adadaf0e23ca24b54823" - integrity sha512-vlWpBmIGfYvB9XMAdDZWOihOTFPE2VV9CDeZzBbSMF32KxDqUkhfaLf3dg6puIeUPkPbj5k+V57xjAl7g9k+Xw== +"@nrwl/nx-cloud@14.4.2-beta.2": + version "14.4.2-beta.2" + resolved "https://registry.yarnpkg.com/@nrwl/nx-cloud/-/nx-cloud-14.4.2-beta.2.tgz#9e913c9fc182827492aa6960bda5066ff50c700a" + integrity sha512-sJcxDFGqAcehLaE5DeWokuAKZmSAOI+b1k2w+9QgXNYVQD7dbS+rP0qo+32W+PYMElDWfwizOszKiaCNF7dHDw== dependencies: axios "^0.21.1" chalk "4.1.0"