From a01ea8ce25d0b95e90de59da941b132ef62a5f38 Mon Sep 17 00:00:00 2001 From: Jason Jean Date: Thu, 8 Apr 2021 12:38:49 -0400 Subject: [PATCH] docs(devkit): initial project graph plugin guide (#5281) --- docs/map.json | 17 ++++- .../shared/workspace/project-graph-plugins.md | 71 +++++++++++++++++++ .../workspace/structure/dependency-graph.md | 2 +- .../devkit/src/project-graph/interfaces.ts | 57 +++++++++++++++ 4 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 docs/shared/workspace/project-graph-plugins.md diff --git a/docs/map.json b/docs/map.json index f96ae14dcf..d89dc4ace0 100644 --- a/docs/map.json +++ b/docs/map.json @@ -937,9 +937,14 @@ "file": "shared/monorepo-tags" }, { - "name": "Dependency Graph", + "name": "Project Graph", "id": "dependency-graph", "file": "shared/workspace/structure/dependency-graph" + }, + { + "name": "Extending the Project Graph", + "id": "project-graph-plugins", + "file": "shared/workspace/project-graph-plugins" } ] }, @@ -1998,6 +2003,11 @@ "name": "Dependency Graph", "id": "dependency-graph", "file": "shared/workspace/structure/dependency-graph" + }, + { + "name": "Extending the Project Graph", + "id": "project-graph-plugins", + "file": "shared/workspace/project-graph-plugins" } ] }, @@ -3002,6 +3012,11 @@ "name": "Dependency Graph", "id": "dependency-graph", "file": "shared/workspace/structure/dependency-graph" + }, + { + "name": "Extending the Project Graph", + "id": "project-graph-plugins", + "file": "shared/workspace/project-graph-plugins" } ] }, diff --git a/docs/shared/workspace/project-graph-plugins.md b/docs/shared/workspace/project-graph-plugins.md new file mode 100644 index 0000000000..2f4a2c319e --- /dev/null +++ b/docs/shared/workspace/project-graph-plugins.md @@ -0,0 +1,71 @@ +# Extending the Project Graph of Nx + +> This API is experimental and might change. + +Nx views the workspace as a graph of projects that depend on one another. It's able to infer most projects and dependencies automatically. Currently, this works best within the Javascript ecosystem but it can be extended to other languages and technologies as well. + +## Defining Plugins to be used in a workspace + +In `nx.json`, add an array of plugins: + +```json +{ + ..., + "plugins": [ + "awesome-plugin" + ] +} +``` + +These plugins are used when running targets, linting, and sometimes when generating code. + +## Implementing a Project Graph Processor + +Project Graph Plugins are chained together to produce the final project graph. Each plugin may have a Project Graph Processor which iterates upon the project graph. Plugins should export a function named `processProjectGraph` that handles updating the project graph with new nodes and edges. This function receives two things: + +- A `ProjectGraph` + - Nodes in the project graph are the different projects currently in the graph. + - Edges in the project graph are dependencies between different projects in the graph. +- Some context is also passed into the function to use when processing the project graph. The context contains: + - The `workspace` which contains both configuration as well as the different projects. + - A `fileMap` which has a map of files by projects + +The `processProjectGraph` function should return an updated `ProjectGraph`. This is most easily done using the `ProjectGraphBuilder` to iteratively add edges and nodes to the graph: + +```typescript +import { + ProjectGraph, + ProjectGraphBuilder, + ProjectGraphProcessorContext, + DependencyType, +} from '@nrwl/devkit'; + +export function processProjectGraph( + graph: ProjectGraph, + context: ProjectGraphProcessorContext +): ProjectGraph { + const builder = new ProjectGraphBuilder(graph); + + // Add a new node + builder.addNode({ + name: 'new-project', + type: 'lib', + data: { + files: [], + }, + }); + + // Add a new edge + builder.addDependency( + DependencyType.static, + 'existing-project', + 'new-project' + ); + + return builder.getProjectGraph(); +} +``` + +## Visualizing the Project Graph + +You can then visualize the project graph as described [here](dependency-graph). diff --git a/docs/shared/workspace/structure/dependency-graph.md b/docs/shared/workspace/structure/dependency-graph.md index 2ab4a391c4..ab8e70a1ce 100644 --- a/docs/shared/workspace/structure/dependency-graph.md +++ b/docs/shared/workspace/structure/dependency-graph.md @@ -4,7 +4,7 @@ To be able to support the monorepo-style development, the tools must know how di -## How the Dependency Graph is Built +## How the Project Graph is Built Nx creates a graph of all the dependencies between projects in your workspace using two sources of information: diff --git a/packages/devkit/src/project-graph/interfaces.ts b/packages/devkit/src/project-graph/interfaces.ts index c47dbe8575..37350dfbae 100644 --- a/packages/devkit/src/project-graph/interfaces.ts +++ b/packages/devkit/src/project-graph/interfaces.ts @@ -1,15 +1,24 @@ import { TargetConfiguration, Workspace } from '@nrwl/tao/src/shared/workspace'; +/** + * Some metadata about a file + */ export interface FileData { file: string; hash: string; ext: string; } +/** + * A list of files separated by the project they belong to + */ export interface ProjectFileMap { [projectName: string]: FileData[]; } +/** + * A Graph of projects in the workspace and dependencies between them + */ export interface ProjectGraph { nodes: Record; dependencies: Record; @@ -18,38 +27,86 @@ export interface ProjectGraph { allWorkspaceFiles?: FileData[]; } +/** + * Type of dependency between projects + */ export enum DependencyType { + /** + * Static dependencies are tied to the loading of the module + */ static = 'static', + /** + * Dynamic dependencies are brought in by the module at run time + */ dynamic = 'dynamic', + /** + * Implicit dependencies are inferred + */ implicit = 'implicit', } +/** + * A node describing a project in a workspace + */ export interface ProjectGraphNode { type: string; name: string; + /** + * Additional metadata about a project + */ data: T & { + /** + * The project's root directory + */ root?: string; + /** + * Targets associated to the project + */ targets?: { [targetName: string]: TargetConfiguration }; + /** + * Files associated to the project + */ files: FileData[]; }; } +/** + * A dependency between two projects + */ export interface ProjectGraphDependency { type: DependencyType | string; + /** + * The project being imported by the other + */ target: string; + /** + * The project importing the other + */ source: string; } +/** + * Additional information to be used to process a project graph + */ export interface ProjectGraphProcessorContext { + /** + * Workspace information such as projects and configuration + */ workspace: Workspace; fileMap: ProjectFileMap; } +/** + * A function that produces an updated ProjectGraph + */ export type ProjectGraphProcessor = ( currentGraph: ProjectGraph, context: ProjectGraphProcessorContext ) => ProjectGraph; +/** + * A plugin for Nx + */ export interface NxPlugin { processProjectGraph: ProjectGraphProcessor; }