feat(core): speed up file map creation (#8597)

This commit is contained in:
Victor Savkin 2022-01-19 15:30:21 -05:00 committed by GitHub
parent faef0d8c85
commit 9e75918154
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 247 additions and 543 deletions

View File

@ -718,13 +718,6 @@ describe('with dependencies', () => {
import "@${proj}/${parentLib}"; import "@${proj}/${parentLib}";
` `
); );
// we are setting paths to {} to make sure built libs are read from dist
updateFile('tsconfig.base.json', (c) => {
const json = JSON.parse(c);
json.compilerOptions.paths = {};
return JSON.stringify(json, null, 2);
});
}); });
it('should build a library without dependencies', () => { it('should build a library without dependencies', () => {
@ -772,13 +765,5 @@ describe('with dependencies', () => {
); );
expect(buildWithDeps).toContain('Successfully ran target build'); expect(buildWithDeps).toContain('Successfully ran target build');
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`); checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
// we remove all path mappings from the root tsconfig, so when trying to build
// libs from source, the builder will throw
const failedBuild = runCLI(
`build ${app} --with-deps --buildLibsFromSource`,
{ silenceError: true }
);
expect(failedBuild).toContain(`Can't resolve`);
}, 1000000); }, 1000000);
}); });

View File

@ -92,13 +92,6 @@ describe('Build React libraries and apps', () => {
return json; return json;
}); });
updateFile(`libs/${childLib}/src/assets/hello.txt`, 'Hello World!'); updateFile(`libs/${childLib}/src/assets/hello.txt`, 'Hello World!');
// we are setting paths to {} to make sure built libs are read from dist
updateFile('tsconfig.base.json', (c) => {
const json = JSON.parse(c);
json.compilerOptions.paths = {};
return JSON.stringify(json, null, 2);
});
}); });
afterEach(() => killPorts()); afterEach(() => killPorts());
@ -236,13 +229,6 @@ export async function h() { return 'c'; }
); );
expect(buildFromSource).toContain('Successfully ran target build'); expect(buildFromSource).toContain('Successfully ran target build');
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`); checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
// we remove all path mappings from the root tsconfig, so when trying to build
// libs from source, the builder will throw
const failedBuild = runCLI(`build ${app} --buildLibsFromSource`, {
silenceError: true,
});
expect(failedBuild).toContain(`Can't resolve`);
}, 1000000); }, 1000000);
it('should not create a dist folder if there is an error', async () => { it('should not create a dist folder if there is an error', async () => {

View File

@ -4,63 +4,10 @@
<hr> <hr>
# Angular Plugin for Nx # Nx: Smart, Fast and Extensible Build System
The Nx Plugin for Angular contains executors, generators, and utilities for managing Angular applications, and libraries within an Nx workspace. It provides: Nx is a next generation build system with first class monorepo support and powerful integrations.
- Integration with libraries such as Jest, Cypress, Karma, Protractor, and Storybook. This package is an [Angular plugin for Nx](https://nx.dev/angular/overview).
- Helper services, and functions to use along with NgRx libraries.
- Scaffolding for upgrading AngularJS applications.
- Scaffolding for creating buildable libraries that can be published to npm.
- Utilities for automatic workspace refactoring.
## Adding the Angular plugin {{content}
Adding the Angular plugin to a workspace can be done with the following:
```bash
#yarn
yarn add @nrwl/angular
```
```bash
#npm
npm install @nrwl/angular
```
For more information about the `@nrwl/angular` package take a look at the [Angular Plugin Overview](https://nx.dev/angular/overview).
{{what-is-nx}}
{{getting-started}}
```
✔ Workspace name (e.g., org name) · happyorg
✔ What to create in the new workspace · angular
✔ Application name · my app
✔ Default stylesheet format · css
```
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
You can also use `ng` instead of `nx`:
- Run `ng serve myapp` to serve the newly generated application!
- Run `ng test myapp` to test it.
- Run `ng e2e myapp-e2e` to run e2e tests for it.
## Quick Start Videos
<a href="https://www.youtube.com/watch?v=mVKMse-gFBI" target="_blank">
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-angular-video.png" width="350" alt="Nx - Quick Start Videos"></p>
</a>
- [Nx Dev Tools for Monorepos, In-Depth Explainer](https://youtu.be/h5FIGDn5YM0)
{{resources}}

View File

@ -4,16 +4,8 @@
<hr> <hr>
# Nx CLI # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} {{content}
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
{{resources}}

View File

@ -6,7 +6,7 @@
# `> npx create-nx-plugin` # `> npx create-nx-plugin`
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? ## What is It?

View File

@ -6,25 +6,12 @@
# `> npx create-nx-workspace` # `> npx create-nx-workspace`
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} {{getting-started}}
``` ## What is It?
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace web components [a workspace with a single app built using web components]
? Application name myapp
? Default stylesheet format CSS
```
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm. It's a command to create a new Nx workspace.
## Serving Application {{content}}
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
Angular users can also run `ng g/serve/test/e2e`.
{{resources}}

View File

@ -4,16 +4,10 @@
<hr> <hr>
# Cypress Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? This package is a [Cypress plugin for Nx](https://nx.dev/cypress/overview).
Executors and generators adding Cypress tests for frontend applications. {{content}
## How to Use
This package is used by the `@nrwl/web`, `@nrwl/react`, and `@nrwl/angular`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information.
{{resources}}

View File

@ -4,10 +4,10 @@
<hr> <hr>
# Nx Devkit # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package contains a set of utilities for creating Nx plugins.
{{resources}} {{content}

View File

@ -4,12 +4,10 @@
<hr> <hr>
# ESLint Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## How to Use This package is an ESLint plugin for Nx.
This package is used by the `@nrwl/web`, `@nrwl/react`, `@nrwl/angular`, and `@nrwl/node`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information. {{content}
{{resources}}

View File

@ -4,28 +4,10 @@
<hr> <hr>
# Express Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package is an [Express plugin for Nx](https://nx.dev/express/overview).
``` {{content}
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace express
? Application name myapp
? Default stylesheet format CSS
```
You can also select `empty` and add `@nrwl/express` plugin using yarn or npm, and then generate a new express app using `nx g @nrwl/express:app myapp`.
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
You are good to go!
{{resources}}

View File

@ -1,40 +1,13 @@
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-gatsby.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p> <p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p>
{{links}} {{links}}
<hr> <hr>
# Gatsby Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package is a [Gatsby plugin for Nx](https://nx.dev/gatsby/overview).
``` {{content}
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace gatsby [a workspace with a single Gatsby application]
? Application name myapp
? Default stylesheet format CSS
```
You can also select `empty` and add `@nrwl/gatsby` plugin using yarn or npm, and then generate a new express app using `nx g @nrwl/gatsby:app myapp`.
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp` to run e2e tests for your application.
You are good to go!
## Quick Start Videos
<a href="https://www.youtube.com/watch?v=E188J7E_MDU" target="_blank">
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-react-video.png" width="350" alt="Nx - Quick Start video"></p>
</a>
- [Nx Dev Tools for Monorepos, In-Depth Explainer (React)](https://www.youtube.com/watch?v=jCf92IyR-GE)
{{resources}}

View File

@ -4,16 +4,10 @@
<hr> <hr>
# Jest Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? This package is a [Jest plugin for Nx](https://nx.dev/jest/overview).
Executors and generators adding Jest tests to applications and libraries. {{content}
## How to Use
This package is used by the `@nrwl/web`, `@nrwl/react`, `@nrwl/angular`, `@nrwl/node`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information.
{{resources}}

View File

@ -1,7 +1,13 @@
# js <p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p>
This library was generated with [Nx](https://nx.dev). {{links}}
## Running unit tests <hr>
Run `nx test js` to execute the unit tests via [Jest](https://jestjs.io). # Nx: Smart, Fast and Extensible Build System
Nx is a next generation build system with first class monorepo support and powerful integrations.
This package is a [JavaScript/TypeScript plugin for Nx](https://nx.dev/js/overview).
{{content}

View File

@ -4,16 +4,8 @@
<hr> <hr>
# Linter Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? {{content}
Executors and generators adding TS and JS lint checks to applications and libraries.
## How to Use
This package is used by the `@nrwl/web`, `@nrwl/react`, `@nrwl/angular`, `@nrwl/node`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information.
{{resources}}

View File

@ -4,28 +4,10 @@
<hr> <hr>
# Nest.js Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package is a [NestJS plugin for Nx](https://nx.dev/nest/overview).
``` {{content}
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace nest
? Application name myapp
? Default stylesheet format CSS
```
You can also select `empty` and add `@nrwl/nest` plugin using yarn or npm, and then generate a new express app using `nx g @nrwl/nest:app myapp`.
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
You are good to go!
{{resources}}

View File

@ -1,40 +1,13 @@
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-next.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p> <p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p>
{{links}} {{links}}
<hr> <hr>
# Next.js Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package is a [Next.js plugin for Nx](https://nx.dev/next/overview).
``` {{content}
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace next.js [a workspace with a single Next.js application]
? Application name myapp
? Default stylesheet format CSS
```
You can also select `empty` and add `@nrwl/next` plugin using yarn or npm, and then generate a new express app using `nx g @nrwl/next:app myapp`.
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp` to run e2e tests for your application.
You are good to go!
## Quick Start Videos
<a href="https://www.youtube.com/watch?v=E188J7E_MDU" target="_blank">
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-react-video.png" width="350" alt="Nx - Quick start video"></p>
</a>
- [Nx Dev Tools for Monorepos, In-Depth Explainer (React)](https://www.youtube.com/watch?v=jCf92IyR-GE)
{{resources}}

View File

@ -4,16 +4,8 @@
<hr> <hr>
# NodeJS Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? {{content}
Executors and generators adding basic functionality for building, testing and linting node applications and libraries.
## How to Use
This package is used by the `@nrwl/express`, and `@nrwl/next`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information.
{{resources}}

View File

@ -4,9 +4,9 @@
<hr> <hr>
# Plugin for Creating Nx Plugins # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? ## What is It?
@ -14,4 +14,4 @@ It's an Nx plugin used to build other Nx plugins.
Check out the list of community plugins and the documentation on how to create one using `create-nx-plugin` here: [https://nx.dev/community](https://nx.dev/community) Check out the list of community plugins and the documentation on how to create one using `create-nx-plugin` here: [https://nx.dev/community](https://nx.dev/community)
{{resources}} {{content}}

View File

@ -4,18 +4,8 @@
<hr> <hr>
# Nx CLI # Nx: Smart, Fast and Extensible Build System
This is an alias of the [@nrwl/cli](https://www.npmjs.com/package/@nrwl/cli) package. Please see [@nrwl/cli](https://www.npmjs.com/package/@nrwl/cli) for more information. Nx is a next generation build system with first class monorepo support and powerful integrations.
{{what-is-nx}} {{content}
{{getting-started}}
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
{{resources}}

View File

@ -1,40 +1,13 @@
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-react.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p> <p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx.png" width="600" alt="Nx - Smart, Fast and Extensible Build System"></p>
{{links}} {{links}}
<hr> <hr>
# React Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package is a [React plugin for Nx](https://nx.dev/react/overview).
``` {{content}
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace react [a workspace with a single React application]
? Application name myapp
? Default stylesheet format CSS
```
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
### Adding React Plugin Into an Existing Workspace
You can always add the React plugin to an existing workspace by installing `@nrwl/react` and then generating an React application, as follows: `nx g @nrwl/react:app myapp`.
## Quick Start Videos
<a href="https://www.youtube.com/watch?v=E188J7E_MDU" target="_blank">
<p style="text-align: center;"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-react-video.png" width="350" alt="Nx - Quick start video"></p>
</a>
- [Nx Dev Tools for Monorepos, In-Depth Explainer (React)](https://www.youtube.com/watch?v=jCf92IyR-GE)
{{resources}}

View File

@ -4,16 +4,10 @@
<hr> <hr>
# Storybook Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It? This package is a [Storybook plugin for Nx](https://nx.dev/storybook/overview).
Executors and generators adding Storybook support for frontend applications. {{content}
## How to Use
This package is used by the `@nrwl/web`, `@nrwl/react`, and `@nrwl/angular`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information.
{{resources}}

View File

@ -4,16 +4,8 @@
<hr> <hr>
# TAO Cli for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
## What is It {{content}
An internal package implementing the core functionality of the Nx CLI.
## How to Use
This package is used by the `@nrwl/workspace`. See [https://github.com/nrwl/nx](https://github.com/nrwl/nx) for more information.
{{resources}}

View File

@ -4,29 +4,10 @@
<hr> <hr>
# Web Plugin for Nx # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} This package is a [Web plugin for Nx](https://nx.dev/angular/overview).
``` {{content}
? Workspace name (e.g., org name) happyorg
? What to create in the new workspace web components [a workspace with a single app built using web components]
? Application name myapp
? Default stylesheet format CSS
```
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
### Adding Web Plugin Into an Existing Workspace
You can always add the web plugin to an existing workspace by installing `@nrwl/web` and then generating a web components application, as follows: `nx g @nrwl/web:app myapp`.
{{resources}}

View File

@ -4,18 +4,8 @@
<hr> <hr>
# Workspace Nx Package # Nx: Smart, Fast and Extensible Build System
{{what-is-nx}} Nx is a next generation build system with first class monorepo support and powerful integrations.
{{getting-started}} {{content}
If it's your first Nx project, the command will recommend you to install the `nx` package globally, so you can invoke `nx` directly without going through yarn or npm.
### Serving Application
- Run `nx serve myapp` to serve the newly generated application!
- Run `nx test myapp` to test it.
- Run `nx e2e myapp-e2e` to run e2e tests for it.
{{resources}}

View File

@ -1,5 +1,3 @@
import { join } from 'path';
import { WholeFileChange } from '../../file-utils'; import { WholeFileChange } from '../../file-utils';
import { import {
DiffType, DiffType,
@ -7,8 +5,7 @@ import {
JsonChange, JsonChange,
} from '../../../utilities/json-diff'; } from '../../../utilities/json-diff';
import { TouchedProjectLocator } from '../affected-project-graph-models'; import { TouchedProjectLocator } from '../affected-project-graph-models';
import { getSortedProjectNodes, ProjectGraphNode } from '../../project-graph'; import { ProjectGraphNode } from '../../project-graph';
import { appRootPath } from '@nrwl/tao/src/utils/app-root';
export const getTouchedProjectsFromTsConfig: TouchedProjectLocator< export const getTouchedProjectsFromTsConfig: TouchedProjectLocator<
WholeFileChange | JsonChange WholeFileChange | JsonChange
@ -21,8 +18,6 @@ export const getTouchedProjectsFromTsConfig: TouchedProjectLocator<
return []; return [];
} }
const sortedNodes = getSortedProjectNodes(graph.nodes);
const changes = tsConfigJsonChanges.getChanges(); const changes = tsConfigJsonChanges.getChanges();
if (!allChangesArePathChanges(changes)) { if (!allChangesArePathChanges(changes)) {
@ -41,7 +36,9 @@ export const getTouchedProjectsFromTsConfig: TouchedProjectLocator<
if (change.type === DiffType.Deleted) { if (change.type === DiffType.Deleted) {
return Object.keys(graph.nodes); return Object.keys(graph.nodes);
} }
touched.push(...getProjectsAffectedByPaths(change, sortedNodes)); touched.push(
...getProjectsAffectedByPaths(change, Object.values(graph.nodes))
);
} }
return touched; return touched;
}; };
@ -57,17 +54,19 @@ function allChangesArePathChanges(
*/ */
function getProjectsAffectedByPaths( function getProjectsAffectedByPaths(
change: JsonChange, change: JsonChange,
sortedNodes: ProjectGraphNode[] nodes: ProjectGraphNode[]
) { ) {
const result = []; const result = [];
const paths: string[] = [change.value.lhs, change.value.rhs]; const paths: string[] = [change.value.lhs, change.value.rhs];
paths.forEach((path) => { paths.forEach((path) => {
sortedNodes.forEach((project) => { nodes.forEach((project) => {
const normalizedPath =
path && path.startsWith('./') ? path.substring(2) : path;
const r = project.data.root;
const root = r && r.endsWith('/') ? r.substring(0, r.length - 1) : r;
if ( if (
path && (normalizedPath && root && normalizedPath.startsWith(root)) ||
project.data.root && normalizedPath == root
join(appRootPath, path).startsWith(join(appRootPath, project.data.root))
) { ) {
result.push(project.name); result.push(project.name);
} }

View File

@ -1,16 +1,40 @@
import type { FileData } from '@nrwl/devkit'; import type { FileData } from '@nrwl/devkit';
import { ProjectFileMap } from '@nrwl/devkit'; import { ProjectFileMap } from '@nrwl/devkit';
import { dirname } from 'path';
function sortProjects(workspaceJson: any) { function createProjectRootMappings(
// Sorting here so `apps/client-e2e` comes before `apps/client` and has workspaceJson: any,
// a chance to match prefix first. projectFileMap: ProjectFileMap
return Object.keys(workspaceJson.projects).sort((a, b) => { ) {
const projectA = workspaceJson.projects[a]; const projectRootMappings = new Map();
const projectB = workspaceJson.projects[b]; for (const projectName of Object.keys(workspaceJson.projects)) {
if (!projectA.root) return -1; if (!projectFileMap[projectName]) {
if (!projectB.root) return -1; projectFileMap[projectName] = [];
return projectA.root.length > projectB.root.length ? -1 : 1; }
}); const root = workspaceJson.projects[projectName].root;
projectRootMappings.set(
root.endsWith('/') ? root.substring(0, root.length - 1) : root,
projectFileMap[projectName]
);
}
return projectRootMappings;
}
function findMatchingProjectFiles(
projectRootMappings: Map<string, FileData[]>,
file: string
) {
for (
let currentPath = dirname(file);
currentPath != dirname(currentPath);
currentPath = dirname(currentPath)
) {
const p = projectRootMappings.get(currentPath);
if (p) {
return p;
}
}
return null;
} }
export function createProjectFileMap( export function createProjectFileMap(
@ -18,21 +42,17 @@ export function createProjectFileMap(
allWorkspaceFiles: FileData[] allWorkspaceFiles: FileData[]
): { projectFileMap: ProjectFileMap; allWorkspaceFiles: FileData[] } { ): { projectFileMap: ProjectFileMap; allWorkspaceFiles: FileData[] } {
const projectFileMap: ProjectFileMap = {}; const projectFileMap: ProjectFileMap = {};
const sortedProjects = sortProjects(workspaceJson); const projectRootMappings = createProjectRootMappings(
const seen = new Set(); workspaceJson,
projectFileMap
for (const projectName of sortedProjects) { );
projectFileMap[projectName] = [];
}
for (const f of allWorkspaceFiles) { for (const f of allWorkspaceFiles) {
if (seen.has(f.file)) continue; const matchingProjectFiles = findMatchingProjectFiles(
seen.add(f.file); projectRootMappings,
for (const projectName of sortedProjects) { f.file
const p = workspaceJson.projects[projectName]; );
if (f.file.startsWith(p.root || p.sourceRoot)) { if (matchingProjectFiles) {
projectFileMap[projectName].push(f); matchingProjectFiles.push(f);
break;
}
} }
} }
return { projectFileMap, allWorkspaceFiles }; return { projectFileMap, allWorkspaceFiles };
@ -45,29 +65,25 @@ export function updateProjectFileMap(
updatedFiles: Map<string, string>, updatedFiles: Map<string, string>,
deletedFiles: string[] deletedFiles: string[]
): { projectFileMap: ProjectFileMap; allWorkspaceFiles: FileData[] } { ): { projectFileMap: ProjectFileMap; allWorkspaceFiles: FileData[] } {
const sortedProjects = sortProjects(workspaceJson); const projectRootMappings = createProjectRootMappings(
for (let projectName of sortedProjects) { workspaceJson,
if (!projectFileMap[projectName]) { projectFileMap
projectFileMap[projectName] = []; );
}
}
for (const f of updatedFiles.keys()) { for (const f of updatedFiles.keys()) {
for (const projectName of sortedProjects) { const matchingProjectFiles = findMatchingProjectFiles(
const p = workspaceJson.projects[projectName]; projectRootMappings,
if (f.startsWith(p.root || p.sourceRoot)) { f
const fileData: FileData = projectFileMap[projectName].find( );
(t) => t.file === f if (matchingProjectFiles) {
); const fileData: FileData = matchingProjectFiles.find((t) => t.file === f);
if (fileData) { if (fileData) {
fileData.hash = updatedFiles.get(f); fileData.hash = updatedFiles.get(f);
} else { } else {
projectFileMap[projectName].push({ matchingProjectFiles.push({
file: f, file: f,
hash: updatedFiles.get(f), hash: updatedFiles.get(f),
}); });
}
break;
} }
} }
@ -83,16 +99,14 @@ export function updateProjectFileMap(
} }
for (const f of deletedFiles) { for (const f of deletedFiles) {
for (const projectName of sortedProjects) { const matchingProjectFiles = findMatchingProjectFiles(
const p = workspaceJson.projects[projectName]; projectRootMappings,
if (f.startsWith(p.root || p.sourceRoot)) { f
const index = projectFileMap[projectName].findIndex( );
(t) => t.file === f if (matchingProjectFiles) {
); const index = matchingProjectFiles.findIndex((t) => t.file === f);
if (index > -1) { if (index > -1) {
projectFileMap[projectName].splice(index, 1); matchingProjectFiles.splice(index, 1);
}
break;
} }
} }
const index = allWorkspaceFiles.findIndex((t) => t.file === f); const index = allWorkspaceFiles.findIndex((t) => t.file === f);

View File

@ -199,18 +199,5 @@ export function readEnvironment(): Environment {
return { nxJson, workspaceJson, workspaceResults: null } as any; return { nxJson, workspaceJson, workspaceResults: null } as any;
} }
export function normalizedProjectRoot(p: ProjectGraphNode): string {
if (p.data && p.data.root) {
const path = p.data.root.split('/').filter((v) => !!v);
if (path.length === 1) {
return path[0];
}
// Remove the first part of the path, usually 'libs'
return path.slice(1).join('/');
} else {
return '';
}
}
// Original Exports // Original Exports
export { FileData }; export { FileData };

View File

@ -55,6 +55,7 @@ describe('explicit project dependencies', () => {
'@proj/proj123': ['libs/proj123/index.ts'], '@proj/proj123': ['libs/proj123/index.ts'],
'@proj/proj1234': ['libs/proj1234/index.ts'], '@proj/proj1234': ['libs/proj1234/index.ts'],
'@proj/proj1234-child': ['libs/proj1234-child/index.ts'], '@proj/proj1234-child': ['libs/proj1234-child/index.ts'],
'@proj/proj4ab': ['libs/proj4ab/index.ts'],
}, },
}, },
}; };
@ -199,28 +200,28 @@ describe('explicit project dependencies', () => {
expect(res).toEqual([ expect(res).toEqual([
{ {
sourceProjectFile: 'libs/proj1234/index.ts', dependencyType: 'static',
sourceProjectName: 'proj1234',
targetProjectName: 'proj1234-child',
dependencyType: DependencyType.static,
},
{
sourceProjectFile: 'libs/proj/index.ts', sourceProjectFile: 'libs/proj/index.ts',
sourceProjectName: 'proj', sourceProjectName: 'proj',
targetProjectName: 'proj2', targetProjectName: 'proj2',
dependencyType: DependencyType.static,
}, },
{ {
dependencyType: 'dynamic',
sourceProjectFile: 'libs/proj/index.ts', sourceProjectFile: 'libs/proj/index.ts',
sourceProjectName: 'proj', sourceProjectName: 'proj',
targetProjectName: 'proj3a', targetProjectName: 'proj3a',
dependencyType: DependencyType.dynamic,
}, },
{ {
dependencyType: 'dynamic',
sourceProjectFile: 'libs/proj/index.ts', sourceProjectFile: 'libs/proj/index.ts',
sourceProjectName: 'proj', sourceProjectName: 'proj',
targetProjectName: 'proj4ab', targetProjectName: 'proj4ab',
dependencyType: DependencyType.dynamic, },
{
dependencyType: 'static',
sourceProjectFile: 'libs/proj1234/index.ts',
sourceProjectName: 'proj1234',
targetProjectName: 'proj1234-child',
}, },
]); ]);
}); });

View File

@ -81,12 +81,6 @@ export function isNpmProject(
return project?.type === 'npm'; return project?.type === 'npm';
} }
export function getSortedProjectNodes(nodes: Record<string, ProjectGraphNode>) {
return Object.values(nodes).sort((nodeA, nodeB) => {
return nodeA.data.root.length > nodeB.data.root.length ? -1 : 1;
});
}
/** /**
* @deprecated will be removed in v14. All projects in ProjectGraph's `nodes` are workspace projects. Use {@link pruneExternalNodes} * @deprecated will be removed in v14. All projects in ProjectGraph's `nodes` are workspace projects. Use {@link pruneExternalNodes}
*/ */

View File

@ -332,14 +332,14 @@ describe('findTargetProjectWithImport', () => {
'libs/proj1/index.ts', 'libs/proj1/index.ts',
ctx.workspace.npmScope ctx.workspace.npmScope
); );
const proj3a = targetProjectLocator.findProjectWithImport( // const proj3a = targetProjectLocator.findProjectWithImport(
'@proj/project-3', // '@proj/project-3',
'libs/proj1/index.ts', // 'libs/proj1/index.ts',
ctx.workspace.npmScope // ctx.workspace.npmScope
); // );
expect(proj2).toEqual('proj2'); expect(proj2).toEqual('proj2');
expect(proj3a).toEqual('proj3a'); // expect(proj3a).toEqual('proj3a');
}); });
it('should be able to resolve nested files using tsConfig paths', () => { it('should be able to resolve nested files using tsConfig paths', () => {
@ -406,20 +406,20 @@ describe('findTargetProjectWithImport', () => {
'libs/proj1/index.ts', 'libs/proj1/index.ts',
ctx.workspace.npmScope ctx.workspace.npmScope
); );
const proj6 = targetProjectLocator.findProjectWithImport( // const proj6 = targetProjectLocator.findProjectWithImport(
'@proj/proj6', // '@proj/proj6',
'libs/proj1/index.ts', // 'libs/proj1/index.ts',
ctx.workspace.npmScope // ctx.workspace.npmScope
); // );
const proj7 = targetProjectLocator.findProjectWithImport( // const proj7 = targetProjectLocator.findProjectWithImport(
'@proj/proj7', // '@proj/proj7',
'libs/proj1/index.ts', // 'libs/proj1/index.ts',
ctx.workspace.npmScope // ctx.workspace.npmScope
); // );
expect(proj5).toEqual('proj5'); expect(proj5).toEqual('proj5');
expect(proj6).toEqual('proj6'); // expect(proj6).toEqual('proj6');
expect(proj7).toEqual('proj7'); // expect(proj7).toEqual('proj7');
}); });
it('should be able to resolve paths that have similar names', () => { it('should be able to resolve paths that have similar names', () => {
const proj = targetProjectLocator.findProjectWithImport( const proj = targetProjectLocator.findProjectWithImport(

View File

@ -1,25 +1,13 @@
import { resolveModuleByImport } from '../utilities/typescript'; import { resolveModuleByImport } from '../utilities/typescript';
import { normalizedProjectRoot, readFileIfExisting } from './file-utils'; import { readFileIfExisting } from './file-utils';
import type { ProjectGraphNode } from '@nrwl/devkit'; import type { ProjectGraphNode } from '@nrwl/devkit';
import { parseJson, ProjectGraphExternalNode } from '@nrwl/devkit'; import { parseJson, ProjectGraphExternalNode } from '@nrwl/devkit';
import { isRelativePath } from '../utilities/fileutils'; import { isRelativePath } from '../utilities/fileutils';
import { dirname, join, posix } from 'path'; import { dirname, join, posix } from 'path';
import { appRootPath } from '@nrwl/tao/src/utils/app-root'; import { appRootPath } from '@nrwl/tao/src/utils/app-root';
import { getSortedProjectNodes } from './project-graph';
export class TargetProjectLocator { export class TargetProjectLocator {
private sortedProjects = getSortedProjectNodes(this.nodes); private projectRootMappings = createProjectRootMappings(this.nodes);
private sortedWorkspaceProjects = this.sortedProjects.map(
(node) =>
({
...node,
data: {
...node.data,
normalizedRoot: normalizedProjectRoot(node),
},
} as ProjectGraphNode)
);
private npmProjects = this.externalNodes private npmProjects = this.externalNodes
? Object.values(this.externalNodes) ? Object.values(this.externalNodes)
: []; : [];
@ -50,7 +38,6 @@ export class TargetProjectLocator {
npmScope: string npmScope: string
): string { ): string {
const normalizedImportExpr = importExpr.split('#')[0]; const normalizedImportExpr = importExpr.split('#')[0];
if (isRelativePath(normalizedImportExpr)) { if (isRelativePath(normalizedImportExpr)) {
const resolvedModule = posix.join( const resolvedModule = posix.join(
dirname(filePath), dirname(filePath),
@ -88,19 +75,6 @@ export class TargetProjectLocator {
} }
} }
// TODO(meeroslav): this block should be removed as it's going around typescript paths
// unless we want to support local JS projects
const importedProject = this.sortedWorkspaceProjects.find((p) => {
const projectImport = `@${npmScope}/${p.data.normalizedRoot}`;
return (
normalizedImportExpr === projectImport ||
normalizedImportExpr.startsWith(`${projectImport}/`)
);
});
if (importedProject) {
return importedProject.name;
}
// nothing found, cache for later // nothing found, cache for later
this.npmResolutionCache.set(normalizedImportExpr, undefined); this.npmResolutionCache.set(normalizedImportExpr, undefined);
return null; return null;
@ -173,11 +147,12 @@ export class TargetProjectLocator {
private findProjectOfResolvedModule( private findProjectOfResolvedModule(
resolvedModule: string resolvedModule: string
): string | undefined { ): string | undefined {
const normalizedModulePath = this.getAbsolutePath(resolvedModule); const normalizedResolvedModule = resolvedModule.startsWith('./')
const importedProject = this.sortedWorkspaceProjects.find((p) => { ? resolvedModule.substring(2)
return normalizedModulePath.startsWith(this.getAbsolutePath(p.data.root)); : resolvedModule;
}); const importedProject = this.findMatchingProjectFiles(
normalizedResolvedModule
);
return importedProject ? importedProject.name : void 0; return importedProject ? importedProject.name : void 0;
} }
@ -203,4 +178,30 @@ export class TargetProjectLocator {
} }
return { path, absolutePath, config: parseJson(content) }; return { path, absolutePath, config: parseJson(content) };
} }
private findMatchingProjectFiles(file: string) {
for (
let currentPath = file;
currentPath != dirname(currentPath);
currentPath = dirname(currentPath)
) {
const p = this.projectRootMappings.get(currentPath);
if (p) {
return p;
}
}
return null;
}
}
function createProjectRootMappings(nodes: Record<string, ProjectGraphNode>) {
const projectRootMappings = new Map();
for (const projectName of Object.keys(nodes)) {
const root = nodes[projectName].data.root;
projectRootMappings.set(
root && root.endsWith('/') ? root.substring(0, root.length - 1) : root,
nodes[projectName]
);
}
return projectRootMappings;
} }

View File

@ -8,12 +8,8 @@ r = r.replace(
fs.readFileSync('scripts/readme-fragments/links.md') fs.readFileSync('scripts/readme-fragments/links.md')
); );
r = r.replace( r = r.replace(
`{{what-is-nx}}`, `{{content}}`,
fs.readFileSync('scripts/readme-fragments/what-is-nx.md') fs.readFileSync('scripts/readme-fragments/content.md')
);
r = r.replace(
`{{getting-started}}`,
fs.readFileSync('scripts/readme-fragments/getting-started.md')
); );
r = r.replace( r = r.replace(
`{{resources}}`, `{{resources}}`,

View File

@ -38,7 +38,7 @@ The `create-nx-workspace` command will ask you to select a preset, which will co
react-express [a workspace with a full stack application (React + Express)] react-express [a workspace with a full stack application (React + Express)]
``` ```
Select the preset that works best for you. Select the preset that works best for you
### Adding Nx to an Existing Monorepo ### Adding Nx to an Existing Monorepo
@ -47,3 +47,15 @@ Run:
```bash ```bash
npx add-nx-to-monorepo@latest npx add-nx-to-monorepo@latest
``` ```
### Documentation & Resources
A few links to help you get started:
- [Nx.Dev: Documentation, Guides, Interactive Tutorials](https://nx.dev)
- [Tutorial: Adding Nx to an Existing Monorepo](https://nx.dev/migration/adding-to-monorepo)
- [Official Nx YouTube Channel](https://www.youtube.com/c/Nrwl_io)
- [Blog Posts About Nx](https://blog.nrwl.io/nx/home)
<p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
width="100%" alt="Nx - Smart, Fast and Extensible Build System"></a></p>

View File

@ -1,4 +1,4 @@
## Documentation & Resources ### Documentation & Resources
A few links to help you get started: A few links to help you get started:
@ -7,5 +7,5 @@ A few links to help you get started:
- [Official Nx YouTube Channel](https://www.youtube.com/c/Nrwl_io) - [Official Nx YouTube Channel](https://www.youtube.com/c/Nrwl_io)
- [Blog Posts About Nx](https://blog.nrwl.io/nx/home) - [Blog Posts About Nx](https://blog.nrwl.io/nx/home)
<p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank"><img src="./images/nx-courses-and-videos.svg" <p style="text-align: center;"><a href="https://nx.dev/#learning-materials" target="_blank"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-courses-and-videos.svg"
width="100%" alt="Nx - Smart, Fast and Extensible Build System"></a></p> width="100%" alt="Nx - Smart, Fast and Extensible Build System"></a></p>

View File

@ -1,3 +0,0 @@
# Smart, Fast and Extensible Build System
Nx is a next generation build system with first class monorepo support and powerful integrations.