feat(core): optimize project graph file mapping (#13249)

This commit is contained in:
Miroslav Jonaš 2022-11-18 14:34:58 +01:00 committed by GitHub
parent ab93817d44
commit de44bf86b1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 52 deletions

View File

@ -21,7 +21,7 @@ import {
stripIndents, stripIndents,
workspaceRoot, workspaceRoot,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { mapProjectGraphFiles } from 'nx/src/utils/target-project-locator'; import { createProjectFileMappings } from 'nx/src/utils/target-project-locator';
import { lstatSync, mkdirSync, writeFileSync } from 'fs'; import { lstatSync, mkdirSync, writeFileSync } from 'fs';
import { dirname, join, relative } from 'path'; import { dirname, join, relative } from 'path';
import type { BrowserBuilderSchema } from '../src/builders/webpack-browser/webpack-browser.impl'; import type { BrowserBuilderSchema } from '../src/builders/webpack-browser/webpack-browser.impl';
@ -279,14 +279,16 @@ function withSchemaDefaults(options: any): BrowserBuilderSchema {
* this file should get cleaned up via the cypress executor * this file should get cleaned up via the cypress executor
*/ */
function getTempStylesForTailwind(ctExecutorContext: ExecutorContext) { function getTempStylesForTailwind(ctExecutorContext: ExecutorContext) {
const mappedGraph = mapProjectGraphFiles(ctExecutorContext.projectGraph); const mappedGraphFiles = createProjectFileMappings(
ctExecutorContext.projectGraph
);
const ctProjectConfig = ctExecutorContext.projectGraph.nodes[ const ctProjectConfig = ctExecutorContext.projectGraph.nodes[
ctExecutorContext.projectName ctExecutorContext.projectName
].data as ProjectConfiguration; ].data as ProjectConfiguration;
// angular only supports `tailwind.config.{js,cjs}` // angular only supports `tailwind.config.{js,cjs}`
const ctProjectTailwindConfig = join(ctProjectConfig.root, 'tailwind.config'); const ctProjectTailwindConfig = join(ctProjectConfig.root, 'tailwind.config');
const isTailWindInCtProject = !!mappedGraph.allFiles[ctProjectTailwindConfig]; const isTailWindInCtProject = !!mappedGraphFiles[ctProjectTailwindConfig];
const isTailWindInRoot = !!mappedGraph.allFiles['tailwind.config']; const isTailWindInRoot = !!mappedGraphFiles['tailwind.config'];
if (isTailWindInRoot || isTailWindInCtProject) { if (isTailWindInRoot || isTailWindInCtProject) {
const pathToStyle = getTempTailwindPath(ctExecutorContext); const pathToStyle = getTempTailwindPath(ctExecutorContext);

View File

@ -9,7 +9,7 @@ import {
workspaceRoot, workspaceRoot,
} from '@nrwl/devkit'; } from '@nrwl/devkit';
import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph'; import { readProjectsConfigurationFromProjectGraph } from 'nx/src/project-graph/project-graph';
import { mapProjectGraphFiles } from 'nx/src/utils/target-project-locator'; import { createProjectFileMappings } from 'nx/src/utils/target-project-locator';
import { dirname, extname, join, relative } from 'path'; import { dirname, extname, join, relative } from 'path';
import { lstatSync } from 'fs'; import { lstatSync } from 'fs';
@ -90,9 +90,9 @@ export function getProjectConfigByPath(
: configFileFromWorkspaceRoot : configFileFromWorkspaceRoot
); );
const mappedGraph = mapProjectGraphFiles(graph); const mappedGraphFiles = createProjectFileMappings(graph);
const componentTestingProjectName = const componentTestingProjectName =
mappedGraph.allFiles[normalizedPathFromWorkspaceRoot]; mappedGraphFiles[normalizedPathFromWorkspaceRoot];
if ( if (
!componentTestingProjectName || !componentTestingProjectName ||
!graph.nodes[componentTestingProjectName]?.data !graph.nodes[componentTestingProjectName]?.data

View File

@ -5,7 +5,7 @@ import { TSESLint } from '@typescript-eslint/utils';
import { vol } from 'memfs'; import { vol } from 'memfs';
import { import {
TargetProjectLocator, TargetProjectLocator,
mapProjectGraphFiles, createProjectFileMappings,
} from 'nx/src/utils/target-project-locator'; } from 'nx/src/utils/target-project-locator';
import enforceModuleBoundaries, { import enforceModuleBoundaries, {
RULE_NAME as enforceModuleBoundariesRuleName, RULE_NAME as enforceModuleBoundariesRuleName,
@ -1885,7 +1885,9 @@ function runRule(
projectGraph: ProjectGraph projectGraph: ProjectGraph
): TSESLint.Linter.LintMessage[] { ): TSESLint.Linter.LintMessage[] {
(global as any).projectPath = `${process.cwd()}/proj`; (global as any).projectPath = `${process.cwd()}/proj`;
(global as any).projectGraph = mapProjectGraphFiles(projectGraph); (global as any).projectGraph = projectGraph;
(global as any).projectGraphFileMappings =
createProjectFileMappings(projectGraph);
(global as any).targetProjectLocator = new TargetProjectLocator( (global as any).targetProjectLocator = new TargetProjectLocator(
projectGraph.nodes, projectGraph.nodes,
projectGraph.externalNodes projectGraph.externalNodes

View File

@ -154,7 +154,8 @@ export default createESLintRule<Options, MessageIds>({
); );
const fileName = normalizePath(context.getFilename()); const fileName = normalizePath(context.getFilename());
const projectGraph = readProjectGraph(RULE_NAME); const { projectGraph, projectGraphFileMappings } =
readProjectGraph(RULE_NAME);
if (!projectGraph) { if (!projectGraph) {
return {}; return {};
@ -198,7 +199,11 @@ export default createESLintRule<Options, MessageIds>({
const sourceFilePath = getSourceFilePath(fileName, projectPath); const sourceFilePath = getSourceFilePath(fileName, projectPath);
const sourceProject = findSourceProject(projectGraph, sourceFilePath); const sourceProject = findSourceProject(
projectGraph,
projectGraphFileMappings,
sourceFilePath
);
// If source is not part of an nx workspace, return. // If source is not part of an nx workspace, return.
if (!sourceProject) { if (!sourceProject) {
return; return;
@ -210,12 +215,17 @@ export default createESLintRule<Options, MessageIds>({
let targetProject: ProjectGraphProjectNode | ProjectGraphExternalNode; let targetProject: ProjectGraphProjectNode | ProjectGraphExternalNode;
if (isAbsoluteImportIntoAnotherProj) { if (isAbsoluteImportIntoAnotherProj) {
targetProject = findTargetProject(projectGraph, imp); targetProject = findTargetProject(
projectGraph,
projectGraphFileMappings,
imp
);
} else { } else {
targetProject = getTargetProjectBasedOnRelativeImport( targetProject = getTargetProjectBasedOnRelativeImport(
imp, imp,
projectPath, projectPath,
projectGraph, projectGraph,
projectGraphFileMappings,
sourceFilePath sourceFilePath
); );
} }

View File

@ -87,14 +87,19 @@ export default createESLintRule<Options, MessageIds>({
return {}; return {};
} }
const projectGraph = readProjectGraph(RULE_NAME); const { projectGraph, projectGraphFileMappings } =
readProjectGraph(RULE_NAME);
const sourceFilePath = getSourceFilePath( const sourceFilePath = getSourceFilePath(
context.getFilename(), context.getFilename(),
workspaceRoot workspaceRoot
); );
const sourceProject = findSourceProject(projectGraph, sourceFilePath); const sourceProject = findSourceProject(
projectGraph,
projectGraphFileMappings,
sourceFilePath
);
// If source is not part of an nx workspace, return. // If source is not part of an nx workspace, return.
if (!sourceProject) { if (!sourceProject) {
return {}; return {};

View File

@ -1,8 +1,5 @@
import { readCachedProjectGraph, readNxJson } from '@nrwl/devkit'; import { ProjectGraph, readCachedProjectGraph, readNxJson } from '@nrwl/devkit';
import { import { createProjectFileMappings } from 'nx/src/utils/target-project-locator';
mapProjectGraphFiles,
MappedProjectGraph,
} from 'nx/src/utils/target-project-locator';
import { isTerminalRun } from './runtime-lint-utils'; import { isTerminalRun } from './runtime-lint-utils';
import * as chalk from 'chalk'; import * as chalk from 'chalk';
@ -11,7 +8,11 @@ export function ensureGlobalProjectGraph(ruleName: string) {
* Only reuse graph when running from terminal * Only reuse graph when running from terminal
* Enforce every IDE change to get a fresh nxdeps.json * Enforce every IDE change to get a fresh nxdeps.json
*/ */
if (!(global as any).projectGraph || !isTerminalRun()) { if (
!(global as any).projectGraph ||
!(global as any).projectGraphFileMappings ||
!isTerminalRun()
) {
const nxJson = readNxJson(); const nxJson = readNxJson();
(global as any).workspaceLayout = nxJson.workspaceLayout; (global as any).workspaceLayout = nxJson.workspaceLayout;
@ -20,8 +21,9 @@ export function ensureGlobalProjectGraph(ruleName: string) {
* the ProjectGraph may or may not exist by the time the lint rule is invoked for the first time. * the ProjectGraph may or may not exist by the time the lint rule is invoked for the first time.
*/ */
try { try {
(global as any).projectGraph = mapProjectGraphFiles( (global as any).projectGraph = readCachedProjectGraph();
readCachedProjectGraph() (global as any).projectGraphFileMappings = createProjectFileMappings(
(global as any).projectGraph
); );
} catch { } catch {
const WARNING_PREFIX = `${chalk.reset.keyword('orange')('warning')}`; const WARNING_PREFIX = `${chalk.reset.keyword('orange')('warning')}`;
@ -34,7 +36,13 @@ export function ensureGlobalProjectGraph(ruleName: string) {
} }
} }
export function readProjectGraph(ruleName: string) { export function readProjectGraph(ruleName: string): {
projectGraph: ProjectGraph;
projectGraphFileMappings: Record<string, string>;
} {
ensureGlobalProjectGraph(ruleName); ensureGlobalProjectGraph(ruleName);
return (global as any).projectGraph as MappedProjectGraph; return {
projectGraph: (global as any).projectGraph,
projectGraphFileMappings: (global as any).projectGraphFileMappings,
};
} }

View File

@ -16,7 +16,6 @@ import { existsSync } from 'fs';
import { readFileIfExisting } from 'nx/src/project-graph/file-utils'; import { readFileIfExisting } from 'nx/src/project-graph/file-utils';
import { import {
TargetProjectLocator, TargetProjectLocator,
MappedProjectGraph,
removeExt, removeExt,
} from 'nx/src/utils/target-project-locator'; } from 'nx/src/utils/target-project-locator';
@ -99,7 +98,8 @@ export function isRelative(s: string) {
export function getTargetProjectBasedOnRelativeImport( export function getTargetProjectBasedOnRelativeImport(
imp: string, imp: string,
projectPath: string, projectPath: string,
projectGraph: MappedProjectGraph, projectGraph: ProjectGraph,
projectGraphFileMappings: Record<string, string>,
sourceFilePath: string sourceFilePath: string
): ProjectGraphProjectNode<any> | undefined { ): ProjectGraphProjectNode<any> | undefined {
if (!isRelative(imp)) { if (!isRelative(imp)) {
@ -111,38 +111,51 @@ export function getTargetProjectBasedOnRelativeImport(
projectPath.length + 1 projectPath.length + 1
); );
return findTargetProject(projectGraph, targetFile); return findTargetProject(projectGraph, projectGraphFileMappings, targetFile);
} }
export function findProjectUsingFile<T>( function findProjectUsingFile(
projectGraph: MappedProjectGraph<T>, projectGraph: ProjectGraph,
projectGraphFileMappings: Record<string, string>,
file: string file: string
): ProjectGraphProjectNode { ): ProjectGraphProjectNode {
return projectGraph.nodes[projectGraph.allFiles[file]]; return projectGraph.nodes[projectGraphFileMappings[file]];
} }
export function findSourceProject( export function findSourceProject(
projectGraph: MappedProjectGraph, projectGraph: ProjectGraph,
projectGraphFileMappings: Record<string, string>,
sourceFilePath: string sourceFilePath: string
) { ) {
const targetFile = removeExt(sourceFilePath); const targetFile = removeExt(sourceFilePath);
return findProjectUsingFile(projectGraph, targetFile); return findProjectUsingFile(
projectGraph,
projectGraphFileMappings,
targetFile
);
} }
export function findTargetProject( export function findTargetProject(
projectGraph: MappedProjectGraph, projectGraph: ProjectGraph,
projectGraphFileMappings: Record<string, string>,
targetFile: string targetFile: string
) { ) {
let targetProject = findProjectUsingFile(projectGraph, targetFile); let targetProject = findProjectUsingFile(
projectGraph,
projectGraphFileMappings,
targetFile
);
if (!targetProject) { if (!targetProject) {
targetProject = findProjectUsingFile( targetProject = findProjectUsingFile(
projectGraph, projectGraph,
projectGraphFileMappings,
normalizePath(path.join(targetFile, 'index')) normalizePath(path.join(targetFile, 'index'))
); );
} }
if (!targetProject) { if (!targetProject) {
targetProject = findProjectUsingFile( targetProject = findProjectUsingFile(
projectGraph, projectGraph,
projectGraphFileMappings,
normalizePath(path.join(targetFile, 'src', 'index')) normalizePath(path.join(targetFile, 'src', 'index'))
); );
} }
@ -162,7 +175,7 @@ export function isAbsoluteImportIntoAnotherProject(
} }
export function findProjectUsingImport( export function findProjectUsingImport(
projectGraph: MappedProjectGraph, projectGraph: ProjectGraph,
targetProjectLocator: TargetProjectLocator, targetProjectLocator: TargetProjectLocator,
filePath: string, filePath: string,
imp: string imp: string

View File

@ -206,7 +206,7 @@ function filterRootExternalDependencies(
*/ */
export function createProjectRootMappings( export function createProjectRootMappings(
nodes: Record<string, ProjectGraphProjectNode> nodes: Record<string, ProjectGraphProjectNode>
) { ): Map<string, string> {
const projectRootMappings = new Map<string, string>(); const projectRootMappings = new Map<string, string>();
for (const projectName of Object.keys(nodes)) { for (const projectName of Object.keys(nodes)) {
const root = nodes[projectName].data.root; const root = nodes[projectName].data.root;
@ -218,10 +218,6 @@ export function createProjectRootMappings(
return projectRootMappings; return projectRootMappings;
} }
export type MappedProjectGraph<T = any> = ProjectGraph<T> & {
allFiles: Record<string, string>;
};
/** /**
* Strips the file extension from the file path * Strips the file extension from the file path
* @param file * @param file
@ -237,26 +233,20 @@ export function removeExt(file: string): string {
* @param projectGraph * @param projectGraph
* @returns * @returns
*/ */
export function mapProjectGraphFiles<T>( export function createProjectFileMappings(
projectGraph: ProjectGraph<T> projectGraph: ProjectGraph
): MappedProjectGraph | null { ): Record<string, string> {
if (!projectGraph) { const result: Record<string, string> = {};
return null;
}
const allFiles: Record<string, string> = {};
Object.entries( Object.entries(
projectGraph.nodes as Record<string, ProjectGraphProjectNode> projectGraph.nodes as Record<string, ProjectGraphProjectNode>
).forEach(([name, node]) => { ).forEach(([name, node]) => {
node.data.files.forEach(({ file }) => { node.data.files.forEach(({ file }) => {
const fileName = removeExt(file); const fileName = removeExt(file);
allFiles[fileName] = name; result[fileName] = name;
}); });
}); });
return { return result;
...projectGraph,
allFiles,
};
} }
/** /**