diff --git a/docs/generated/devkit/index.md b/docs/generated/devkit/index.md index 005a65014f04e..60423a79ed8b3 100644 --- a/docs/generated/devkit/index.md +++ b/docs/generated/devkit/index.md @@ -147,6 +147,7 @@ It only uses language primitives and immutable objects - [defaultTasksRunner](../../devkit/index#defaulttasksrunner) - [detectPackageManager](../../devkit/index#detectpackagemanager) - [detectWorkspaceScope](../../devkit/index#detectworkspacescope) +- [ensurePackage](../../devkit/index#ensurepackage) - [extractLayoutDirectory](../../devkit/index#extractlayoutdirectory) - [formatFiles](../../devkit/index#formatfiles) - [generateFiles](../../devkit/index#generatefiles) @@ -1164,6 +1165,39 @@ Detect workspace scope from the package.json name --- +### ensurePackage + +▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `Promise`<`void`\> + +Ensure that dependencies and devDependencies from package.json are installed at the required versions. + +For example: + +```typescript +ensureDependencies(tree, {}, { '@nrwl/jest': nxVersion }); +``` + +This will check that @nrwl/jest@ exists in devDependencies. +If it exists then function returns, otherwise it will install the package before continuing. +When running with --dryRun, the function will throw when dependencies are missing. + +#### Parameters + +| Name | Type | Description | +| :------------------------ | :-------------------------------- | :------------------------------------- | +| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree | +| `pkg` | `string` | the package to check (e.g. @nrwl/jest) | +| `requiredVersion` | `string` | the version to check | +| `options` | `Object` | | +| `options.dev?` | `boolean` | - | +| `options.throwOnMissing?` | `boolean` | - | + +#### Returns + +`Promise`<`void`\> + +--- + ### extractLayoutDirectory ▸ **extractLayoutDirectory**(`directory`): `Object` diff --git a/docs/generated/packages/devkit.json b/docs/generated/packages/devkit.json index 24295ddc0cd4a..b7c6919f8169e 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- [ModuleFederationConfig](../../devkit/index#modulefederationconfig)\n- [RemoteCache](../../devkit/index#remotecache)\n- [SharedLibraryConfig](../../devkit/index#sharedlibraryconfig)\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- [AdditionalSharedConfig](../../devkit/index#additionalsharedconfig)\n- [ModuleFederationLibrary](../../devkit/index#modulefederationlibrary)\n- [Remotes](../../devkit/index#remotes)\n- [SharedFunction](../../devkit/index#sharedfunction)\n- [SharedWorkspaceLibraryConfig](../../devkit/index#sharedworkspacelibraryconfig)\n- [StringChange](../../devkit/index#stringchange)\n- [WorkspaceLibrary](../../devkit/index#workspacelibrary)\n- [WorkspaceLibrarySecondaryEntryPoint](../../devkit/index#workspacelibrarysecondaryentrypoint)\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- [applyAdditionalShared](../../devkit/index#applyadditionalshared)\n- [applyChangesToString](../../devkit/index#applychangestostring)\n- [applySharedFunction](../../devkit/index#applysharedfunction)\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- [extractLayoutDirectory](../../devkit/index#extractlayoutdirectory)\n- [formatFiles](../../devkit/index#formatfiles)\n- [generateFiles](../../devkit/index#generatefiles)\n- [getDependentPackagesForProject](../../devkit/index#getdependentpackagesforproject)\n- [getImportPath](../../devkit/index#getimportpath)\n- [getNpmPackageSharedConfig](../../devkit/index#getnpmpackagesharedconfig)\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- [mapRemotes](../../devkit/index#mapremotes)\n- [mapRemotesForSSR](../../devkit/index#mapremotesforssr)\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- [readRootPackageJson](../../devkit/index#readrootpackagejson)\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- [sharePackages](../../devkit/index#sharepackages)\n- [shareWorkspaceLibraries](../../devkit/index#shareworkspacelibraries)\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### ModuleFederationConfig\n\n• **ModuleFederationConfig**: `Object`\n\n---\n\n### RemoteCache\n\n• **RemoteCache**: `Object`\n\n---\n\n### SharedLibraryConfig\n\n• **SharedLibraryConfig**: `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### AdditionalSharedConfig\n\nƬ **AdditionalSharedConfig**: (`string` \\| [libraryName: string, sharedConfig: SharedLibraryConfig] \\| { `libraryName`: `string` ; `sharedConfig`: [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) })[]\n\n---\n\n### ModuleFederationLibrary\n\nƬ **ModuleFederationLibrary**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :----- | :------- |\n| `name` | `string` |\n| `type` | `string` |\n\n---\n\n### Remotes\n\nƬ **Remotes**: `string`[] \\| [remoteName: string, remoteUrl: string][]\n\n---\n\n### SharedFunction\n\nƬ **SharedFunction**: (`libraryName`: `string`, `sharedConfig`: [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)) => `undefined` \\| `false` \\| [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\n\n#### Type declaration\n\n▸ (`libraryName`, `sharedConfig`): `undefined` \\| `false` \\| [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\n\n##### Parameters\n\n| Name | Type |\n| :------------- | :-------------------------------------------------------------- |\n| `libraryName` | `string` |\n| `sharedConfig` | [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) |\n\n##### Returns\n\n`undefined` \\| `false` \\| [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\n\n---\n\n### SharedWorkspaceLibraryConfig\n\nƬ **SharedWorkspaceLibraryConfig**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :--------------------- | :------------------------------------------------------------------------------------------------------------ |\n| `getAliases` | () => `Record`<`string`, `string`\\> |\n| `getLibraries` | (`eager?`: `boolean`) => `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\> |\n| `getReplacementPlugin` | () => `NormalModuleReplacementPlugin` |\n\n---\n\n### StringChange\n\nƬ **StringChange**: [`StringInsertion`](../../devkit/index#stringinsertion) \\| [`StringDeletion`](../../devkit/index#stringdeletion)\n\n---\n\n### WorkspaceLibrary\n\nƬ **WorkspaceLibrary**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :---------- | :---------------------- |\n| `importKey` | `string` \\| `undefined` |\n| `name` | `string` |\n| `root` | `string` |\n\n---\n\n### WorkspaceLibrarySecondaryEntryPoint\n\nƬ **WorkspaceLibrarySecondaryEntryPoint**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :----- | :------- |\n| `name` | `string` |\n| `path` | `string` |\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, no-op otherwise\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### applyAdditionalShared\n\n▸ **applyAdditionalShared**(`sharedConfig`, `additionalShared`, `projectGraph`): `void`\n\nAdd additional dependencies to the shared package that may not have been\ndiscovered by the project graph.\n\nThis can be useful for applications that use a Dependency Injection system\nthat expects certain Singleton values to be present in the shared injection\nhierarchy.\n\n#### Parameters\n\n| Name | Type | Description |\n| :----------------- | :----------------------------------------------------------------------------------- | :--------------------------------- |\n| `sharedConfig` | `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\> | The original Shared Config |\n| `additionalShared` | [`AdditionalSharedConfig`](../../devkit/index#additionalsharedconfig) | The additional dependencies to add |\n| `projectGraph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> | The Nx project graph |\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### applySharedFunction\n\n▸ **applySharedFunction**(`sharedConfig`, `sharedFn`): `void`\n\nApply a custom function provided by the user that will modify the Shared Config\nof the dependencies for the Module Federation build.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------- | :----------------------------------------------------------------------------------- | :---------------------------------------- |\n| `sharedConfig` | `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\> | The original Shared Config to be modified |\n| `sharedFn` | [`SharedFunction`](../../devkit/index#sharedfunction) | The custom function to run |\n\n#### Returns\n\n`void`\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**(`opts?`): `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#### Parameters\n\n| Name | Type |\n| :------------------------ | :-------- |\n| `opts` | `Object` |\n| `opts.exitOnError` | `boolean` |\n| `opts.resetDaemonClient?` | `boolean` |\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### extractLayoutDirectory\n\n▸ **extractLayoutDirectory**(`directory`): `Object`\n\nExperimental\n\n#### Parameters\n\n| Name | Type |\n| :---------- | :------- |\n| `directory` | `string` |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :----------------- | :------- |\n| `layoutDirectory` | `string` |\n| `projectDirectory` | `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### getDependentPackagesForProject\n\n▸ **getDependentPackagesForProject**(`projectGraph`, `name`): `Object`\n\n#### Parameters\n\n| Name | Type |\n| :------------- | :-------------------------------------------------------- |\n| `projectGraph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> |\n| `name` | `string` |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :------------------- | :---------------------------------------------------------- |\n| `npmPackages` | `string`[] |\n| `workspaceLibraries` | [`WorkspaceLibrary`](../../devkit/index#workspacelibrary)[] |\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### getNpmPackageSharedConfig\n\n▸ **getNpmPackageSharedConfig**(`pkgName`, `version`): [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) \\| `undefined`\n\nBuild the Module Federation Share Config for a specific package and the\nspecified version of that package.\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------- | :------- | :----------------------------------------------------------------------------- |\n| `pkgName` | `string` | Name of the package to share |\n| `version` | `string` | Version of the package to require by other apps in the Module Federation setup |\n\n#### Returns\n\n[`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) \\| `undefined`\n\n---\n\n### getOutputsForTargetAndConfiguration\n\n▸ **getOutputsForTargetAndConfiguration**(`task`, `node`): `string`[]\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), `\"overrides\"` \\| `\"target\"`\\> | target + overrides |\n| `node` | [`ProjectGraphProjectNode`](../../devkit/index#projectgraphprojectnode)<`any`\\> | ProjectGraphProjectNode object that the task runs against |\n\n#### Returns\n\n`string`[]\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### mapRemotes\n\n▸ **mapRemotes**(`remotes`, `remoteEntryExt`, `determineRemoteUrl`): `Record`<`string`, `string`\\>\n\nMap remote names to a format that can be understood and used by Module\nFederation.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------------- | :-------------------------------------- | :------------------------------------------------------- |\n| `remotes` | [`Remotes`](../../devkit/index#remotes) | The remotes to map |\n| `remoteEntryExt` | `\"js\"` \\| `\"mjs\"` | The file extension of the remoteEntry file |\n| `determineRemoteUrl` | (`remote`: `string`) => `string` | The function used to lookup the URL of the served remote |\n\n#### Returns\n\n`Record`<`string`, `string`\\>\n\n---\n\n### mapRemotesForSSR\n\n▸ **mapRemotesForSSR**(`remotes`, `remoteEntryExt`, `determineRemoteUrl`): `Record`<`string`, `string`\\>\n\nMap remote names to a format that can be understood and used by Module\nFederation.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------------- | :-------------------------------------- | :------------------------------------------------------- |\n| `remotes` | [`Remotes`](../../devkit/index#remotes) | The remotes to map |\n| `remoteEntryExt` | `\"js\"` \\| `\"mjs\"` | The file extension of the remoteEntry file |\n| `determineRemoteUrl` | (`remote`: `string`) => `string` | The function used to lookup the URL of the served remote |\n\n#### Returns\n\n`Record`<`string`, `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### readRootPackageJson\n\n▸ **readRootPackageJson**(): `Object`\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :----------------- | :------- |\n| `dependencies?` | `Object` |\n| `devDependencies?` | `Object` |\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### sharePackages\n\n▸ **sharePackages**(`packages`): `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\>\n\nCreate a dictionary of packages and their Module Federation Shared Config\nfrom an array of package names.\n\nLookup the versions of the packages from the root package.json file in the\nworkspace.\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :--------- | :-------------------------------- |\n| `packages` | `string`[] | Array of package names as strings |\n\n#### Returns\n\n`Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\>\n\n---\n\n### shareWorkspaceLibraries\n\n▸ **shareWorkspaceLibraries**(`libraries`, `tsConfigPath?`): [`SharedWorkspaceLibraryConfig`](../../devkit/index#sharedworkspacelibraryconfig)\n\nBuild an object of functions to be used with the ModuleFederationPlugin to\nshare Nx Workspace Libraries between Hosts and Remotes.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------- | :---------------------------------------------------------- | :--------------------------------------------------------------------------- |\n| `libraries` | [`WorkspaceLibrary`](../../devkit/index#workspacelibrary)[] | The Nx Workspace Libraries to share |\n| `tsConfigPath` | `string` | The path to TS Config File that contains the Path Mappings for the Libraries |\n\n#### Returns\n\n[`SharedWorkspaceLibraryConfig`](../../devkit/index#sharedworkspacelibraryconfig)\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- [ModuleFederationConfig](../../devkit/index#modulefederationconfig)\n- [RemoteCache](../../devkit/index#remotecache)\n- [SharedLibraryConfig](../../devkit/index#sharedlibraryconfig)\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- [AdditionalSharedConfig](../../devkit/index#additionalsharedconfig)\n- [ModuleFederationLibrary](../../devkit/index#modulefederationlibrary)\n- [Remotes](../../devkit/index#remotes)\n- [SharedFunction](../../devkit/index#sharedfunction)\n- [SharedWorkspaceLibraryConfig](../../devkit/index#sharedworkspacelibraryconfig)\n- [StringChange](../../devkit/index#stringchange)\n- [WorkspaceLibrary](../../devkit/index#workspacelibrary)\n- [WorkspaceLibrarySecondaryEntryPoint](../../devkit/index#workspacelibrarysecondaryentrypoint)\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- [applyAdditionalShared](../../devkit/index#applyadditionalshared)\n- [applyChangesToString](../../devkit/index#applychangestostring)\n- [applySharedFunction](../../devkit/index#applysharedfunction)\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- [ensurePackage](../../devkit/index#ensurepackage)\n- [extractLayoutDirectory](../../devkit/index#extractlayoutdirectory)\n- [formatFiles](../../devkit/index#formatfiles)\n- [generateFiles](../../devkit/index#generatefiles)\n- [getDependentPackagesForProject](../../devkit/index#getdependentpackagesforproject)\n- [getImportPath](../../devkit/index#getimportpath)\n- [getNpmPackageSharedConfig](../../devkit/index#getnpmpackagesharedconfig)\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- [mapRemotes](../../devkit/index#mapremotes)\n- [mapRemotesForSSR](../../devkit/index#mapremotesforssr)\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- [readRootPackageJson](../../devkit/index#readrootpackagejson)\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- [sharePackages](../../devkit/index#sharepackages)\n- [shareWorkspaceLibraries](../../devkit/index#shareworkspacelibraries)\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### ModuleFederationConfig\n\n• **ModuleFederationConfig**: `Object`\n\n---\n\n### RemoteCache\n\n• **RemoteCache**: `Object`\n\n---\n\n### SharedLibraryConfig\n\n• **SharedLibraryConfig**: `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### AdditionalSharedConfig\n\nƬ **AdditionalSharedConfig**: (`string` \\| [libraryName: string, sharedConfig: SharedLibraryConfig] \\| { `libraryName`: `string` ; `sharedConfig`: [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) })[]\n\n---\n\n### ModuleFederationLibrary\n\nƬ **ModuleFederationLibrary**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :----- | :------- |\n| `name` | `string` |\n| `type` | `string` |\n\n---\n\n### Remotes\n\nƬ **Remotes**: `string`[] \\| [remoteName: string, remoteUrl: string][]\n\n---\n\n### SharedFunction\n\nƬ **SharedFunction**: (`libraryName`: `string`, `sharedConfig`: [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)) => `undefined` \\| `false` \\| [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\n\n#### Type declaration\n\n▸ (`libraryName`, `sharedConfig`): `undefined` \\| `false` \\| [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\n\n##### Parameters\n\n| Name | Type |\n| :------------- | :-------------------------------------------------------------- |\n| `libraryName` | `string` |\n| `sharedConfig` | [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) |\n\n##### Returns\n\n`undefined` \\| `false` \\| [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\n\n---\n\n### SharedWorkspaceLibraryConfig\n\nƬ **SharedWorkspaceLibraryConfig**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :--------------------- | :------------------------------------------------------------------------------------------------------------ |\n| `getAliases` | () => `Record`<`string`, `string`\\> |\n| `getLibraries` | (`eager?`: `boolean`) => `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\> |\n| `getReplacementPlugin` | () => `NormalModuleReplacementPlugin` |\n\n---\n\n### StringChange\n\nƬ **StringChange**: [`StringInsertion`](../../devkit/index#stringinsertion) \\| [`StringDeletion`](../../devkit/index#stringdeletion)\n\n---\n\n### WorkspaceLibrary\n\nƬ **WorkspaceLibrary**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :---------- | :---------------------- |\n| `importKey` | `string` \\| `undefined` |\n| `name` | `string` |\n| `root` | `string` |\n\n---\n\n### WorkspaceLibrarySecondaryEntryPoint\n\nƬ **WorkspaceLibrarySecondaryEntryPoint**: `Object`\n\n#### Type declaration\n\n| Name | Type |\n| :----- | :------- |\n| `name` | `string` |\n| `path` | `string` |\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, no-op otherwise\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### applyAdditionalShared\n\n▸ **applyAdditionalShared**(`sharedConfig`, `additionalShared`, `projectGraph`): `void`\n\nAdd additional dependencies to the shared package that may not have been\ndiscovered by the project graph.\n\nThis can be useful for applications that use a Dependency Injection system\nthat expects certain Singleton values to be present in the shared injection\nhierarchy.\n\n#### Parameters\n\n| Name | Type | Description |\n| :----------------- | :----------------------------------------------------------------------------------- | :--------------------------------- |\n| `sharedConfig` | `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\> | The original Shared Config |\n| `additionalShared` | [`AdditionalSharedConfig`](../../devkit/index#additionalsharedconfig) | The additional dependencies to add |\n| `projectGraph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> | The Nx project graph |\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### applySharedFunction\n\n▸ **applySharedFunction**(`sharedConfig`, `sharedFn`): `void`\n\nApply a custom function provided by the user that will modify the Shared Config\nof the dependencies for the Module Federation build.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------- | :----------------------------------------------------------------------------------- | :---------------------------------------- |\n| `sharedConfig` | `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\> | The original Shared Config to be modified |\n| `sharedFn` | [`SharedFunction`](../../devkit/index#sharedfunction) | The custom function to run |\n\n#### Returns\n\n`void`\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**(`opts?`): `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#### Parameters\n\n| Name | Type |\n| :------------------------ | :-------- |\n| `opts` | `Object` |\n| `opts.exitOnError` | `boolean` |\n| `opts.resetDaemonClient?` | `boolean` |\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### ensurePackage\n\n▸ **ensurePackage**(`tree`, `pkg`, `requiredVersion`, `options?`): `Promise`<`void`\\>\n\nEnsure that dependencies and devDependencies from package.json are installed at the required versions.\n\nFor example:\n\n```typescript\nensureDependencies(tree, {}, { '@nrwl/jest': nxVersion });\n```\n\nThis will check that @nrwl/jest@ exists in devDependencies.\nIf it exists then function returns, otherwise it will install the package before continuing.\nWhen running with --dryRun, the function will throw when dependencies are missing.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------------------ | :-------------------------------- | :------------------------------------- |\n| `tree` | [`Tree`](../../devkit/index#tree) | the file system tree |\n| `pkg` | `string` | the package to check (e.g. @nrwl/jest) |\n| `requiredVersion` | `string` | the version to check |\n| `options` | `Object` | |\n| `options.dev?` | `boolean` | - |\n| `options.throwOnMissing?` | `boolean` | - |\n\n#### Returns\n\n`Promise`<`void`\\>\n\n---\n\n### extractLayoutDirectory\n\n▸ **extractLayoutDirectory**(`directory`): `Object`\n\nExperimental\n\n#### Parameters\n\n| Name | Type |\n| :---------- | :------- |\n| `directory` | `string` |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :----------------- | :------- |\n| `layoutDirectory` | `string` |\n| `projectDirectory` | `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### getDependentPackagesForProject\n\n▸ **getDependentPackagesForProject**(`projectGraph`, `name`): `Object`\n\n#### Parameters\n\n| Name | Type |\n| :------------- | :-------------------------------------------------------- |\n| `projectGraph` | [`ProjectGraph`](../../devkit/index#projectgraph)<`any`\\> |\n| `name` | `string` |\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :------------------- | :---------------------------------------------------------- |\n| `npmPackages` | `string`[] |\n| `workspaceLibraries` | [`WorkspaceLibrary`](../../devkit/index#workspacelibrary)[] |\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### getNpmPackageSharedConfig\n\n▸ **getNpmPackageSharedConfig**(`pkgName`, `version`): [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) \\| `undefined`\n\nBuild the Module Federation Share Config for a specific package and the\nspecified version of that package.\n\n#### Parameters\n\n| Name | Type | Description |\n| :-------- | :------- | :----------------------------------------------------------------------------- |\n| `pkgName` | `string` | Name of the package to share |\n| `version` | `string` | Version of the package to require by other apps in the Module Federation setup |\n\n#### Returns\n\n[`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig) \\| `undefined`\n\n---\n\n### getOutputsForTargetAndConfiguration\n\n▸ **getOutputsForTargetAndConfiguration**(`task`, `node`): `string`[]\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), `\"overrides\"` \\| `\"target\"`\\> | target + overrides |\n| `node` | [`ProjectGraphProjectNode`](../../devkit/index#projectgraphprojectnode)<`any`\\> | ProjectGraphProjectNode object that the task runs against |\n\n#### Returns\n\n`string`[]\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### mapRemotes\n\n▸ **mapRemotes**(`remotes`, `remoteEntryExt`, `determineRemoteUrl`): `Record`<`string`, `string`\\>\n\nMap remote names to a format that can be understood and used by Module\nFederation.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------------- | :-------------------------------------- | :------------------------------------------------------- |\n| `remotes` | [`Remotes`](../../devkit/index#remotes) | The remotes to map |\n| `remoteEntryExt` | `\"js\"` \\| `\"mjs\"` | The file extension of the remoteEntry file |\n| `determineRemoteUrl` | (`remote`: `string`) => `string` | The function used to lookup the URL of the served remote |\n\n#### Returns\n\n`Record`<`string`, `string`\\>\n\n---\n\n### mapRemotesForSSR\n\n▸ **mapRemotesForSSR**(`remotes`, `remoteEntryExt`, `determineRemoteUrl`): `Record`<`string`, `string`\\>\n\nMap remote names to a format that can be understood and used by Module\nFederation.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------------- | :-------------------------------------- | :------------------------------------------------------- |\n| `remotes` | [`Remotes`](../../devkit/index#remotes) | The remotes to map |\n| `remoteEntryExt` | `\"js\"` \\| `\"mjs\"` | The file extension of the remoteEntry file |\n| `determineRemoteUrl` | (`remote`: `string`) => `string` | The function used to lookup the URL of the served remote |\n\n#### Returns\n\n`Record`<`string`, `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### readRootPackageJson\n\n▸ **readRootPackageJson**(): `Object`\n\n#### Returns\n\n`Object`\n\n| Name | Type |\n| :----------------- | :------- |\n| `dependencies?` | `Object` |\n| `devDependencies?` | `Object` |\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### sharePackages\n\n▸ **sharePackages**(`packages`): `Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\>\n\nCreate a dictionary of packages and their Module Federation Shared Config\nfrom an array of package names.\n\nLookup the versions of the packages from the root package.json file in the\nworkspace.\n\n#### Parameters\n\n| Name | Type | Description |\n| :--------- | :--------- | :-------------------------------- |\n| `packages` | `string`[] | Array of package names as strings |\n\n#### Returns\n\n`Record`<`string`, [`SharedLibraryConfig`](../../devkit/index#sharedlibraryconfig)\\>\n\n---\n\n### shareWorkspaceLibraries\n\n▸ **shareWorkspaceLibraries**(`libraries`, `tsConfigPath?`): [`SharedWorkspaceLibraryConfig`](../../devkit/index#sharedworkspacelibraryconfig)\n\nBuild an object of functions to be used with the ModuleFederationPlugin to\nshare Nx Workspace Libraries between Hosts and Remotes.\n\n#### Parameters\n\n| Name | Type | Description |\n| :------------- | :---------------------------------------------------------- | :--------------------------------------------------------------------------- |\n| `libraries` | [`WorkspaceLibrary`](../../devkit/index#workspacelibrary)[] | The Nx Workspace Libraries to share |\n| `tsConfigPath` | `string` | The path to TS Config File that contains the Path Mappings for the Libraries |\n\n#### Returns\n\n[`SharedWorkspaceLibraryConfig`](../../devkit/index#sharedworkspacelibraryconfig)\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/docs/generated/packages/webpack.json b/docs/generated/packages/webpack.json index bcc9900f250c0..f1b37b1100396 100644 --- a/docs/generated/packages/webpack.json +++ b/docs/generated/packages/webpack.json @@ -18,6 +18,12 @@ "description": "Init Webpack Plugin.", "type": "object", "properties": { + "uiFramework": { + "type": "string", + "description": "UI Framework to use for Vite.", + "enum": ["react", "none"], + "x-prompt": "What UI framework plugin should Webpack use?" + }, "compiler": { "type": "string", "enum": ["babel", "swc", "tsc"], diff --git a/packages/devkit/index.ts b/packages/devkit/index.ts index 76722b2ca11da..92ca1fefeb0d2 100644 --- a/packages/devkit/index.ts +++ b/packages/devkit/index.ts @@ -225,6 +225,7 @@ export { readJsonFile, writeJsonFile } from 'nx/src/utils/fileutils'; */ export { addDependenciesToPackageJson, + ensurePackage, removeDependenciesFromPackageJson, } from './src/utils/package-json'; diff --git a/packages/js/src/utils/async-iterable/combine-async-iteratable-iterators.ts b/packages/devkit/src/utils/async-iterable/combine-async-iteratable-iterators.ts similarity index 87% rename from packages/js/src/utils/async-iterable/combine-async-iteratable-iterators.ts rename to packages/devkit/src/utils/async-iterable/combine-async-iteratable-iterators.ts index 4046de85cae7d..0e8c41497f8d1 100644 --- a/packages/js/src/utils/async-iterable/combine-async-iteratable-iterators.ts +++ b/packages/devkit/src/utils/async-iterable/combine-async-iteratable-iterators.ts @@ -1,6 +1,6 @@ -export async function* combineAsyncIterableIterators( - ...iterators: { 0: AsyncIterableIterator } & AsyncIterableIterator[] -) { +export async function* combineAsyncIterableIterators( + ...iterators: { 0: AsyncIterableIterator } & AsyncIterableIterator[] +): AsyncGenerator { let [options] = iterators; if (typeof options.next === 'function') { options = Object.create(null); diff --git a/packages/js/src/utils/async-iterable/combine-async-iteratables-iterators.spec.ts b/packages/devkit/src/utils/async-iterable/combine-async-iteratables-iterators.spec.ts similarity index 100% rename from packages/js/src/utils/async-iterable/combine-async-iteratables-iterators.spec.ts rename to packages/devkit/src/utils/async-iterable/combine-async-iteratables-iterators.spec.ts diff --git a/packages/js/src/utils/async-iterable/create-async-iterable.spec.ts b/packages/devkit/src/utils/async-iterable/create-async-iterable.spec.ts similarity index 100% rename from packages/js/src/utils/async-iterable/create-async-iterable.spec.ts rename to packages/devkit/src/utils/async-iterable/create-async-iterable.spec.ts diff --git a/packages/js/src/utils/async-iterable/create-async-iterable.ts b/packages/devkit/src/utils/async-iterable/create-async-iterable.ts similarity index 100% rename from packages/js/src/utils/async-iterable/create-async-iterable.ts rename to packages/devkit/src/utils/async-iterable/create-async-iterable.ts diff --git a/packages/devkit/src/utils/async-iterable/index.ts b/packages/devkit/src/utils/async-iterable/index.ts new file mode 100644 index 0000000000000..22687ccaca16a --- /dev/null +++ b/packages/devkit/src/utils/async-iterable/index.ts @@ -0,0 +1,4 @@ +export * from './create-async-iterable'; +export * from './combine-async-iteratable-iterators'; +export * from './map-async-iteratable'; +export * from './tap-async-iteratable'; diff --git a/packages/js/src/utils/async-iterable/map-async-iteratable.spec.ts b/packages/devkit/src/utils/async-iterable/map-async-iteratable.spec.ts similarity index 100% rename from packages/js/src/utils/async-iterable/map-async-iteratable.spec.ts rename to packages/devkit/src/utils/async-iterable/map-async-iteratable.spec.ts diff --git a/packages/js/src/utils/async-iterable/map-async-iteratable.ts b/packages/devkit/src/utils/async-iterable/map-async-iteratable.ts similarity index 92% rename from packages/js/src/utils/async-iterable/map-async-iteratable.ts rename to packages/devkit/src/utils/async-iterable/map-async-iteratable.ts index 6ff58ff44afec..a7af704f017bb 100644 --- a/packages/js/src/utils/async-iterable/map-async-iteratable.ts +++ b/packages/devkit/src/utils/async-iterable/map-async-iteratable.ts @@ -5,7 +5,7 @@ export async function* mapAsyncIterable( index?: number, data?: AsyncIterable | AsyncIterableIterator ) => O -) { +): AsyncIterable | AsyncIterableIterator { async function* f() { const generator = data[Symbol.asyncIterator] || data[Symbol.iterator]; const iterator = generator.call(data); diff --git a/packages/js/src/utils/async-iterable/tap-async-iteratable.spec.ts b/packages/devkit/src/utils/async-iterable/tap-async-iteratable.spec.ts similarity index 80% rename from packages/js/src/utils/async-iterable/tap-async-iteratable.spec.ts rename to packages/devkit/src/utils/async-iterable/tap-async-iteratable.spec.ts index 6ba8d07940dad..9018eed22ec8a 100644 --- a/packages/js/src/utils/async-iterable/tap-async-iteratable.spec.ts +++ b/packages/devkit/src/utils/async-iterable/tap-async-iteratable.spec.ts @@ -1,4 +1,4 @@ -import { tapAsyncIterator } from './tap-async-iteratable'; +import { tapAsyncIterable } from './tap-async-iteratable'; describe('tapAsyncIterator', () => { it('should tap values', async () => { @@ -11,7 +11,7 @@ describe('tapAsyncIterator', () => { const tapped = []; const results = []; - const c = tapAsyncIterator(f(), (x) => { + const c = tapAsyncIterable(f(), (x) => { tapped.push(`tap: ${x}`); }); diff --git a/packages/js/src/utils/async-iterable/tap-async-iteratable.ts b/packages/devkit/src/utils/async-iterable/tap-async-iteratable.ts similarity index 66% rename from packages/js/src/utils/async-iterable/tap-async-iteratable.ts rename to packages/devkit/src/utils/async-iterable/tap-async-iteratable.ts index 8ff02bf62e489..6ac6f389e30d3 100644 --- a/packages/js/src/utils/async-iterable/tap-async-iteratable.ts +++ b/packages/devkit/src/utils/async-iterable/tap-async-iteratable.ts @@ -1,9 +1,9 @@ import { mapAsyncIterable } from './map-async-iteratable'; -export async function* tapAsyncIterator( +export async function* tapAsyncIterable( data: AsyncIterable | AsyncIterableIterator, fn: (input: I) => void -) { +): AsyncIterable | AsyncIterableIterator { return yield* mapAsyncIterable(data, (x) => { fn(x); return x; diff --git a/packages/devkit/src/utils/package-json.spec.ts b/packages/devkit/src/utils/package-json.spec.ts index 4321333a19056..528e11bf7c23d 100644 --- a/packages/devkit/src/utils/package-json.spec.ts +++ b/packages/devkit/src/utils/package-json.spec.ts @@ -1,6 +1,6 @@ import type { Tree } from 'nx/src/generators/tree'; import { readJson, writeJson } from 'nx/src/generators/utils/json'; -import { addDependenciesToPackageJson } from './package-json'; +import { addDependenciesToPackageJson, ensurePackage } from './package-json'; import { createTree } from 'nx/src/generators/testing-utils/create-tree'; describe('addDependenciesToPackageJson', () => { @@ -310,3 +310,42 @@ describe('addDependenciesToPackageJson', () => { expect(installTask).toBeDefined(); }); }); + +describe('ensureDependencies', () => { + let tree: Tree; + + beforeEach(() => { + tree = createTree(); + }); + + it('should return without error when dependency is satisfied', async () => { + writeJson(tree, 'package.json', { + devDependencies: { + '@nrwl/vite': '15.0.0', + }, + }); + + await expect( + ensurePackage(tree, '@nrwl/vite', '>=15.0.0', { + throwOnMissing: true, + }) + ).resolves.toBeUndefined(); + }); + + it('should throw when dependencies are missing', async () => { + writeJson(tree, 'package.json', {}); + + await expect(() => + ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', { + throwOnMissing: true, + }) + ).rejects.toThrow(/-D( -W)? @nrwl\/does-not-exist@>=15.0.0/); + + await expect(() => + ensurePackage(tree, '@nrwl/does-not-exist', '>=15.0.0', { + dev: false, + throwOnMissing: true, + }) + ).rejects.toThrow('@nrwl/does-not-exist@>=15.0.0'); + }); +}); diff --git a/packages/devkit/src/utils/package-json.ts b/packages/devkit/src/utils/package-json.ts index 8430cd76fe968..031a770522d78 100644 --- a/packages/devkit/src/utils/package-json.ts +++ b/packages/devkit/src/utils/package-json.ts @@ -2,7 +2,9 @@ import { readJson, updateJson } from 'nx/src/generators/utils/json'; import { installPackagesTask } from '../tasks/install-packages-task'; import type { Tree } from 'nx/src/generators/tree'; import { GeneratorCallback } from 'nx/src/config/misc-interfaces'; -import { coerce, gt } from 'semver'; +import { coerce, gt, satisfies } from 'semver'; +import { getPackageManagerCommand } from 'nx/src/utils/package-manager'; +import { execSync } from 'child_process'; const NON_SEMVER_TAGS = { '*': 2, @@ -274,3 +276,73 @@ function requiresRemovingOfPackages( return needsDepsUpdate || needsDevDepsUpdate; } + +/** + * @typedef EnsurePackageOptions + * @type {object} + * @property {boolean} dev indicate if the package is a dev dependency + * @property {throwOnMissing} boolean throws an error when the packag is missing + */ + +/** + * Ensure that dependencies and devDependencies from package.json are installed at the required versions. + * + * For example: + * ```typescript + * ensureDependencies(tree, {}, { '@nrwl/jest': nxVersion }) + * ``` + * This will check that @nrwl/jest@ exists in devDependencies. + * If it exists then function returns, otherwise it will install the package before continuing. + * When running with --dryRun, the function will throw when dependencies are missing. + * + * @param tree the file system tree + * @param pkg the package to check (e.g. @nrwl/jest) + * @param requiredVersion the version to check + * @param {EnsurePackageOptions} options + * @returns {Promise} + */ +export async function ensurePackage( + tree: Tree, + pkg: string, + requiredVersion: string, + options: { + dev?: boolean; + throwOnMissing?: boolean; + } = {} +): Promise { + let version: string; + + // Read package and version from root package.json file. + const packageJson = readJson(tree, 'package.json'); + const dev = options.dev ?? true; + const throwOnMissing = options.throwOnMissing ?? !!process.env.NX_DRY_RUN; // NX_DRY_RUN is set in `packages/nx/src/command-line/generate.ts` + const pmc = getPackageManagerCommand(); + const field = dev ? 'devDependencies' : 'dependencies'; + + version = packageJson[field]?.[pkg]; + + // If package not found, try to resolve it using Node and get its version. + if (!version) { + try { + version = require(`${pkg}/package.json`).version; + } catch { + // ignore + } + } + + if (!satisfies(version, requiredVersion)) { + const installCmd = `${ + dev ? pmc.addDev : pmc.add + } ${pkg}@${requiredVersion}`; + if (throwOnMissing) { + throw new Error( + `Required package ${pkg}@${requiredVersion} is missing. Run "${installCmd}", and then try again.` + ); + } else { + execSync(installCmd, { + cwd: tree.root, + stdio: [0, 1, 2], + }); + } + } +} diff --git a/packages/esbuild/src/executors/esbuild/esbuild.impl.ts b/packages/esbuild/src/executors/esbuild/esbuild.impl.ts index 87bfb959dd4fa..a99571e664f6a 100644 --- a/packages/esbuild/src/executors/esbuild/esbuild.impl.ts +++ b/packages/esbuild/src/executors/esbuild/esbuild.impl.ts @@ -15,7 +15,7 @@ import { normalizeOptions } from './lib/normalize'; import { EsBuildExecutorOptions } from './schema'; import { removeSync, writeJsonSync } from 'fs-extra'; -import { createAsyncIterable } from '@nrwl/js/src/utils/async-iterable/create-async-iterable'; +import { createAsyncIterable } from '@nrwl/devkit/src/utils/async-iterable'; import { buildEsbuildOptions } from './lib/build-esbuild-options'; import { getExtraDependencies } from './lib/get-extra-dependencies'; import { DependentBuildableProjectNode } from '@nrwl/workspace/src/utilities/buildable-libs-utils'; diff --git a/packages/js/package.json b/packages/js/package.json index 170d61d001bde..e222beb61acfb 100644 --- a/packages/js/package.json +++ b/packages/js/package.json @@ -33,7 +33,6 @@ "builders": "./executors.json", "dependencies": { "@nrwl/devkit": "file:../devkit", - "@nrwl/jest": "file:../jest", "@nrwl/linter": "file:../linter", "@nrwl/workspace": "file:../workspace", "chalk": "4.1.0", diff --git a/packages/js/src/generators/library/library.ts b/packages/js/src/generators/library/library.ts index 12c8d709df924..d404ee70af493 100644 --- a/packages/js/src/generators/library/library.ts +++ b/packages/js/src/generators/library/library.ts @@ -2,6 +2,7 @@ import { addDependenciesToPackageJson, addProjectConfiguration, convertNxGenerator, + ensurePackage, extractLayoutDirectory, formatFiles, generateFiles, @@ -18,7 +19,6 @@ import { writeJson, } from '@nrwl/devkit'; import { getImportPath } from 'nx/src/utils/path'; -import { jestProjectGenerator } from '@nrwl/jest'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { @@ -293,6 +293,8 @@ async function addJest( tree: Tree, options: NormalizedSchema ): Promise { + await ensurePackage(tree, '@nrwl/jest', nxVersion); + const { jestProjectGenerator } = await import('@nrwl/jest'); return await jestProjectGenerator(tree, { ...options, project: options.name, diff --git a/packages/js/src/utils/swc/compile-swc.ts b/packages/js/src/utils/swc/compile-swc.ts index c597470802372..138b0d0c0608f 100644 --- a/packages/js/src/utils/swc/compile-swc.ts +++ b/packages/js/src/utils/swc/compile-swc.ts @@ -1,7 +1,7 @@ import { cacheDir, ExecutorContext, logger } from '@nrwl/devkit'; import { exec, execSync } from 'child_process'; import { removeSync } from 'fs-extra'; -import { createAsyncIterable } from '../async-iterable/create-async-iterable'; +import { createAsyncIterable } from '@nrwl/devkit/src/utils/async-iterable'; import { NormalizedSwcExecutorOptions, SwcCliOptions } from '../schema'; import { printDiagnostics } from '../typescript/print-diagnostics'; import { runTypeCheck, TypeCheckOptions } from '../typescript/run-type-check'; diff --git a/packages/js/src/utils/typescript/compile-typescript-files.ts b/packages/js/src/utils/typescript/compile-typescript-files.ts index 88e5d13110e0f..70ae56fb8a25a 100644 --- a/packages/js/src/utils/typescript/compile-typescript-files.ts +++ b/packages/js/src/utils/typescript/compile-typescript-files.ts @@ -4,7 +4,7 @@ import { TypeScriptCompilationOptions, } from '@nrwl/workspace/src/utilities/typescript/compilation'; import type { Diagnostic } from 'typescript'; -import { createAsyncIterable } from '../async-iterable/create-async-iterable'; +import { createAsyncIterable } from '@nrwl/devkit/src/utils/async-iterable'; import { NormalizedExecutorOptions } from '../schema'; const TYPESCRIPT_FOUND_N_ERRORS_WATCHING_FOR_FILE_CHANGES = 6194; diff --git a/packages/linter/package.json b/packages/linter/package.json index a34a04085f3a9..d9ff9f0838e74 100644 --- a/packages/linter/package.json +++ b/packages/linter/package.json @@ -34,7 +34,6 @@ }, "dependencies": { "@nrwl/devkit": "file:../devkit", - "@nrwl/jest": "file:../jest", "@phenomnomnominal/tsquery": "4.1.1", "nx": "file:../nx", "tmp": "~0.2.1", diff --git a/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts b/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts index 0a212ce1091bc..c60a119b11af8 100644 --- a/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts +++ b/packages/linter/src/generators/workspace-rules-project/workspace-rules-project.ts @@ -2,6 +2,7 @@ import { addDependenciesToPackageJson, addProjectConfiguration, convertNxGenerator, + ensurePackage, formatFiles, generateFiles, joinPathFragments, @@ -11,17 +12,22 @@ import { Tree, updateWorkspaceConfiguration, } from '@nrwl/devkit'; -import { addPropertyToJestConfig, jestProjectGenerator } from '@nrwl/jest'; import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; import { join } from 'path'; import { workspaceLintPluginDir } from '../../utils/workspace-lint-rules'; import { swcCoreVersion, swcNodeVersion } from 'nx/src/utils/versions'; +import { nxVersion } from '../../utils/versions'; export const WORKSPACE_RULES_PROJECT_NAME = 'eslint-rules'; export const WORKSPACE_PLUGIN_DIR = 'tools/eslint-rules'; export async function lintWorkspaceRulesProjectGenerator(tree: Tree) { + await ensurePackage(tree, '@nrwl/jest/', nxVersion); + const { addPropertyToJestConfig, jestProjectGenerator } = await import( + '@nrwl/jest' + ); + // Noop if the workspace rules project already exists try { readProjectConfiguration(tree, WORKSPACE_RULES_PROJECT_NAME); diff --git a/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts b/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts index b30ad503e13b4..ea778068f18ff 100644 --- a/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts +++ b/packages/linter/src/migrations/update-13-3-0/eslint-8-updates.ts @@ -4,11 +4,11 @@ import { Tree, visitNotIgnoredFiles, } from '@nrwl/devkit'; -import { addPropertyToJestConfig } from '@nrwl/jest'; import { tsquery } from '@phenomnomnominal/tsquery'; export default async function eslint8Updates(tree: Tree) { try { + const { addPropertyToJestConfig } = await import('@nrwl/jest'); const existingJestConfigPath = normalizePath( 'tools/eslint-rules/jest.config.js' ); diff --git a/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts b/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts index 66eefc0cacc10..29cae3dbe352a 100644 --- a/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts +++ b/packages/nest/src/generators/convert-tslint-to-eslint/convert-tslint-to-eslint.spec.ts @@ -9,11 +9,12 @@ import { import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; import { exampleRootTslintJson } from '@nrwl/linter'; import { conversionGenerator } from './convert-tslint-to-eslint'; +import * as devkit from '@nrwl/devkit'; /** * Don't run actual child_process implementation of installPackagesTask() */ -jest.mock('child_process'); +// jest.mock('child_process'); const appProjectName = 'nest-app-1'; const appProjectRoot = `apps/${appProjectName}`; @@ -101,6 +102,7 @@ describe('convert-tslint-to-eslint', () => { let host: Tree; beforeEach(async () => { + jest.spyOn(devkit, 'installPackagesTask'); host = createTreeWithEmptyV1Workspace(); writeJson(host, 'tslint.json', exampleRootTslintJson.raw); diff --git a/packages/nx/src/command-line/generate.ts b/packages/nx/src/command-line/generate.ts index dc0daf72d1c8a..c16a85ff87be9 100644 --- a/packages/nx/src/command-line/generate.ts +++ b/packages/nx/src/command-line/generate.ts @@ -289,6 +289,9 @@ export async function generate(cwd: string, args: { [k: string]: any }) { 'generate', projectsConfiguration ); + if (opts.dryRun) { + process.env.NX_DRY_RUN = 'true'; + } const { normalizedGeneratorName, schema, implementationFactory, aliases } = ws.readGenerator(opts.collectionName, opts.generatorName); diff --git a/packages/react-native/src/generators/stories/stories.ts b/packages/react-native/src/generators/stories/stories.ts index 637a5f3e49465..0abf25d5b7b9e 100644 --- a/packages/react-native/src/generators/stories/stories.ts +++ b/packages/react-native/src/generators/stories/stories.ts @@ -22,8 +22,8 @@ export async function createAllStories( const projects = getProjects(tree); const projectConfiguration = projects.get(projectName); - const { sourceRoot, root } = projectConfiguration; - const projectPath = projectRootPath(projectConfiguration); + const { sourceRoot } = projectConfiguration; + const projectPath = await projectRootPath(tree, projectConfiguration); let componentPaths: string[] = []; visitNotIgnoredFiles(tree, projectPath, (path) => { diff --git a/packages/react/migrations.json b/packages/react/migrations.json index ce6e5008cf932..982d7cb06fba8 100644 --- a/packages/react/migrations.json +++ b/packages/react/migrations.json @@ -71,6 +71,12 @@ "version": "15.3.0-beta.0", "description": "Update projects using @nrwl/web:rollup to @nrwl/rollup:rollup for build.", "factory": "./src/migrations/update-15-3-0/update-rollup-executor" + }, + "install-webpack-rollup-dependencies": { + "cli": "nx", + "version": "15.3.0-beta.0", + "description": "Install new dependencies for React projects using Webpack or Rollup.", + "factory": "./src/migrations/update-15-3-0/install-webpack-rollup-dependencies" } }, "packageJsonUpdates": { diff --git a/packages/react/package.json b/packages/react/package.json index 60c574f5e4dd8..43ef6306b0112 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -31,32 +31,12 @@ "migrations": "./migrations.json" }, "dependencies": { - "@babel/core": "^7.15.0", - "@babel/preset-react": "^7.14.5", - "@nrwl/cypress": "file:../cypress", "@nrwl/devkit": "file:../devkit", - "@nrwl/jest": "file:../jest", - "@nrwl/js": "file:../js", "@nrwl/linter": "file:../linter", - "@nrwl/storybook": "file:../storybook", - "@nrwl/vite": "file:../vite", - "@nrwl/web": "file:../web", - "@nrwl/webpack": "file:../webpack", "@nrwl/workspace": "file:../workspace", - "@pmmmwh/react-refresh-webpack-plugin": "^0.5.7", - "@phenomnomnominal/tsquery": "4.1.1", - "@svgr/webpack": "^6.1.2", "chalk": "4.1.0", - "css-loader": "^6.4.0", "minimatch": "3.0.5", - "react-refresh": "^0.10.0", - "semver": "7.3.4", - "style-loader": "^3.3.0", - "stylus": "^0.55.0", - "stylus-loader": "^7.1.0", - "url-loader": "^4.1.1", - "webpack": "^5.75.0", - "webpack-merge": "^5.8.0" + "semver": "7.3.4" }, "publishConfig": { "access": "public" diff --git a/packages/react/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts b/packages/react/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts index 39ca1164222e3..1968dc89e0882 100644 --- a/packages/react/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts +++ b/packages/react/src/executors/module-federation-dev-server/module-federation-dev-server.impl.ts @@ -3,8 +3,10 @@ import devServerExecutor from '@nrwl/webpack/src/executors/dev-server/dev-server import { WebDevServerOptions } from '@nrwl/webpack/src/executors/dev-server/schema'; import { join } from 'path'; import * as chalk from 'chalk'; -import { combineAsyncIterableIterators } from '@nrwl/js/src/utils/async-iterable/combine-async-iteratable-iterators'; -import { tapAsyncIterator } from '@nrwl/js/src/utils/async-iterable/tap-async-iteratable'; +import { + combineAsyncIterableIterators, + tapAsyncIterable, +} from '@nrwl/devkit/src/utils/async-iterable'; type ModuleFederationDevServerOptions = WebDevServerOptions & { devRemotes?: string | string[]; @@ -65,7 +67,7 @@ export default async function* moduleFederationDevServer( } let numAwaiting = knownRemotes.length + 1; // remotes + host - return yield* tapAsyncIterator(iter, (x) => { + return yield* tapAsyncIterable(iter, (x) => { numAwaiting--; if (numAwaiting === 0) { logger.info( diff --git a/packages/react/src/generators/application/application.ts b/packages/react/src/generators/application/application.ts index 72a3c2055fe3c..c6c88fc462a95 100644 --- a/packages/react/src/generators/application/application.ts +++ b/packages/react/src/generators/application/application.ts @@ -15,6 +15,7 @@ import { addStyledModuleDependencies } from '../../rules/add-styled-dependencies import { addDependenciesToPackageJson, convertNxGenerator, + ensurePackage, formatFiles, GeneratorCallback, joinPathFragments, @@ -24,10 +25,12 @@ import { import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import reactInitGenerator from '../init/init'; import { Linter, lintProjectGenerator } from '@nrwl/linter'; -import { swcCoreVersion } from '@nrwl/js/src/utils/versions'; -import { swcLoaderVersion } from '@nrwl/webpack/src/utils/versions'; -import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite'; import { mapLintPattern } from '@nrwl/linter/src/generators/lint-project/lint-project'; +import { + nxVersion, + swcCoreVersion, + swcLoaderVersion, +} from '../../utils/versions'; async function addLinting(host: Tree, options: NormalizedSchema) { const tasks: GeneratorCallback[] = []; @@ -90,6 +93,8 @@ export async function applicationGenerator(host: Tree, schema: Schema) { addProject(host, options); if (options.bundler === 'vite') { + await ensurePackage(host, '@nrwl/vite', nxVersion); + const { viteConfigurationGenerator } = await import('@nrwl/vite'); // We recommend users use `import.meta.env.MODE` and other variables in their code to differentiate between production and development. // See: https://vitejs.dev/guide/env-and-mode.html host.delete(joinPathFragments(options.appProjectRoot, 'src/environments')); @@ -101,9 +106,20 @@ export async function applicationGenerator(host: Tree, schema: Schema) { includeVitest: true, }); tasks.push(viteTask); + } else if (options.bundler === 'webpack') { + await ensurePackage(host, '@nrwl/webpack', nxVersion); + + const { webpackInitGenerator } = await import('@nrwl/webpack'); + const webpackInitTask = await webpackInitGenerator(host, { + uiFramework: 'react', + }); + tasks.push(webpackInitTask); } if (options.bundler !== 'vite' && options.unitTestRunner === 'vitest') { + await ensurePackage(host, '@nrwl/vite', nxVersion); + const { vitestGenerator } = await import('@nrwl/vite'); + const vitestTask = await vitestGenerator(host, { uiFramework: 'react', project: options.projectName, diff --git a/packages/react/src/generators/application/lib/add-cypress.ts b/packages/react/src/generators/application/lib/add-cypress.ts index 61fc114528eec..539576ecaf013 100644 --- a/packages/react/src/generators/application/lib/add-cypress.ts +++ b/packages/react/src/generators/application/lib/add-cypress.ts @@ -1,11 +1,13 @@ -import { cypressProjectGenerator } from '@nrwl/cypress'; -import { Tree } from '@nrwl/devkit'; +import { ensurePackage, Tree } from '@nrwl/devkit'; +import { nxVersion } from '../../../utils/versions'; import { NormalizedSchema } from '../schema'; export async function addCypress(host: Tree, options: NormalizedSchema) { if (options.e2eTestRunner !== 'cypress') { return () => {}; } + await ensurePackage(host, '@nrwl/cypress', nxVersion); + const { cypressProjectGenerator } = await import('@nrwl/cypress'); return await cypressProjectGenerator(host, { ...options, diff --git a/packages/react/src/generators/application/lib/add-jest.ts b/packages/react/src/generators/application/lib/add-jest.ts index ff23ea0af4de4..56c06f9b972e7 100644 --- a/packages/react/src/generators/application/lib/add-jest.ts +++ b/packages/react/src/generators/application/lib/add-jest.ts @@ -1,8 +1,11 @@ -import { Tree } from '@nrwl/devkit'; -import { jestProjectGenerator } from '@nrwl/jest'; +import { ensurePackage, Tree } from '@nrwl/devkit'; import { NormalizedSchema } from '../schema'; +import { nxVersion } from '../../../utils/versions'; export async function addJest(host: Tree, options: NormalizedSchema) { + await ensurePackage(host, '@nrwl/jest', nxVersion); + const { jestProjectGenerator } = await import('@nrwl/jest'); + if (options.unitTestRunner !== 'jest') { return () => {}; } diff --git a/packages/react/src/generators/component-test/component-test.spec.ts b/packages/react/src/generators/component-test/component-test.spec.ts index 822b366e89aa3..fe9acc514544c 100644 --- a/packages/react/src/generators/component-test/component-test.spec.ts +++ b/packages/react/src/generators/component-test/component-test.spec.ts @@ -26,7 +26,7 @@ describe(componentTestGenerator.name, () => { component: true, }); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'lib/some-lib.tsx', }); @@ -47,7 +47,7 @@ describe(componentTestGenerator.name, () => { js: true, }); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'lib/some-lib.js', }); @@ -67,7 +67,7 @@ describe(componentTestGenerator.name, () => { component: true, }); tree.write('libs/some-lib/src/lib/some-lib.cy.tsx', 'existing content'); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'lib/some-lib.tsx', }); @@ -89,12 +89,12 @@ describe(componentTestGenerator.name, () => { component: true, }); - expect(() => { + await expect( componentTestGenerator(tree, { project: 'some-lib', componentPath: 'lib/blah/abc-123.blah', - }); - }).not.toThrow(); + }) + ).resolves.not.toThrow(); }); it('should handle being provided the full path to the component', async () => { @@ -109,7 +109,7 @@ describe(componentTestGenerator.name, () => { component: true, }); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -144,11 +144,11 @@ export interface AnotherCmpProps { } export function AnotherCmp(props: AnotherCmpProps) { - return ; + return ; } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -180,7 +180,7 @@ export function AnotherCmp() { } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -214,7 +214,7 @@ export interface AnotherCmpProps { } export default function AnotherCmp(props: AnotherCmpProps) { - return ; + return ; } export function AnotherCmp2() { @@ -222,7 +222,7 @@ export function AnotherCmp2() { } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -257,7 +257,7 @@ export interface AnotherCmpProps { } export function AnotherCmp(props: AnotherCmpProps) { - return ; + return ; } export function AnotherCmp2() { @@ -265,7 +265,7 @@ export function AnotherCmp2() { } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -302,11 +302,11 @@ export interface AnotherCmpProps { } export function AnotherCmp(props: AnotherCmpProps) { - return ; + return ; } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -328,7 +328,7 @@ export function AnotherCmp(props: AnotherCmpProps) { unitTestRunner: 'none', component: true, }); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -362,11 +362,11 @@ export interface AnotherCmpProps { } export default function AnotherCmp(props: AnotherCmpProps) { - return ; + return ; } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); @@ -400,11 +400,11 @@ export interface AnotherCmpProps { } export function AnotherCmp(props: AnotherCmpProps) { - return ; + return ; } ` ); - componentTestGenerator(tree, { + await componentTestGenerator(tree, { project: 'some-lib', componentPath: 'libs/some-lib/src/lib/some-lib.tsx', }); diff --git a/packages/react/src/generators/component-test/component-test.ts b/packages/react/src/generators/component-test/component-test.ts index 801e3f70cd7ca..26e69f1ca0abf 100644 --- a/packages/react/src/generators/component-test/component-test.ts +++ b/packages/react/src/generators/component-test/component-test.ts @@ -1,5 +1,5 @@ -import { assertMinimumCypressVersion } from '@nrwl/cypress/src/utils/cypress-version'; import { + ensurePackage, generateFiles, joinPathFragments, readProjectConfiguration, @@ -12,12 +12,17 @@ import { getComponentNode, } from '../../utils/ast-utils'; import { getDefaultsForComponent } from '../../utils/component-props'; +import { nxVersion } from '../../utils/versions'; import { ComponentTestSchema } from './schema'; -export function componentTestGenerator( +export async function componentTestGenerator( tree: Tree, options: ComponentTestSchema ) { + await ensurePackage(tree, '@nrwl/cypress', nxVersion); + const { assertMinimumCypressVersion } = await import( + '@nrwl/cypress/src/utils/cypress-version' + ); assertMinimumCypressVersion(10); const projectConfig = readProjectConfiguration(tree, options.project); diff --git a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts index ea53edb529b49..3ac5523961ef0 100644 --- a/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts +++ b/packages/react/src/generators/cypress-component-configuration/cypress-component-configuration.ts @@ -1,5 +1,10 @@ -import { cypressComponentProject } from '@nrwl/cypress'; -import { formatFiles, readProjectConfiguration, Tree } from '@nrwl/devkit'; +import { + ensurePackage, + formatFiles, + readProjectConfiguration, + Tree, +} from '@nrwl/devkit'; +import { nxVersion } from '../../utils/versions'; import { addFiles } from './lib/add-files'; import { updateProjectConfig } from './lib/update-configs'; import { CypressComponentConfigurationSchema } from './schema.d'; @@ -13,6 +18,8 @@ export async function cypressComponentConfigGenerator( tree: Tree, options: CypressComponentConfigurationSchema ) { + await ensurePackage(tree, '@nrwl/cypress', nxVersion); + const { cypressComponentProject } = await import('@nrwl/cypress'); const projectConfig = readProjectConfiguration(tree, options.project); const installTask = await cypressComponentProject(tree, { project: options.project, @@ -20,7 +27,7 @@ export async function cypressComponentConfigGenerator( }); await updateProjectConfig(tree, options); - addFiles(tree, projectConfig, options); + await addFiles(tree, projectConfig, options); if (options.skipFormat) { await formatFiles(tree); } diff --git a/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts b/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts index 2c5ddf3588f12..81b2c0ef62b2c 100644 --- a/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts +++ b/packages/react/src/generators/cypress-component-configuration/lib/add-files.ts @@ -13,7 +13,7 @@ import { CypressComponentConfigurationSchema } from '../schema'; const allowedFileExt = new RegExp(/\.[jt]sx?/g); const isSpecFile = new RegExp(/(spec|test)\./g); -export function addFiles( +export async function addFiles( tree: Tree, projectConfig: ProjectConfiguration, options: CypressComponentConfigurationSchema @@ -36,14 +36,19 @@ export function addFiles( ); if (options.generateTests) { + const filePaths = []; visitNotIgnoredFiles(tree, projectConfig.sourceRoot, (filePath) => { if (isComponent(tree, filePath)) { - componentTestGenerator(tree, { - project: options.project, - componentPath: filePath, - }); + filePaths.push(filePath); } }); + + for (const filePath of filePaths) { + await componentTestGenerator(tree, { + project: options.project, + componentPath: filePath, + }); + } } } diff --git a/packages/react/src/generators/cypress-component-configuration/lib/update-configs.ts b/packages/react/src/generators/cypress-component-configuration/lib/update-configs.ts index bd11912df4c61..57d83ba4531eb 100644 --- a/packages/react/src/generators/cypress-component-configuration/lib/update-configs.ts +++ b/packages/react/src/generators/cypress-component-configuration/lib/update-configs.ts @@ -1,10 +1,6 @@ -import { findBuildConfig } from '@nrwl/cypress/src/utils/find-target-options'; import { - joinPathFragments, - ProjectConfiguration, readProjectConfiguration, Tree, - updateJson, updateProjectConfiguration, } from '@nrwl/devkit'; import { CypressComponentConfigurationSchema } from '../schema'; @@ -13,6 +9,9 @@ export async function updateProjectConfig( tree: Tree, options: CypressComponentConfigurationSchema ) { + const { findBuildConfig } = await import( + '@nrwl/cypress/src/utils/find-target-options' + ); const found = await findBuildConfig(tree, { project: options.project, buildTarget: options.buildTarget, diff --git a/packages/react/src/generators/init/init.spec.ts b/packages/react/src/generators/init/init.spec.ts index 61d1317b5d617..0d2ed5e92c7f2 100644 --- a/packages/react/src/generators/init/init.spec.ts +++ b/packages/react/src/generators/init/init.spec.ts @@ -1,4 +1,4 @@ -import { NxJsonConfiguration, readJson, Tree } from '@nrwl/devkit'; +import { readJson, Tree } from '@nrwl/devkit'; import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; import reactInitGenerator from './init'; import { InitSchema } from './schema'; @@ -30,4 +30,9 @@ describe('init', () => { await reactInitGenerator(tree, { ...schema, unitTestRunner: 'none' }); expect(tree.exists('jest.config.js')).toEqual(false); }); + + it('should not add babel.config.json if skipBabelConfig is true', async () => { + await reactInitGenerator(tree, { ...schema, skipBabelConfig: true }); + expect(tree.exists('babel.config.json')).toEqual(false); + }); }); diff --git a/packages/react/src/generators/init/init.ts b/packages/react/src/generators/init/init.ts index e5526e4a8320c..35b674e64d963 100755 --- a/packages/react/src/generators/init/init.ts +++ b/packages/react/src/generators/init/init.ts @@ -1,16 +1,17 @@ -import { cypressInitGenerator } from '@nrwl/cypress'; import { addDependenciesToPackageJson, convertNxGenerator, + ensurePackage, GeneratorCallback, readWorkspaceConfiguration, removeDependenciesFromPackageJson, Tree, updateWorkspaceConfiguration, + writeJson, } from '@nrwl/devkit'; -import { webInitGenerator } from '@nrwl/web'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { + babelPresetReactVersion, nxVersion, reactDomVersion, reactTestRendererVersion, @@ -66,22 +67,54 @@ function updateDependencies(host: Tree, schema: InitSchema) { }); } +function initRootBabelConfig(tree: Tree, schema: InitSchema) { + if (tree.exists('/babel.config.json') || tree.exists('/babel.config.js')) { + return; + } + + if (!schema.skipBabelConfig) { + writeJson(tree, '/babel.config.json', { + babelrcRoots: ['*'], // Make sure .babelrc files other than root can be loaded in a monorepo + }); + } + + const workspaceConfiguration = readWorkspaceConfiguration(tree); + + if (workspaceConfiguration.namedInputs?.sharedGlobals) { + workspaceConfiguration.namedInputs.sharedGlobals.push( + '{workspaceRoot}/babel.config.json' + ); + } + updateWorkspaceConfiguration(tree, workspaceConfiguration); +} + export async function reactInitGenerator(host: Tree, schema: InitSchema) { const tasks: GeneratorCallback[] = []; setDefault(host); if (!schema.e2eTestRunner || schema.e2eTestRunner === 'cypress') { + await ensurePackage(host, '@nrwl/cypress', nxVersion); + const { cypressInitGenerator } = await import('@nrwl/cypress'); const cypressTask = cypressInitGenerator(host, {}); tasks.push(cypressTask); } - // TODO(jack): We should be able to remove this generator and have react init everything. - const initTask = await webInitGenerator(host, { - ...schema, - skipPackageJson: true, - }); - tasks.push(initTask); + if (!schema.skipPackageJson && !schema.skipBabelConfig) { + const installBabelTask = addDependenciesToPackageJson( + host, + {}, + { + '@babel/preset-react': babelPresetReactVersion, + } + ); + tasks.push(installBabelTask); + } + + if (!schema.skipBabelConfig) { + initRootBabelConfig(host, schema); + } + if (!schema.skipPackageJson) { const installTask = updateDependencies(host, schema); tasks.push(installTask); diff --git a/packages/react/src/generators/library/lib/add-linting.ts b/packages/react/src/generators/library/lib/add-linting.ts new file mode 100644 index 0000000000000..4e4106c962efc --- /dev/null +++ b/packages/react/src/generators/library/lib/add-linting.ts @@ -0,0 +1,47 @@ +import { Tree } from 'nx/src/generators/tree'; +import { Linter, lintProjectGenerator } from '@nrwl/linter'; +import { joinPathFragments } from 'nx/src/utils/path'; +import { updateJson } from 'nx/src/generators/utils/json'; +import { addDependenciesToPackageJson } from '@nrwl/devkit'; +import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; + +import { NormalizedSchema } from '../schema'; +import { + extendReactEslintJson, + extraEslintDependencies, +} from '../../../utils/lint'; + +export async function addLinting(host: Tree, options: NormalizedSchema) { + if (options.linter === Linter.EsLint) { + const lintTask = await lintProjectGenerator(host, { + linter: options.linter, + project: options.name, + tsConfigPaths: [ + joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), + ], + unitTestRunner: options.unitTestRunner, + eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`], + skipFormat: true, + skipPackageJson: options.skipPackageJson, + }); + + updateJson( + host, + joinPathFragments(options.projectRoot, '.eslintrc.json'), + extendReactEslintJson + ); + + let installTask = () => {}; + if (!options.skipPackageJson) { + installTask = await addDependenciesToPackageJson( + host, + extraEslintDependencies.dependencies, + extraEslintDependencies.devDependencies + ); + } + + return runTasksInSerial(lintTask, installTask); + } else { + return () => {}; + } +} diff --git a/packages/react/src/generators/library/lib/add-rollup-build-target.ts b/packages/react/src/generators/library/lib/add-rollup-build-target.ts new file mode 100644 index 0000000000000..bd47588f742f7 --- /dev/null +++ b/packages/react/src/generators/library/lib/add-rollup-build-target.ts @@ -0,0 +1,65 @@ +import { Tree } from 'nx/src/generators/tree'; +import { + ensurePackage, + getWorkspaceLayout, + joinPathFragments, + readProjectConfiguration, + updateProjectConfiguration, +} from '@nrwl/devkit'; + +import { maybeJs } from './maybe-js'; +import { NormalizedSchema } from '../schema'; +import { nxVersion } from '../../../utils/versions'; + +export async function addRollupBuildTarget( + host: Tree, + options: NormalizedSchema +) { + await ensurePackage(host, '@nrwl/rollup', nxVersion); + const { rollupInitGenerator } = await import('@nrwl/rollup'); + + const { targets } = readProjectConfiguration(host, options.name); + + const { libsDir } = getWorkspaceLayout(host); + const external: string[] = []; + + if (options.style === '@emotion/styled') { + external.push('@emotion/react/jsx-runtime'); + } else { + external.push('react/jsx-runtime'); + } + + targets.build = { + executor: '@nrwl/rollup:rollup', + outputs: ['{options.outputPath}'], + options: { + outputPath: + libsDir !== '.' + ? `dist/${libsDir}/${options.projectDirectory}` + : `dist/${options.projectDirectory}`, + tsConfig: `${options.projectRoot}/tsconfig.lib.json`, + project: `${options.projectRoot}/package.json`, + entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`), + external, + rollupConfig: `@nrwl/react/plugins/bundle-rollup`, + compiler: options.compiler ?? 'babel', + assets: [ + { + glob: `${options.projectRoot}/README.md`, + input: '.', + output: '.', + }, + ], + }, + }; + + updateProjectConfiguration(host, options.name, { + root: options.projectRoot, + sourceRoot: joinPathFragments(options.projectRoot, 'src'), + projectType: 'library', + tags: options.parsedTags, + targets, + }); + + return rollupInitGenerator(host, options); +} diff --git a/packages/react/src/generators/library/lib/create-files.ts b/packages/react/src/generators/library/lib/create-files.ts new file mode 100644 index 0000000000000..9c6ece6c78323 --- /dev/null +++ b/packages/react/src/generators/library/lib/create-files.ts @@ -0,0 +1,74 @@ +import { Tree } from 'nx/src/generators/tree'; +import { + generateFiles, + joinPathFragments, + names, + offsetFromRoot, + toJS, + updateJson, +} from '@nrwl/devkit'; +import { getRelativePathToRootTsConfig } from '@nrwl/workspace/src/utilities/typescript'; + +import { NormalizedSchema } from '../schema'; + +export function createFiles(host: Tree, options: NormalizedSchema) { + const substitutions = { + ...options, + ...names(options.name), + tmpl: '', + offsetFromRoot: offsetFromRoot(options.projectRoot), + rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot), + }; + + generateFiles( + host, + joinPathFragments(__dirname, '../files/common'), + options.projectRoot, + substitutions + ); + + if (options.bundler === 'vite') { + generateFiles( + host, + joinPathFragments(__dirname, '../files/vite'), + options.projectRoot, + substitutions + ); + + if (host.exists(joinPathFragments(options.projectRoot, '.babelrc'))) { + host.delete(joinPathFragments(options.projectRoot, '.babelrc')); + } + } + + if (!options.publishable && !options.buildable) { + host.delete(`${options.projectRoot}/package.json`); + } + + if (options.js) { + toJS(host); + } + + updateTsConfig(host, options); +} + +function updateTsConfig(tree: Tree, options: NormalizedSchema) { + updateJson( + tree, + joinPathFragments(options.projectRoot, 'tsconfig.json'), + (json) => { + if (options.strict) { + json.compilerOptions = { + ...json.compilerOptions, + forceConsistentCasingInFileNames: true, + strict: true, + noImplicitOverride: true, + noPropertyAccessFromIndexSignature: true, + noImplicitReturns: true, + noFallthroughCasesInSwitch: true, + }; + } + + return json; + } + ); +} diff --git a/packages/react/src/generators/library/lib/maybe-js.ts b/packages/react/src/generators/library/lib/maybe-js.ts new file mode 100644 index 0000000000000..274417777b012 --- /dev/null +++ b/packages/react/src/generators/library/lib/maybe-js.ts @@ -0,0 +1,7 @@ +import { NormalizedSchema } from '../schema'; + +export function maybeJs(options: NormalizedSchema, path: string): string { + return options.js && (path.endsWith('.ts') || path.endsWith('.tsx')) + ? path.replace(/\.tsx?$/, '.js') + : path; +} diff --git a/packages/react/src/generators/library/lib/normalize-options.ts b/packages/react/src/generators/library/lib/normalize-options.ts index bbcd12ac043fd..3e33ee70d5b99 100644 --- a/packages/react/src/generators/library/lib/normalize-options.ts +++ b/packages/react/src/generators/library/lib/normalize-options.ts @@ -9,8 +9,7 @@ import { Tree, } from '@nrwl/devkit'; import { assertValidStyle } from '../../../utils/assertion'; -import { NormalizedSchema } from '../library'; -import { Schema } from '../schema'; +import { NormalizedSchema, Schema } from '../schema'; export function normalizeOptions( host: Tree, @@ -40,7 +39,9 @@ export function normalizeOptions( const normalized = { ...options, compiler: options.compiler ?? 'babel', - bundler: options.bundler ?? 'none', + bundler: + options.bundler ?? + (options.buildable || options.publishable ? 'rollup' : 'none'), fileName, routePath: `/${name}`, name: projectName, diff --git a/packages/react/src/generators/library/lib/update-app-routes.ts b/packages/react/src/generators/library/lib/update-app-routes.ts new file mode 100644 index 0000000000000..fe87a36cf694f --- /dev/null +++ b/packages/react/src/generators/library/lib/update-app-routes.ts @@ -0,0 +1,111 @@ +import { + addDependenciesToPackageJson, + applyChangesToString, + getWorkspaceLayout, + names, +} from '@nrwl/devkit'; +import { Tree } from 'nx/src/generators/tree'; +import { getImportPath, joinPathFragments } from 'nx/src/utils/path'; +import * as ts from 'typescript'; + +import { NormalizedSchema } from '../schema'; +import { + addBrowserRouter, + addInitialRoutes, + addRoute, + findComponentImportPath, +} from '../../../utils/ast-utils'; +import { maybeJs } from './maybe-js'; +import { + reactRouterDomVersion, + typesReactRouterDomVersion, +} from '../../../utils/versions'; + +export function updateAppRoutes(host: Tree, options: NormalizedSchema) { + if (!options.appMain || !options.appSourceRoot) { + return () => {}; + } + + const { content, source } = readComponent(host, options.appMain); + + const componentImportPath = findComponentImportPath('App', source); + + if (!componentImportPath) { + throw new Error( + `Could not find App component in ${options.appMain} (Hint: you can omit --appProject, or make sure App exists)` + ); + } + + const appComponentPath = joinPathFragments( + options.appSourceRoot, + maybeJs(options, `${componentImportPath}.tsx`) + ); + + const routerTask = addDependenciesToPackageJson( + host, + { 'react-router-dom': reactRouterDomVersion }, + { '@types/react-router-dom': typesReactRouterDomVersion } + ); + + // addBrowserRouterToMain + const isRouterPresent = content.match(/react-router-dom/); + if (!isRouterPresent) { + const changes = applyChangesToString( + content, + addBrowserRouter(options.appMain, source) + ); + host.write(options.appMain, changes); + } + + // addInitialAppRoutes + { + const { content: componentContent, source: componentSource } = + readComponent(host, appComponentPath); + const isComponentRouterPresent = componentContent.match(/react-router-dom/); + if (!isComponentRouterPresent) { + const changes = applyChangesToString( + componentContent, + addInitialRoutes(appComponentPath, componentSource) + ); + host.write(appComponentPath, changes); + } + } + + // addNewAppRoute + { + const { content: componentContent, source: componentSource } = + readComponent(host, appComponentPath); + const { npmScope } = getWorkspaceLayout(host); + const changes = applyChangesToString( + componentContent, + addRoute(appComponentPath, componentSource, { + routePath: options.routePath, + componentName: names(options.name).className, + moduleName: getImportPath(npmScope, options.projectDirectory), + }) + ); + host.write(appComponentPath, changes); + } + + return routerTask; +} + +function readComponent( + host: Tree, + path: string +): { content: string; source: ts.SourceFile } { + if (!host.exists(path)) { + throw new Error(`Cannot find ${path}`); + } + + const content = host.read(path, 'utf-8'); + + const source = ts.createSourceFile( + path, + content, + ts.ScriptTarget.Latest, + true + ); + + return { content, source }; +} diff --git a/packages/react/src/generators/library/lib/update-base-tsconfig.ts b/packages/react/src/generators/library/lib/update-base-tsconfig.ts new file mode 100644 index 0000000000000..91a31186ca768 --- /dev/null +++ b/packages/react/src/generators/library/lib/update-base-tsconfig.ts @@ -0,0 +1,32 @@ +import { Tree } from 'nx/src/generators/tree'; +import { updateJson } from 'nx/src/generators/utils/json'; +import { getRootTsConfigPathInTree } from '@nrwl/workspace/src/utilities/typescript'; +import { getWorkspaceLayout, joinPathFragments } from '@nrwl/devkit'; + +import { NormalizedSchema } from '../schema'; +import { maybeJs } from './maybe-js'; + +export function updateBaseTsConfig(host: Tree, options: NormalizedSchema) { + updateJson(host, getRootTsConfigPathInTree(host), (json) => { + const c = json.compilerOptions; + c.paths = c.paths || {}; + delete c.paths[options.name]; + + if (c.paths[options.importPath]) { + throw new Error( + `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` + ); + } + + const { libsDir } = getWorkspaceLayout(host); + + c.paths[options.importPath] = [ + maybeJs( + options, + joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`) + ), + ]; + + return json; + }); +} diff --git a/packages/react/src/generators/library/library.spec.ts b/packages/react/src/generators/library/library.spec.ts index f0cd6596c62ca..3a756ee37e895 100644 --- a/packages/react/src/generators/library/library.spec.ts +++ b/packages/react/src/generators/library/library.spec.ts @@ -11,6 +11,7 @@ import { createTreeWithEmptyWorkspace, } from '@nrwl/devkit/testing'; import { Linter } from '@nrwl/linter'; +import { nxVersion } from '../../utils/versions'; import applicationGenerator from '../application/application'; import libraryGenerator from './library'; import { Schema } from './schema'; @@ -37,6 +38,16 @@ describe('lib', () => { beforeEach(() => { mockedInstalledCypressVersion.mockReturnValue(10); tree = createTreeWithEmptyV1Workspace(); + updateJson(tree, '/package.json', (json) => { + json.devDependencies = { + '@nrwl/cypress': nxVersion, + '@nrwl/jest': nxVersion, + '@nrwl/rollup': nxVersion, + '@nrwl/vite': nxVersion, + '@nrwl/webpack': nxVersion, + }; + return json; + }); }); describe('not nested', () => { @@ -726,7 +737,6 @@ describe('lib', () => { describe('--skipPackageJson', () => { it('should not add dependencies to package.json when true', async () => { // ARRANGE - const tree = createTreeWithEmptyWorkspace({ layout: 'apps-libs' }); const packageJsonBeforeGenerator = tree.read('package.json', 'utf-8'); // ACT await libraryGenerator(tree, { diff --git a/packages/react/src/generators/library/library.ts b/packages/react/src/generators/library/library.ts index ee1ec11a6b833..12edeeea2e28a 100644 --- a/packages/react/src/generators/library/library.ts +++ b/packages/react/src/generators/library/library.ts @@ -1,64 +1,32 @@ import { addDependenciesToPackageJson, addProjectConfiguration, - applyChangesToString, convertNxGenerator, + ensurePackage, formatFiles, - generateFiles, GeneratorCallback, - getWorkspaceLayout, joinPathFragments, - names, - offsetFromRoot, - toJS, Tree, updateJson, } from '@nrwl/devkit'; -import { getImportPath } from 'nx/src/utils/path'; -import { jestProjectGenerator } from '@nrwl/jest'; -import { swcCoreVersion } from '@nrwl/js/src/utils/versions'; -import { Linter, lintProjectGenerator } from '@nrwl/linter'; import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; + import { - getRelativePathToRootTsConfig, - getRootTsConfigPathInTree, -} from '@nrwl/workspace/src/utilities/typescript'; -import * as ts from 'typescript'; -import { - addBrowserRouter, - addInitialRoutes, - addRoute, - findComponentImportPath, -} from '../../utils/ast-utils'; -import { - extendReactEslintJson, - extraEslintDependencies, -} from '../../utils/lint'; -import { + nxVersion, reactDomVersion, - reactRouterDomVersion, reactVersion, - typesReactRouterDomVersion, + swcCoreVersion, } from '../../utils/versions'; import componentGenerator from '../component/component'; import initGenerator from '../init/init'; import { Schema } from './schema'; import { updateJestConfigContent } from '../../utils/jest-utils'; -import { viteConfigurationGenerator, vitestGenerator } from '@nrwl/vite'; import { normalizeOptions } from './lib/normalize-options'; - -export interface NormalizedSchema extends Schema { - name: string; - fileName: string; - projectRoot: string; - routePath: string; - projectDirectory: string; - parsedTags: string[]; - appMain?: string; - appSourceRoot?: string; - libsDir?: string; - unitTestRunner: 'jest' | 'vitest' | 'none'; -} +import { addRollupBuildTarget } from './lib/add-rollup-build-target'; +import { addLinting } from './lib/add-linting'; +import { updateAppRoutes } from './lib/update-app-routes'; +import { createFiles } from './lib/create-files'; +import { updateBaseTsConfig } from './lib/update-base-tsconfig'; export async function libraryGenerator(host: Tree, schema: Schema) { const tasks: GeneratorCallback[] = []; @@ -82,7 +50,18 @@ export async function libraryGenerator(host: Tree, schema: Schema) { }); tasks.push(initTask); - addProject(host, options); + addProjectConfiguration( + host, + options.name, + { + root: options.projectRoot, + sourceRoot: joinPathFragments(options.projectRoot, 'src'), + projectType: 'library', + tags: options.parsedTags, + targets: {}, + }, + options.standaloneConfig + ); const lintTask = await addLinting(host, options); tasks.push(lintTask); @@ -93,7 +72,10 @@ export async function libraryGenerator(host: Tree, schema: Schema) { updateBaseTsConfig(host, options); } + // Set up build target if (options.buildable && options.bundler === 'vite') { + await ensurePackage(host, '@nrwl/vite', nxVersion); + const { viteConfigurationGenerator } = await import('@nrwl/vite'); const viteTask = await viteConfigurationGenerator(host, { uiFramework: 'react', project: options.name, @@ -103,9 +85,16 @@ export async function libraryGenerator(host: Tree, schema: Schema) { includeVitest: true, }); tasks.push(viteTask); + } else if (options.buildable && options.bundler === 'rollup') { + const rollupTask = await addRollupBuildTarget(host, options); + tasks.push(rollupTask); } + // Set up test target if (options.unitTestRunner === 'jest') { + await ensurePackage(host, '@nrwl/jest', nxVersion); + const { jestProjectGenerator } = await import('@nrwl/jest'); + const jestTask = await jestProjectGenerator(host, { ...options, project: options.name, @@ -129,6 +118,8 @@ export async function libraryGenerator(host: Tree, schema: Schema) { options.unitTestRunner === 'vitest' && options.bundler !== 'vite' // tests are already configured if bundler is vite ) { + await ensurePackage(host, '@nrwl/vite', nxVersion); + const { vitestGenerator } = await import('@nrwl/vite'); const vitestTask = await vitestGenerator(host, { uiFramework: 'react', project: options.name, @@ -155,11 +146,14 @@ export async function libraryGenerator(host: Tree, schema: Schema) { } if (options.publishable || options.buildable) { - updateLibPackageNpmScope(host, options); + updateJson(host, `${options.projectRoot}/package.json`, (json) => { + json.name = options.importPath; + return json; + }); } if (!options.skipPackageJson) { - const installTask = await addDependenciesToPackageJson( + const installReactTask = await addDependenciesToPackageJson( host, { react: reactVersion, @@ -167,7 +161,7 @@ export async function libraryGenerator(host: Tree, schema: Schema) { }, options.compiler === 'swc' ? { '@swc/core': swcCoreVersion } : {} ); - tasks.push(installTask); + tasks.push(installReactTask); } const routeTask = updateAppRoutes(host, options); @@ -180,281 +174,5 @@ export async function libraryGenerator(host: Tree, schema: Schema) { return runTasksInSerial(...tasks); } -async function addLinting(host: Tree, options: NormalizedSchema) { - if (options.linter === Linter.EsLint) { - const lintTask = await lintProjectGenerator(host, { - linter: options.linter, - project: options.name, - tsConfigPaths: [ - joinPathFragments(options.projectRoot, 'tsconfig.lib.json'), - ], - unitTestRunner: options.unitTestRunner, - eslintFilePatterns: [`${options.projectRoot}/**/*.{ts,tsx,js,jsx}`], - skipFormat: true, - skipPackageJson: options.skipPackageJson, - }); - - updateJson( - host, - joinPathFragments(options.projectRoot, '.eslintrc.json'), - extendReactEslintJson - ); - - let installTask = () => {}; - if (!options.skipPackageJson) { - installTask = await addDependenciesToPackageJson( - host, - extraEslintDependencies.dependencies, - extraEslintDependencies.devDependencies - ); - } - - return runTasksInSerial(lintTask, installTask); - } else { - return () => {}; - } -} - -function addProject(host: Tree, options: NormalizedSchema) { - const targets: { [key: string]: any } = {}; - - if (options.publishable || options.buildable) { - const { libsDir } = getWorkspaceLayout(host); - const external: string[] = []; - - if (options.style === '@emotion/styled') { - external.push('@emotion/react/jsx-runtime'); - } else { - external.push('react/jsx-runtime'); - } - - targets.build = { - executor: '@nrwl/rollup:rollup', - outputs: ['{options.outputPath}'], - options: { - outputPath: - libsDir !== '.' - ? `dist/${libsDir}/${options.projectDirectory}` - : `dist/${options.projectDirectory}`, - tsConfig: `${options.projectRoot}/tsconfig.lib.json`, - project: `${options.projectRoot}/package.json`, - entryFile: maybeJs(options, `${options.projectRoot}/src/index.ts`), - external, - rollupConfig: `@nrwl/react/plugins/bundle-rollup`, - compiler: options.compiler ?? 'babel', - assets: [ - { - glob: `${options.projectRoot}/README.md`, - input: '.', - output: '.', - }, - ], - }, - }; - } - - addProjectConfiguration( - host, - options.name, - { - root: options.projectRoot, - sourceRoot: joinPathFragments(options.projectRoot, 'src'), - projectType: 'library', - tags: options.parsedTags, - targets, - }, - options.standaloneConfig - ); -} - -function updateTsConfig(tree: Tree, options: NormalizedSchema) { - updateJson( - tree, - joinPathFragments(options.projectRoot, 'tsconfig.json'), - (json) => { - if (options.strict) { - json.compilerOptions = { - ...json.compilerOptions, - forceConsistentCasingInFileNames: true, - strict: true, - noImplicitOverride: true, - noPropertyAccessFromIndexSignature: true, - noImplicitReturns: true, - noFallthroughCasesInSwitch: true, - }; - } - - return json; - } - ); -} - -function updateBaseTsConfig(host: Tree, options: NormalizedSchema) { - updateJson(host, getRootTsConfigPathInTree(host), (json) => { - const c = json.compilerOptions; - c.paths = c.paths || {}; - delete c.paths[options.name]; - - if (c.paths[options.importPath]) { - throw new Error( - `You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.` - ); - } - - const { libsDir } = getWorkspaceLayout(host); - - c.paths[options.importPath] = [ - maybeJs( - options, - joinPathFragments(libsDir, `${options.projectDirectory}/src/index.ts`) - ), - ]; - - return json; - }); -} - -function createFiles(host: Tree, options: NormalizedSchema) { - const substitutions = { - ...options, - ...names(options.name), - tmpl: '', - offsetFromRoot: offsetFromRoot(options.projectRoot), - rootTsConfigPath: getRelativePathToRootTsConfig(host, options.projectRoot), - }; - - generateFiles( - host, - joinPathFragments(__dirname, './files/common'), - options.projectRoot, - substitutions - ); - - if (options.bundler === 'vite') { - generateFiles( - host, - joinPathFragments(__dirname, './files/vite'), - options.projectRoot, - substitutions - ); - - if (host.exists(joinPathFragments(options.projectRoot, '.babelrc'))) { - host.delete(joinPathFragments(options.projectRoot, '.babelrc')); - } - } - - if (!options.publishable && !options.buildable) { - host.delete(`${options.projectRoot}/package.json`); - } - - if (options.js) { - toJS(host); - } - - updateTsConfig(host, options); -} - -function updateAppRoutes(host: Tree, options: NormalizedSchema) { - if (!options.appMain || !options.appSourceRoot) { - return () => {}; - } - - const { content, source } = readComponent(host, options.appMain); - - const componentImportPath = findComponentImportPath('App', source); - - if (!componentImportPath) { - throw new Error( - `Could not find App component in ${options.appMain} (Hint: you can omit --appProject, or make sure App exists)` - ); - } - - const appComponentPath = joinPathFragments( - options.appSourceRoot, - maybeJs(options, `${componentImportPath}.tsx`) - ); - - const routerTask = addDependenciesToPackageJson( - host, - { 'react-router-dom': reactRouterDomVersion }, - { '@types/react-router-dom': typesReactRouterDomVersion } - ); - - // addBrowserRouterToMain - const isRouterPresent = content.match(/react-router-dom/); - if (!isRouterPresent) { - const changes = applyChangesToString( - content, - addBrowserRouter(options.appMain, source) - ); - host.write(options.appMain, changes); - } - - // addInitialAppRoutes - { - const { content: componentContent, source: componentSource } = - readComponent(host, appComponentPath); - const isComponentRouterPresent = componentContent.match(/react-router-dom/); - if (!isComponentRouterPresent) { - const changes = applyChangesToString( - componentContent, - addInitialRoutes(appComponentPath, componentSource) - ); - host.write(appComponentPath, changes); - } - } - - // addNewAppRoute - { - const { content: componentContent, source: componentSource } = - readComponent(host, appComponentPath); - const { npmScope } = getWorkspaceLayout(host); - const changes = applyChangesToString( - componentContent, - addRoute(appComponentPath, componentSource, { - routePath: options.routePath, - componentName: names(options.name).className, - moduleName: getImportPath(npmScope, options.projectDirectory), - }) - ); - host.write(appComponentPath, changes); - } - - return routerTask; -} - -function readComponent( - host: Tree, - path: string -): { content: string; source: ts.SourceFile } { - if (!host.exists(path)) { - throw new Error(`Cannot find ${path}`); - } - - const content = host.read(path, 'utf-8'); - - const source = ts.createSourceFile( - path, - content, - ts.ScriptTarget.Latest, - true - ); - - return { content, source }; -} - -function updateLibPackageNpmScope(host: Tree, options: NormalizedSchema) { - return updateJson(host, `${options.projectRoot}/package.json`, (json) => { - json.name = options.importPath; - return json; - }); -} - -function maybeJs(options: NormalizedSchema, path: string): string { - return options.js && (path.endsWith('.ts') || path.endsWith('.tsx')) - ? path.replace(/\.tsx?$/, '.js') - : path; -} - export default libraryGenerator; export const librarySchematic = convertNxGenerator(libraryGenerator); diff --git a/packages/react/src/generators/library/schema.d.ts b/packages/react/src/generators/library/schema.d.ts index c6062ec2e6c0e..1633b34d17bda 100644 --- a/packages/react/src/generators/library/schema.d.ts +++ b/packages/react/src/generators/library/schema.d.ts @@ -1,4 +1,4 @@ -import { Linter } from '@nrwl/linter'; +import type { Linter } from '@nrwl/linter'; import { SupportedStyles } from '../../../typings/style'; export interface Schema { @@ -28,3 +28,17 @@ export interface Schema { unitTestRunner?: 'jest' | 'vitest' | 'none'; minimal?: boolean; } + +export interface NormalizedSchema extends Schema { + js: boolean; + name: string; + fileName: string; + projectRoot: string; + routePath: string; + projectDirectory: string; + parsedTags: string[]; + appMain?: string; + appSourceRoot?: string; + libsDir?: string; + unitTestRunner: 'jest' | 'vitest' | 'none'; +} diff --git a/packages/react/src/generators/stories/stories.ts b/packages/react/src/generators/stories/stories.ts index 0c228d8f866b2..c4a6e3e5adc81 100644 --- a/packages/react/src/generators/stories/stories.ts +++ b/packages/react/src/generators/stories/stories.ts @@ -15,10 +15,6 @@ import { visitNotIgnoredFiles, } from '@nrwl/devkit'; import { basename, join } from 'path'; -import { - findStorybookAndBuildTargetsAndCompiler, - isTheFileAStory, -} from '@nrwl/storybook/src/utils/utilities'; import minimatch = require('minimatch'); export interface StorybookStoriesSchema { @@ -29,7 +25,13 @@ export interface StorybookStoriesSchema { ignorePaths?: string[]; } -export function projectRootPath(config: ProjectConfiguration): string { +export async function projectRootPath( + tree: Tree, + config: ProjectConfiguration +): Promise { + const { findStorybookAndBuildTargetsAndCompiler } = await import( + '@nrwl/storybook/src/utils/utilities' + ); let projectDir: string; if (config.projectType === 'application') { const { nextBuildTarget } = findStorybookAndBuildTargetsAndCompiler( @@ -79,12 +81,16 @@ export async function createAllStories( cypressProject?: string, ignorePaths?: string[] ) { + const { isTheFileAStory } = await import( + '@nrwl/storybook/src/utils/utilities' + ); const projects = getProjects(tree); const projectConfiguration = projects.get(projectName); const { sourceRoot, root } = projectConfiguration; let componentPaths: string[] = []; - visitNotIgnoredFiles(tree, projectRootPath(projectConfiguration), (path) => { + const projectPath = await projectRootPath(tree, projectConfiguration); + visitNotIgnoredFiles(tree, projectPath, (path) => { // Ignore private files starting with "_". if (basename(path).startsWith('_')) return; diff --git a/packages/react/src/generators/storybook-configuration/configuration.ts b/packages/react/src/generators/storybook-configuration/configuration.ts index 35d9fb77e20f4..5e4537b85d3d5 100644 --- a/packages/react/src/generators/storybook-configuration/configuration.ts +++ b/packages/react/src/generators/storybook-configuration/configuration.ts @@ -2,14 +2,18 @@ import { StorybookConfigureSchema } from './schema'; import storiesGenerator from '../stories/stories'; import { convertNxGenerator, + ensurePackage, logger, readProjectConfiguration, Tree, } from '@nrwl/devkit'; -import { configurationGenerator } from '@nrwl/storybook'; -import { getE2eProjectName } from '@nrwl/cypress/src/utils/project-name'; +import { nxVersion } from '../../utils/versions'; async function generateStories(host: Tree, schema: StorybookConfigureSchema) { + await ensurePackage(host, '@nrwl/cypress', nxVersion); + const { getE2eProjectName } = await import( + '@nrwl/cypress/src/utils/project-name' + ); const projectConfig = readProjectConfiguration(host, schema.name); const cypressProject = getE2eProjectName( schema.name, @@ -30,6 +34,9 @@ export async function storybookConfigurationGenerator( host: Tree, schema: StorybookConfigureSchema ) { + await ensurePackage(host, '@nrwl/storybook', nxVersion); + const { configurationGenerator } = await import('@nrwl/storybook'); + let bundler = schema.bundler ?? 'webpack'; const projectConfig = readProjectConfiguration(host, schema.name); diff --git a/packages/react/src/migrations/update-12-0-0/remove-react-redux-types-package.spec.ts b/packages/react/src/migrations/update-12-0-0/remove-react-redux-types-package.spec.ts deleted file mode 100644 index af19cbd678ffb..0000000000000 --- a/packages/react/src/migrations/update-12-0-0/remove-react-redux-types-package.spec.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { readJson, Tree } from '@nrwl/devkit'; -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; -import * as path from 'path'; -import { removeReactReduxTypesFromPackageJson } from './remove-react-redux-types-package'; -import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing'; - -describe('Remove @types/react-redux Package from package.json 12.0.0', () => { - let tree: Tree; - let schematicRunner: SchematicTestRunner; - - beforeEach(async () => { - tree = createTreeWithEmptyV1Workspace(); - - schematicRunner = new SchematicTestRunner( - '@nrwl/react', - path.join(__dirname, '../../../migrations.json') - ); - }); - - it(`should remove @types/react-redux from deps and/or from devDeps in package.json`, async () => { - tree.write( - 'package.json', - JSON.stringify({ - dependencies: { - '@types/react-redux': '10.1.1', - }, - devDependencies: { - '@types/react-redux': '10.1.1', - }, - }) - ); - await removeReactReduxTypesFromPackageJson(tree); - - const packageJson = readJson(tree, '/package.json'); - expect(packageJson).toMatchObject({ - dependencies: {}, - devDependencies: {}, - }); - }); -}); diff --git a/packages/react/src/migrations/update-14-6-0/add-preset-jest-config.ts b/packages/react/src/migrations/update-14-6-0/add-preset-jest-config.ts index 11e185f355526..1ad1ebd0b19e5 100644 --- a/packages/react/src/migrations/update-14-6-0/add-preset-jest-config.ts +++ b/packages/react/src/migrations/update-14-6-0/add-preset-jest-config.ts @@ -4,7 +4,7 @@ import { readProjectConfiguration, Tree, } from '@nrwl/devkit'; -import { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema'; +import type { JestExecutorOptions } from '@nrwl/jest/src/executors/jest/schema'; import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils'; import { tsquery } from '@phenomnomnominal/tsquery'; import { StringLiteral } from 'typescript'; diff --git a/packages/react/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.spec.ts b/packages/react/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.spec.ts new file mode 100644 index 0000000000000..1a8a040b23664 --- /dev/null +++ b/packages/react/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.spec.ts @@ -0,0 +1,62 @@ +import { addProjectConfiguration, readJson } from '@nrwl/devkit'; +import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing'; +import { installWebpackRollupDependencies } from './install-webpack-rollup-dependencies'; + +describe('installWebpackRollupDependencies', () => { + it('should install packages if webpack is used', async () => { + const tree = createTreeWithEmptyWorkspace(); + + addProjectConfiguration(tree, 'proj', { + root: 'proj', + targets: { + build: { executor: '@nrwl/webpack:webpack' }, + }, + }); + + await installWebpackRollupDependencies(tree); + + expect(readJson(tree, 'package.json')).toMatchObject({ + devDependencies: { + webpack: '^5.75.0', + }, + }); + }); + + it('should install packages if rollup is used', async () => { + const tree = createTreeWithEmptyWorkspace(); + + addProjectConfiguration(tree, 'proj', { + root: 'proj', + targets: { + build: { executor: '@nrwl/rollup:rollup' }, + }, + }); + + await installWebpackRollupDependencies(tree); + + expect(readJson(tree, 'package.json')).toMatchObject({ + devDependencies: { + webpack: '^5.75.0', + }, + }); + }); + + it('should not install packages if neither webpack nor rollup are used', async () => { + const tree = createTreeWithEmptyWorkspace(); + + addProjectConfiguration(tree, 'proj', { + root: 'proj', + targets: { + build: { executor: '@nrwl/vite:vite' }, + }, + }); + + await installWebpackRollupDependencies(tree); + + expect(readJson(tree, 'package.json')).not.toMatchObject({ + devDependencies: { + webpack: '^5.75.0', + }, + }); + }); +}); diff --git a/packages/react/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.ts b/packages/react/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.ts new file mode 100644 index 0000000000000..b3537a69cade0 --- /dev/null +++ b/packages/react/src/migrations/update-15-3-0/install-webpack-rollup-dependencies.ts @@ -0,0 +1,42 @@ +import { addDependenciesToPackageJson, getProjects, Tree } from '@nrwl/devkit'; + +export function installWebpackRollupDependencies(tree: Tree) { + const projects = getProjects(tree); + let shouldInstall = false; + + for (const [, project] of projects) { + if ( + project.targets?.build?.executor === '@nrwl/webpack:webpack' || + project.targets?.build?.executor === '@nrwl/rollup:rollup' || + project.targets?.build?.executor === '@nrwl/web:rollup' + ) { + shouldInstall = true; + break; + } + } + + if (shouldInstall) { + // These were previously dependencies of `@nrwl/react` but we've removed them + // to accommodate different bundlers and test runners. + return addDependenciesToPackageJson( + tree, + {}, + { + '@babel/preset-react': '^7.14.5', + '@pmmmwh/react-refresh-webpack-plugin': '^0.5.7', + '@phenomnomnominal/tsquery': '4.1.1', + '@svgr/webpack': '^6.1.2', + 'css-loader': '^6.4.0', + 'react-refresh': '^0.10.0', + 'style-loader': '^3.3.0', + stylus: '^0.55.0', + 'stylus-loader': '^7.1.0', + 'url-loader': '^4.1.1', + webpack: '^5.75.0', + 'webpack-merge': '^5.8.0', + } + ); + } +} + +export default installWebpackRollupDependencies; diff --git a/packages/react/src/migrations/utils/rules.ts b/packages/react/src/migrations/utils/rules.ts deleted file mode 100644 index 2fbf009568e8c..0000000000000 --- a/packages/react/src/migrations/utils/rules.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Rule, Tree } from '@angular-devkit/schematics'; - -export function initRootBabelConfig(): Rule { - return (host: Tree) => { - if (host.exists('/babel.config.json') || host.exists('/babel.config.js')) - return; - host.create( - '/babel.config.json', - JSON.stringify( - { - presets: ['@nrwl/web/babel'], - babelrcRoots: ['*'], // Make sure .babelrc files other than root can be loaded in a monorepo - }, - null, - 2 - ) - ); - }; -} diff --git a/packages/react/src/migrations/utils/testing.ts b/packages/react/src/migrations/utils/testing.ts deleted file mode 100644 index c71dd663e0b07..0000000000000 --- a/packages/react/src/migrations/utils/testing.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { join } from 'path'; -import { SchematicTestRunner } from '@angular-devkit/schematics/testing'; -import { Rule, Tree } from '@angular-devkit/schematics'; -import { updateWorkspace } from '@nrwl/workspace/src/utils/workspace'; -import { readJsonInTree } from '@nrwl/workspace'; -import { names } from '@nrwl/devkit'; - -const testRunner = new SchematicTestRunner( - '@nrwl/react', - join(__dirname, '../../../generators.json') -); - -testRunner.registerCollection( - '@nrwl/jest', - join(__dirname, '../../../../jest/generators.json') -); - -testRunner.registerCollection( - '@nrwl/cypress', - join(__dirname, '../../../../cypress/generators.json') -); - -testRunner.registerCollection( - '@nrwl/storybook', - join(__dirname, '../../../../storybook/generators.json') -); - -export function callRule(rule: Rule, tree: Tree) { - return testRunner.callRule(rule, tree).toPromise(); -} - -export function updateNxJson(tree, update: (json: any) => any) { - const updated = update(readJsonInTree(tree, '/nx.json')); - tree.overwrite('/nx.json', JSON.stringify(updated)); -} - -export function createApp(tree: Tree, appName: string): Promise { - const { fileName } = names(appName); - - tree.create( - `/apps/${fileName}/src/main.tsx`, - `import ReactDOM from 'react-dom';\n` - ); - - updateNxJson(tree, (json) => { - json.projects[appName] = { tags: [] }; - return json; - }); - - return callRule( - updateWorkspace((workspace) => { - workspace.projects.add({ - name: fileName, - root: `apps/${fileName}`, - projectType: 'application', - sourceRoot: `apps/${fileName}/src`, - targets: {}, - }); - }), - tree - ); -} - -export function createWebApp(tree: Tree, appName: string): Promise { - const { fileName } = names(appName); - - tree.create(`/apps/${fileName}/src/index.ts`, `\n`); - - updateNxJson(tree, (json) => { - json.projects[appName] = { tags: [] }; - return json; - }); - - return callRule( - updateWorkspace((workspace) => { - workspace.projects.add({ - name: fileName, - root: `apps/${fileName}`, - projectType: 'application', - sourceRoot: `apps/${fileName}/src`, - targets: {}, - }); - }), - tree - ); -} - -export function createLib(tree: Tree, libName: string): Promise { - const { fileName } = names(libName); - - tree.create(`/libs/${fileName}/src/index.ts`, `import React from 'react';\n`); - - updateNxJson(tree, (json) => { - json.projects[libName] = { tags: [] }; - return json; - }); - - return callRule( - updateWorkspace((workspace) => { - workspace.projects.add({ - name: fileName, - root: `libs/${fileName}`, - projectType: 'library', - sourceRoot: `libs/${fileName}/src`, - targets: {}, - }); - }), - tree - ); -} diff --git a/packages/react/src/utils/versions.ts b/packages/react/src/utils/versions.ts index cc27d4b90f02b..4ba690860d815 100755 --- a/packages/react/src/utils/versions.ts +++ b/packages/react/src/utils/versions.ts @@ -3,12 +3,16 @@ export const nxVersion = require('../../package.json').version; export const reactVersion = '18.2.0'; export const reactDomVersion = '18.2.0'; export const reactIsVersion = '18.2.0'; +export const swcLoaderVersion = '0.1.15'; +export const swcCoreVersion = '^1.2.173'; export const typesReactVersion = '18.0.25'; export const typesReactDomVersion = '18.0.9'; export const typesReactIsVersion = '17.0.3'; export const typesNodeVersion = '18.11.9'; +export const babelPresetReactVersion = '^7.14.5'; + export const styledComponentsVersion = '5.3.6'; export const typesStyledComponentsVersion = '5.1.26'; diff --git a/packages/rollup/index.ts b/packages/rollup/index.ts index 348565fdd5a14..07188dea2ee4c 100644 --- a/packages/rollup/index.ts +++ b/packages/rollup/index.ts @@ -1,2 +1,4 @@ +export * from './src/generators/init/init'; +export * from './src/generators/rollup-project/rollup-project'; export * from './src/executors/rollup/schema'; export * from './src/executors/rollup/rollup.impl'; diff --git a/packages/rollup/src/generators/init/init.ts b/packages/rollup/src/generators/init/init.ts index 3a86f769be91c..af74ae67f4c9a 100644 --- a/packages/rollup/src/generators/init/init.ts +++ b/packages/rollup/src/generators/init/init.ts @@ -27,9 +27,7 @@ export async function rollupInitGenerator(tree: Tree, schema: Schema) { 'swc-loader': swcLoaderVersion, } ); - } - - if (schema.compiler === 'tsc') { + } else { task = addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion }); } diff --git a/packages/webpack/index.ts b/packages/webpack/index.ts index 2bf324588d8a8..57e56c9b3afbc 100644 --- a/packages/webpack/index.ts +++ b/packages/webpack/index.ts @@ -1,4 +1,5 @@ export * from './src/utils/config'; +export * from './src/generators/init/init'; export * from './src/generators/webpack-project/webpack-project'; export type { WebDevServerOptions } from './src/executors/dev-server/schema'; export * from './src/executors/dev-server/dev-server.impl'; diff --git a/packages/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts b/packages/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts index 6d3a127bad5a5..15e592e00d418 100644 --- a/packages/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts +++ b/packages/webpack/src/executors/ssr-dev-server/ssr-dev-server.impl.ts @@ -5,10 +5,10 @@ import { runExecutor, } from '@nrwl/devkit'; import * as chalk from 'chalk'; -import { combineAsyncIterableIterators } from '@nrwl/js/src/utils/async-iterable/combine-async-iteratable-iterators'; +import { combineAsyncIterableIterators } from '@nrwl/devkit/src/utils/async-iterable'; import { WebpackExecutorOptions } from '../webpack/schema'; -import { WebSsrDevServerOptions } from './schema'; +import { TargetOptions, WebSsrDevServerOptions } from './schema'; import { waitUntilServerIsListening } from './lib/wait-until-server-is-listening'; export async function* ssrDevServerExecutor( @@ -29,6 +29,7 @@ export async function* ssrDevServerExecutor( const runBrowser = await runExecutor<{ success: boolean; baseUrl?: string; + options: TargetOptions; }>( browserTarget, { ...browserOptions, ...options.browserTargetOptions }, @@ -37,6 +38,7 @@ export async function* ssrDevServerExecutor( const runServer = await runExecutor<{ success: boolean; baseUrl?: string; + options: TargetOptions; }>( serverTarget, { ...serverOptions, ...options.serverTargetOptions }, diff --git a/packages/webpack/src/generators/init/init.ts b/packages/webpack/src/generators/init/init.ts index 0babd09590970..3cc5819f143aa 100644 --- a/packages/webpack/src/generators/init/init.ts +++ b/packages/webpack/src/generators/init/init.ts @@ -5,24 +5,31 @@ import { GeneratorCallback, Tree, } from '@nrwl/devkit'; -import { Schema } from './schema'; +import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial'; import { swcCoreVersion } from '@nrwl/js/src/utils/versions'; + +import { Schema } from './schema'; import { + reactRefreshVersion, + reactRefreshWebpackPluginVersion, + svgrWebpackVersion, swcHelpersVersion, swcLoaderVersion, tsLibVersion, + tsQueryVersion, + urlLoaderVersion, } from '../../utils/versions'; import { addBabelInputs } from '@nrwl/js/src/utils/add-babel-inputs'; export async function webpackInitGenerator(tree: Tree, schema: Schema) { - let task: GeneratorCallback; + const tasks: GeneratorCallback[] = []; if (schema.compiler === 'babel') { addBabelInputs(tree); } if (schema.compiler === 'swc') { - task = addDependenciesToPackageJson( + const swcInstallTask = addDependenciesToPackageJson( tree, {}, { @@ -31,17 +38,39 @@ export async function webpackInitGenerator(tree: Tree, schema: Schema) { 'swc-loader': swcLoaderVersion, } ); + tasks.push(swcInstallTask); } if (schema.compiler === 'tsc') { - task = addDependenciesToPackageJson(tree, {}, { tslib: tsLibVersion }); + const tscInstallTask = addDependenciesToPackageJson( + tree, + {}, + { tslib: tsLibVersion } + ); + tasks.push(tscInstallTask); + } + + if (schema.uiFramework === 'react') { + const reactInstallTask = addDependenciesToPackageJson( + tree, + {}, + { + '@pmmmwh/react-refresh-webpack-plugin': + reactRefreshWebpackPluginVersion, + '@phenomnomnominal/tsquery': tsQueryVersion, + '@svgr/webpack': svgrWebpackVersion, + 'react-refresh': reactRefreshVersion, + 'url-loader': urlLoaderVersion, + } + ); + tasks.push(reactInstallTask); } if (!schema.skipFormat) { await formatFiles(tree); } - return task; + return runTasksInSerial(...tasks); } export default webpackInitGenerator; diff --git a/packages/webpack/src/generators/init/schema.d.ts b/packages/webpack/src/generators/init/schema.d.ts index 0b1664d543f2c..584d1172e2796 100644 --- a/packages/webpack/src/generators/init/schema.d.ts +++ b/packages/webpack/src/generators/init/schema.d.ts @@ -1,4 +1,5 @@ export interface Schema { compiler?: 'babel' | 'swc' | 'tsc'; + uiFramework?: 'react' | 'none'; skipFormat?: boolean; } diff --git a/packages/webpack/src/generators/init/schema.json b/packages/webpack/src/generators/init/schema.json index 453ac44aee420..1df1db63d9392 100644 --- a/packages/webpack/src/generators/init/schema.json +++ b/packages/webpack/src/generators/init/schema.json @@ -6,6 +6,12 @@ "description": "Init Webpack Plugin.", "type": "object", "properties": { + "uiFramework": { + "type": "string", + "description": "UI Framework to use for Vite.", + "enum": ["react", "none"], + "x-prompt": "What UI framework plugin should Webpack use?" + }, "compiler": { "type": "string", "enum": ["babel", "swc", "tsc"], diff --git a/packages/webpack/src/utils/versions.ts b/packages/webpack/src/utils/versions.ts index c37ad2fb287e6..912e1b9c39ce4 100644 --- a/packages/webpack/src/utils/versions.ts +++ b/packages/webpack/src/utils/versions.ts @@ -3,3 +3,10 @@ export const nxVersion = require('../../package.json').version; export const swcLoaderVersion = '0.1.15'; export const swcHelpersVersion = '~0.4.11'; export const tsLibVersion = '^2.3.0'; + +// React apps +export const reactRefreshWebpackPluginVersion = '^0.5.7'; +export const tsQueryVersion = '4.1.1'; +export const svgrWebpackVersion = '^6.1.2'; +export const reactRefreshVersion = '^0.10.0'; +export const urlLoaderVersion = '^4.1.1'; diff --git a/packages/workspace/project.json b/packages/workspace/project.json index a0c2b74914120..dce029b8def70 100644 --- a/packages/workspace/project.json +++ b/packages/workspace/project.json @@ -109,9 +109,6 @@ { "command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/devkit" }, - { - "command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/jest" - }, { "command": "node ./scripts/add-dependency-to-build.js workspace @nrwl/linter" } diff --git a/packages/workspace/src/generators/library/library.ts b/packages/workspace/src/generators/library/library.ts index 1b4cd3e1fdffc..89197f459f745 100644 --- a/packages/workspace/src/generators/library/library.ts +++ b/packages/workspace/src/generators/library/library.ts @@ -1,19 +1,20 @@ import { - Tree, - convertNxGenerator, - names, - offsetFromRoot, - generateFiles, - toJS, - getWorkspaceLayout, + addDependenciesToPackageJson, addProjectConfiguration, + convertNxGenerator, + ensurePackage, + extractLayoutDirectory, formatFiles, - updateJson, + generateFiles, GeneratorCallback, + getWorkspaceLayout, joinPathFragments, + names, + offsetFromRoot, ProjectConfiguration, - addDependenciesToPackageJson, - extractLayoutDirectory, + toJS, + Tree, + updateJson, } from '@nrwl/devkit'; import { getImportPath } from 'nx/src/utils/path'; import { join } from 'path'; @@ -25,11 +26,6 @@ import { import { nxVersion } from '../../utils/versions'; import { Schema } from './schema'; -// nx-ignore-next-line -const { jestProjectGenerator } = require('@nrwl/jest'); -// nx-ignore-next-line -const { lintProjectGenerator, Linter } = require('@nrwl/linter'); - export interface NormalizedSchema extends Schema { name: string; fileName: string; @@ -74,10 +70,12 @@ function addProject(tree: Tree, options: NormalizedSchema) { ); } -export function addLint( +export async function addLint( tree: Tree, options: NormalizedSchema ): Promise { + await ensurePackage(tree, '@nrwl/linter', nxVersion); + const { lintProjectGenerator } = require('@nrwl/linter'); return lintProjectGenerator(tree, { project: options.name, linter: options.linter, @@ -178,6 +176,8 @@ async function addJest( tree: Tree, options: NormalizedSchema ): Promise { + await ensurePackage(tree, '@nrwl/jest', nxVersion); + const { jestProjectGenerator } = require('@nrwl/jest'); return await jestProjectGenerator(tree, { ...options, project: options.name, @@ -232,7 +232,7 @@ function normalizeOptions(tree: Tree, options: Schema): NormalizedSchema { } if (!options.linter) { - options.linter = Linter.EsLint; + options.linter = 'eslint'; } const projectName = projectDirectory.replace(new RegExp('/', 'g'), '-'); diff --git a/scripts/depcheck/missing.ts b/scripts/depcheck/missing.ts index df2269801a7b1..24a19b46ec7b3 100644 --- a/scripts/depcheck/missing.ts +++ b/scripts/depcheck/missing.ts @@ -3,7 +3,21 @@ import { join } from 'path'; // Ignore packages that are defined here per package const IGNORE_MATCHES_IN_PACKAGE = { - '*': ['nx', '@nrwl/cli', '@nrwl/workspace', 'prettier', 'typescript', 'rxjs'], + '*': [ + 'nx', + 'prettier', + 'typescript', + 'rxjs', + '@nrwl/cli', + '@nrwl/workspace', + // These are installed as needed and should not be added to package.json + '@nrwl/cypress', + '@nrwl/jest', + '@nrwl/rollup', + '@nrwl/storybook', + '@nrwl/vite', + '@nrwl/webpack', + ], angular: [ '@angular-devkit/architect', '@angular-devkit/build-angular', @@ -68,26 +82,30 @@ const IGNORE_MATCHES_IN_PACKAGE = { 'webpack', ], react: [ - 'babel-plugin-emotion', - 'babel-plugin-styled-components', - 'rollup', - 'webpack', + // These are brought in by the webpack, rollup, or vite packages via init generators. + '@babel/preset-react', + '@module-federation/node', + '@phenomnomnominal/tsquery', + '@pmmmwh/react-refresh-webpack-plugin', + '@svgr/webpack', '@swc/jest', 'babel-jest', - '@angular-devkit/core', - '@angular-devkit/schematics', - // TODO(caleb): remove when refactoring plugin to use @nrwl/web - // webpack plugins for cypress component testing dev server 'babel-loader', + 'babel-plugin-emotion', + 'babel-plugin-styled-components', 'css-loader', 'less-loader', + 'react-refresh', + 'rollup', 'sass', 'sass-loader', 'style-loader', 'stylus-loader', 'swc-loader', 'tsconfig-paths-webpack-plugin', - '@module-federation/node', + 'url-loader', + 'webpack', + 'webpack-merge', ], rollup: ['@swc/core'], storybook: [