From eb9baab975164ad65c961e98942a519b2f15b482 Mon Sep 17 00:00:00 2001 From: jaybell Date: Thu, 6 May 2021 19:25:25 -0700 Subject: [PATCH 1/8] fix(core): intelligently hash tsconfig and remove global nx hash Adds the ability to pass in number of nodes and current node to affected run commands so that target runs can be split evenly across nodes ISSUES CLOSED: #5283 --- packages/tao/src/shared/tsconfig.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 packages/tao/src/shared/tsconfig.ts diff --git a/packages/tao/src/shared/tsconfig.ts b/packages/tao/src/shared/tsconfig.ts new file mode 100644 index 00000000000..e69de29bb2d From 3b00328c95a978184f986a92e28f06766a99e261 Mon Sep 17 00:00:00 2001 From: jaybell Date: Thu, 6 May 2021 19:27:17 -0700 Subject: [PATCH 2/8] fix(core): fix(core): intelligently hash tsconfig and remove global nx hash commit files correctly --- packages/tao/src/shared/tsconfig.ts | 21 ++++++++++ packages/workspace/src/core/hasher/hasher.ts | 40 ++++++++++++++++---- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/packages/tao/src/shared/tsconfig.ts b/packages/tao/src/shared/tsconfig.ts index e69de29bb2d..e408cd5c9be 100644 --- a/packages/tao/src/shared/tsconfig.ts +++ b/packages/tao/src/shared/tsconfig.ts @@ -0,0 +1,21 @@ +export interface CompilerOptions { + target: string; + sourceMap: boolean; + importHelpers: boolean; + module: string; + moduleResolution: string; + outDir: string; + experimentalDecorators: boolean; + emitDecoratorMetadata: boolean; + skipLibCheck: boolean; + types: string[]; + lib: string[]; + declaration: boolean; + baseUrl: string; + rootDir: string; + paths: Record; +} + +export interface TsconfigJsonConfiguration { + compilerOptions: CompilerOptions; +} diff --git a/packages/workspace/src/core/hasher/hasher.ts b/packages/workspace/src/core/hasher/hasher.ts index a07823cf2ab..85bcafdb8c7 100644 --- a/packages/workspace/src/core/hasher/hasher.ts +++ b/packages/workspace/src/core/hasher/hasher.ts @@ -12,6 +12,7 @@ import { WorkspaceJsonConfiguration, } from '@nrwl/devkit'; import { resolveNewFormatWithInlineProjects } from '@nrwl/tao/src/shared/workspace'; +import { TsconfigJsonConfiguration } from '@nrwl/tao/src/shared/tsconfig'; export interface Hash { value: string; @@ -210,7 +211,6 @@ export class Hasher { ...implicitDepsFromPatterns, //TODO: vsavkin move the special cases into explicit ts support - 'tsconfig.base.json', 'package-lock.json', 'yarn.lock', 'pnpm-lock.yaml', @@ -220,13 +220,11 @@ export class Hasher { '.nxignore', ]; - const fileHashes = [ - ...fileNames.map((file) => { - const hash = this.fileHasher.hashFile(file); - return { file, hash }; - }), - ...this.hashGlobalConfig(), - ]; + const fileHashes = fileNames.map((file) => { + const hash = this.fileHasher.hashFile(file); + return { file, hash }; + }); + const combinedHash = this.hashing.hashArray( fileHashes.map((v) => v.hash) ); @@ -269,6 +267,7 @@ class ProjectHasher { private sourceHashes: { [projectName: string]: Promise } = {}; private workspaceJson: WorkspaceJsonConfiguration; private nxJson: NxJsonConfiguration; + private tsConfigJson: TsconfigJsonConfiguration; constructor( private readonly projectGraph: ProjectGraph, @@ -276,6 +275,7 @@ class ProjectHasher { ) { this.workspaceJson = this.readWorkspaceConfigFile(workspaceFileName()); this.nxJson = this.readNxJsonConfigFile('nx.json'); + this.tsConfigJson = this.readTsConfig(); } async hashProject( @@ -323,12 +323,24 @@ class ProjectHasher { ); const nxJson = JSON.stringify(this.nxJson.projects[projectName] ?? ''); + const { paths, ...compilerOptions } = this.tsConfigJson.compilerOptions; + + const tsConfig = JSON.stringify({ + compilerOptions: { + ...compilerOptions, + paths: { + [projectName]: paths[projectName] ?? [], + }, + }, + }); + res( this.hashing.hashArray([ ...fileNames, ...values, workspaceJson, nxJson, + tsConfig, ]) ); }); @@ -336,6 +348,18 @@ class ProjectHasher { return this.sourceHashes[projectName]; } + private readTsConfig() { + try { + const res = readJsonFile('tsconfig.base.json'); + res.compilerOptions.paths ??= {}; + return res; + } catch { + return { + compilerOptions: { paths: {} }, + }; + } + } + private readWorkspaceConfigFile(path: string): WorkspaceJsonConfiguration { try { const res = readJsonFile(path); From 41562a49333938005b9494cc75118387d499b48c Mon Sep 17 00:00:00 2001 From: jaybell Date: Thu, 27 May 2021 15:43:06 -0700 Subject: [PATCH 3/8] fix(core): fix(core): add option in nx json to cache tsconfig during hashing --- .../workspace/src/core/hasher/hasher.spec.ts | 178 +++++++++++++----- packages/workspace/src/core/hasher/hasher.ts | 38 +++- 2 files changed, 163 insertions(+), 53 deletions(-) diff --git a/packages/workspace/src/core/hasher/hasher.spec.ts b/packages/workspace/src/core/hasher/hasher.spec.ts index 23211829f67..2423b72f937 100644 --- a/packages/workspace/src/core/hasher/hasher.spec.ts +++ b/packages/workspace/src/core/hasher/hasher.spec.ts @@ -4,13 +4,36 @@ import fs = require('fs'); jest.mock('fs'); describe('Hasher', () => { + const nxJson = { + npmScope: 'nrwl', + projects: { + parent: { implicitDependencies: [], tags: [] }, + child: { implicitDependencies: [], tags: [] }, + }, + }; + + const workSpaceJson = { + projects: { + parent: { root: 'libs/parent' }, + child: { root: 'libs/child' }, + }, + }; + + const tsConfigBaseJsonHash = JSON.stringify({ + compilerOptions: { + paths: { + '@nrwl/parent': ['libs/parent/src/index.ts'], + '@nrwl/child': ['libs/child/src/index.ts'], + }, + }, + }); let hashes = { 'yarn.lock': 'yarn.lock.hash', 'nx.json': 'nx.json.hash', 'package-lock.json': 'package-lock.json.hash', 'package.json': 'package.json.hash', 'pnpm-lock.yaml': 'pnpm-lock.yaml.hash', - 'tsconfig.base.json': 'tsconfig.base.json.hash', + 'tsconfig.base.json': tsConfigBaseJsonHash, 'workspace.json': 'workspace.json.hash', global1: 'global1.hash', global2: 'global2.hash', @@ -23,24 +46,87 @@ describe('Hasher', () => { }; } - it('should create project hash', async () => { + beforeAll(() => { fs.readFileSync = (file) => { if (file === 'workspace.json') { - return JSON.stringify({ - projects: { proj: { root: 'proj-from-workspace.json' } }, - }); + return JSON.stringify(workSpaceJson); } if (file === 'nx.json') { - return JSON.stringify({ projects: { proj: 'proj-from-nx.json' } }); + return JSON.stringify(nxJson); + } + if (file === 'tsconfig.base.json') { + return tsConfigBaseJsonHash; } return file; }; + }); + + it('should create project hash', async () => { + hashes['/file'] = 'file.hash'; + const hasher = new Hasher( + { + nodes: { + parent: { + name: 'parent', + type: 'lib', + data: { + root: '', + files: [{ file: '/file', ext: '.ts', hash: 'file.hash' }], + }, + }, + }, + dependencies: { + parent: [], + }, + }, + {} as any, + { + runtimeCacheInputs: ['echo runtime123', 'echo runtime456'], + }, + createHashing() + ); + + const hash = ( + await hasher.hashTasks([ + { + target: { project: 'parent', target: 'build' }, + id: 'parent-build', + overrides: { prop: 'prop-value' }, + }, + ]) + )[0]; + + expect(hash.value).toContain('yarn.lock.hash'); //implicits + expect(hash.value).toContain('file.hash'); //project files + expect(hash.value).toContain('prop-value'); //overrides + expect(hash.value).toContain('parent'); //project + expect(hash.value).toContain('build'); //target + expect(hash.value).toContain('runtime123'); //target + expect(hash.value).toContain('runtime456'); //target + + expect(hash.details.command).toEqual('parent|build||{"prop":"prop-value"}'); + expect(hash.details.sources).toEqual({ + parent: + '/file|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', + }); + expect(hash.details.implicitDeps).toEqual({ + 'yarn.lock': 'yarn.lock.hash', + 'package-lock.json': 'package-lock.json.hash', + 'pnpm-lock.yaml': 'pnpm-lock.yaml.hash', + }); + expect(hash.details.runtime).toEqual({ + 'echo runtime123': 'runtime123', + 'echo runtime456': 'runtime456', + }); + }); + + it('should create project hash with tsconfig.base.json cache', async () => { hashes['/file'] = 'file.hash'; const hasher = new Hasher( { nodes: { - proj: { - name: 'proj', + parent: { + name: 'parent', type: 'lib', data: { root: '', @@ -49,40 +135,40 @@ describe('Hasher', () => { }, }, dependencies: { - proj: [], + parent: [], }, }, {} as any, { runtimeCacheInputs: ['echo runtime123', 'echo runtime456'], + cacheTsConfig: true, }, createHashing() ); const hash = await hasher.hashTaskWithDepsAndContext({ - target: { project: 'proj', target: 'build' }, - id: 'proj-build', + target: { project: 'parent', target: 'build' }, + id: 'parent-build', overrides: { prop: 'prop-value' }, }); expect(hash.value).toContain('yarn.lock.hash'); //implicits expect(hash.value).toContain('file.hash'); //project files expect(hash.value).toContain('prop-value'); //overrides - expect(hash.value).toContain('proj'); //project + expect(hash.value).toContain('parent'); //project expect(hash.value).toContain('build'); //target expect(hash.value).toContain('runtime123'); //target expect(hash.value).toContain('runtime456'); //target - expect(hash.details.command).toEqual('proj|build||{"prop":"prop-value"}'); + expect(hash.details.command).toEqual('parent|build||{"prop":"prop-value"}'); expect(hash.details.nodes).toEqual({ - proj: '/file|file.hash|{"root":"proj-from-workspace.json"}|"proj-from-nx.json"', + parent: + '/file|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"]}}}', }); expect(hash.details.implicitDeps).toEqual({ 'yarn.lock': 'yarn.lock.hash', - 'nx.json': '{}', 'package-lock.json': 'package-lock.json.hash', 'pnpm-lock.yaml': 'pnpm-lock.yaml.hash', - 'tsconfig.base.json': 'tsconfig.base.json.hash', }); expect(hash.details.runtime).toEqual({ 'echo runtime123': 'runtime123', @@ -94,8 +180,8 @@ describe('Hasher', () => { const hasher = new Hasher( { nodes: { - proj: { - name: 'proj', + parent: { + name: 'parent', type: 'lib', data: { root: '', @@ -104,7 +190,7 @@ describe('Hasher', () => { }, }, dependencies: { - proj: [], + parent: [], }, }, {} as any, @@ -116,8 +202,8 @@ describe('Hasher', () => { try { await hasher.hashTaskWithDepsAndContext({ - target: { project: 'proj', target: 'build' }, - id: 'proj-build', + target: { project: 'parent', target: 'build' }, + id: 'parent-build', overrides: {}, }); fail('Should not be here'); @@ -172,8 +258,10 @@ describe('Hasher', () => { // note that the parent hash is based on parent source files only! expect(hash.details.nodes).toEqual({ - parent: '/filea|a.hash|""|""', - child: '/fileb|b.hash|""|""', + child: + '/fileb|b.hash|{"root":"libs/child"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', + parent: + '/filea|a.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', }); }); @@ -183,16 +271,16 @@ describe('Hasher', () => { const hasher = new Hasher( { nodes: { - proja: { - name: 'proja', + parent: { + name: 'parent', type: 'lib', data: { root: '', files: [{ file: '/filea', ext: '.ts', hash: 'a.hash' }], }, }, - projb: { - name: 'projb', + child: { + name: 'child', type: 'lib', data: { root: '', @@ -201,8 +289,8 @@ describe('Hasher', () => { }, }, dependencies: { - proja: [{ source: 'proja', target: 'projb', type: 'static' }], - projb: [{ source: 'projb', target: 'proja', type: 'static' }], + parent: [{ source: 'parent', target: 'child', type: 'static' }], + child: [{ source: 'child', target: 'parent', type: 'static' }], }, }, {} as any, @@ -211,8 +299,8 @@ describe('Hasher', () => { ); const tasksHash = await hasher.hashTaskWithDepsAndContext({ - target: { project: 'proja', target: 'build' }, - id: 'proja-build', + target: { project: 'parent', target: 'build' }, + id: 'parent-build', overrides: { prop: 'prop-value' }, }); @@ -220,16 +308,18 @@ describe('Hasher', () => { expect(tasksHash.value).toContain('a.hash'); //project files expect(tasksHash.value).toContain('b.hash'); //project files expect(tasksHash.value).toContain('prop-value'); //overrides - expect(tasksHash.value).toContain('proj'); //project + expect(tasksHash.value).toContain('parent|build'); //project and target expect(tasksHash.value).toContain('build'); //target expect(tasksHash.details.nodes).toEqual({ - proja: '/filea|a.hash|""|""', - projb: '/fileb|b.hash|""|""', + child: + '/fileb|b.hash|{"root":"libs/child"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', + parent: + '/filea|a.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', }); const hashb = await hasher.hashTaskWithDepsAndContext({ - target: { project: 'projb', target: 'build' }, - id: 'projb-build', + target: { project: 'child', target: 'build' }, + id: 'child-build', overrides: { prop: 'prop-value' }, }); @@ -237,11 +327,13 @@ describe('Hasher', () => { expect(hashb.value).toContain('a.hash'); //project files expect(hashb.value).toContain('b.hash'); //project files expect(hashb.value).toContain('prop-value'); //overrides - expect(hashb.value).toContain('proj'); //project + expect(hashb.value).toContain('child|build'); //project and target expect(hashb.value).toContain('build'); //target expect(hashb.details.nodes).toEqual({ - proja: '/filea|a.hash|""|""', - projb: '/fileb|b.hash|""|""', + child: + '/fileb|b.hash|{"root":"libs/child"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', + parent: + '/filea|a.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', }); }); @@ -251,8 +343,8 @@ describe('Hasher', () => { const hasher = new Hasher( { nodes: { - proja: { - name: 'proja', + parent: { + name: 'parent', type: 'lib', data: { root: '', @@ -284,8 +376,8 @@ describe('Hasher', () => { ); const tasksHash = await hasher.hashTaskWithDepsAndContext({ - target: { project: 'proja', target: 'build' }, - id: 'proja-build', + target: { project: 'parent', target: 'build' }, + id: 'parent-build', overrides: { prop: 'prop-value' }, }); diff --git a/packages/workspace/src/core/hasher/hasher.ts b/packages/workspace/src/core/hasher/hasher.ts index 85bcafdb8c7..bab8203c60f 100644 --- a/packages/workspace/src/core/hasher/hasher.ts +++ b/packages/workspace/src/core/hasher/hasher.ts @@ -62,7 +62,9 @@ export class Hasher { this.fileHasher = new FileHasher(hashing); this.fileHasher.clear(); } - this.projectHashes = new ProjectHasher(this.projectGraph, this.hashing); + this.projectHashes = new ProjectHasher(this.projectGraph, this.hashing, { + cacheTsConfig: this.options.cacheTsConfig ?? false, + }); } async hashTaskWithDepsAndContext(task: Task): Promise { @@ -271,7 +273,8 @@ class ProjectHasher { constructor( private readonly projectGraph: ProjectGraph, - private readonly hashing: HashingImpl + private readonly hashing: HashingImpl, + private readonly options: { cacheTsConfig: boolean } ) { this.workspaceJson = this.readWorkspaceConfigFile(workspaceFileName()); this.nxJson = this.readNxJsonConfigFile('nx.json'); @@ -323,16 +326,31 @@ class ProjectHasher { ); const nxJson = JSON.stringify(this.nxJson.projects[projectName] ?? ''); - const { paths, ...compilerOptions } = this.tsConfigJson.compilerOptions; + let tsConfig: string; + + if (this.options.cacheTsConfig) { + const { + paths, + ...compilerOptions + } = this.tsConfigJson.compilerOptions; - const tsConfig = JSON.stringify({ - compilerOptions: { - ...compilerOptions, - paths: { - [projectName]: paths[projectName] ?? [], + const rootPath = this.workspaceJson.projects[projectName].root.split( + '/' + ); + rootPath.shift(); + const pathAlias = `@${this.nxJson.npmScope}/${rootPath.join('/')}`; + + tsConfig = JSON.stringify({ + compilerOptions: { + ...compilerOptions, + paths: { + [pathAlias]: paths[pathAlias] ?? [], + }, }, - }, - }); + }); + } else { + tsConfig = JSON.stringify(this.tsConfigJson); + } res( this.hashing.hashArray([ From 5ae9c99363957f4b9496171b3af6ab1218f6c71a Mon Sep 17 00:00:00 2001 From: jaybell Date: Thu, 27 May 2021 16:00:12 -0700 Subject: [PATCH 4/8] fix(core): fix(core): rebase onto master and fix incorrect usage of old method --- .../workspace/src/core/hasher/hasher.spec.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/workspace/src/core/hasher/hasher.spec.ts b/packages/workspace/src/core/hasher/hasher.spec.ts index 2423b72f937..e3df0f9db7e 100644 --- a/packages/workspace/src/core/hasher/hasher.spec.ts +++ b/packages/workspace/src/core/hasher/hasher.spec.ts @@ -86,15 +86,11 @@ describe('Hasher', () => { createHashing() ); - const hash = ( - await hasher.hashTasks([ - { - target: { project: 'parent', target: 'build' }, - id: 'parent-build', - overrides: { prop: 'prop-value' }, - }, - ]) - )[0]; + const hash = await hasher.hashTaskWithDepsAndContext({ + target: { project: 'parent', target: 'build' }, + id: 'parent-build', + overrides: { prop: 'prop-value' }, + }); expect(hash.value).toContain('yarn.lock.hash'); //implicits expect(hash.value).toContain('file.hash'); //project files @@ -105,7 +101,7 @@ describe('Hasher', () => { expect(hash.value).toContain('runtime456'); //target expect(hash.details.command).toEqual('parent|build||{"prop":"prop-value"}'); - expect(hash.details.sources).toEqual({ + expect(hash.details.nodes).toEqual({ parent: '/file|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', }); From 861f707f5bfcc913b96e50a9f7d31ea4ebf6118e Mon Sep 17 00:00:00 2001 From: jaybell Date: Sun, 4 Jul 2021 19:08:30 -0700 Subject: [PATCH 5/8] fix(core): update ts config cache flag name --- packages/tao/src/shared/tsconfig.ts | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 packages/tao/src/shared/tsconfig.ts diff --git a/packages/tao/src/shared/tsconfig.ts b/packages/tao/src/shared/tsconfig.ts deleted file mode 100644 index e408cd5c9be..00000000000 --- a/packages/tao/src/shared/tsconfig.ts +++ /dev/null @@ -1,21 +0,0 @@ -export interface CompilerOptions { - target: string; - sourceMap: boolean; - importHelpers: boolean; - module: string; - moduleResolution: string; - outDir: string; - experimentalDecorators: boolean; - emitDecoratorMetadata: boolean; - skipLibCheck: boolean; - types: string[]; - lib: string[]; - declaration: boolean; - baseUrl: string; - rootDir: string; - paths: Record; -} - -export interface TsconfigJsonConfiguration { - compilerOptions: CompilerOptions; -} From f68e37150ad65e8b99114a8cfc4167551d641a3a Mon Sep 17 00:00:00 2001 From: jaybell Date: Sun, 4 Jul 2021 19:08:54 -0700 Subject: [PATCH 6/8] fix(core): fix(core): update ts config cache flag name --- .../workspace/src/core/hasher/hasher.spec.ts | 4 +- packages/workspace/src/core/hasher/hasher.ts | 63 +++++++++++-------- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/packages/workspace/src/core/hasher/hasher.spec.ts b/packages/workspace/src/core/hasher/hasher.spec.ts index e3df0f9db7e..0a53c480872 100644 --- a/packages/workspace/src/core/hasher/hasher.spec.ts +++ b/packages/workspace/src/core/hasher/hasher.spec.ts @@ -106,6 +106,7 @@ describe('Hasher', () => { '/file|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"],"@nrwl/child":["libs/child/src/index.ts"]}}}', }); expect(hash.details.implicitDeps).toEqual({ + 'nx.json': '{"npmScope":"nrwl"}', 'yarn.lock': 'yarn.lock.hash', 'package-lock.json': 'package-lock.json.hash', 'pnpm-lock.yaml': 'pnpm-lock.yaml.hash', @@ -137,7 +138,7 @@ describe('Hasher', () => { {} as any, { runtimeCacheInputs: ['echo runtime123', 'echo runtime456'], - cacheTsConfig: true, + selectivelyCacheTsConfig: true, }, createHashing() ); @@ -162,6 +163,7 @@ describe('Hasher', () => { '/file|file.hash|{"root":"libs/parent"}|{"implicitDependencies":[],"tags":[]}|{"compilerOptions":{"paths":{"@nrwl/parent":["libs/parent/src/index.ts"]}}}', }); expect(hash.details.implicitDeps).toEqual({ + 'nx.json': '{"npmScope":"nrwl"}', 'yarn.lock': 'yarn.lock.hash', 'package-lock.json': 'package-lock.json.hash', 'pnpm-lock.yaml': 'pnpm-lock.yaml.hash', diff --git a/packages/workspace/src/core/hasher/hasher.ts b/packages/workspace/src/core/hasher/hasher.ts index bab8203c60f..546b3302d25 100644 --- a/packages/workspace/src/core/hasher/hasher.ts +++ b/packages/workspace/src/core/hasher/hasher.ts @@ -12,7 +12,6 @@ import { WorkspaceJsonConfiguration, } from '@nrwl/devkit'; import { resolveNewFormatWithInlineProjects } from '@nrwl/tao/src/shared/workspace'; -import { TsconfigJsonConfiguration } from '@nrwl/tao/src/shared/tsconfig'; export interface Hash { value: string; @@ -39,6 +38,14 @@ interface RuntimeHashResult { runtime: { [input: string]: string }; } +interface CompilerOptions { + paths: Record; +} + +interface TsconfigJsonConfiguration { + compilerOptions: CompilerOptions; +} + export class Hasher { static version = '2.0'; private implicitDependencies: Promise; @@ -63,7 +70,7 @@ export class Hasher { this.fileHasher.clear(); } this.projectHashes = new ProjectHasher(this.projectGraph, this.hashing, { - cacheTsConfig: this.options.cacheTsConfig ?? false, + selectivelyCacheTsConfig: this.options.selectivelyCacheTsConfig ?? false, }); } @@ -222,10 +229,13 @@ export class Hasher { '.nxignore', ]; - const fileHashes = fileNames.map((file) => { - const hash = this.fileHasher.hashFile(file); - return { file, hash }; - }); + const fileHashes = [ + ...fileNames.map((file) => { + const hash = this.fileHasher.hashFile(file); + return { file, hash }; + }), + ...this.hashGlobalConfig(), + ]; const combinedHash = this.hashing.hashArray( fileHashes.map((v) => v.hash) @@ -274,7 +284,7 @@ class ProjectHasher { constructor( private readonly projectGraph: ProjectGraph, private readonly hashing: HashingImpl, - private readonly options: { cacheTsConfig: boolean } + private readonly options: { selectivelyCacheTsConfig: boolean } ) { this.workspaceJson = this.readWorkspaceConfigFile(workspaceFileName()); this.nxJson = this.readNxJsonConfigFile('nx.json'); @@ -328,26 +338,8 @@ class ProjectHasher { let tsConfig: string; - if (this.options.cacheTsConfig) { - const { - paths, - ...compilerOptions - } = this.tsConfigJson.compilerOptions; - - const rootPath = this.workspaceJson.projects[projectName].root.split( - '/' - ); - rootPath.shift(); - const pathAlias = `@${this.nxJson.npmScope}/${rootPath.join('/')}`; - - tsConfig = JSON.stringify({ - compilerOptions: { - ...compilerOptions, - paths: { - [pathAlias]: paths[pathAlias] ?? [], - }, - }, - }); + if (this.options.selectivelyCacheTsConfig) { + tsConfig = this.removeOtherProjectsPathRecords(projectName); } else { tsConfig = JSON.stringify(this.tsConfigJson); } @@ -366,6 +358,23 @@ class ProjectHasher { return this.sourceHashes[projectName]; } + private removeOtherProjectsPathRecords(projectName: string) { + const { paths, ...compilerOptions } = this.tsConfigJson.compilerOptions; + + const rootPath = this.workspaceJson.projects[projectName].root.split('/'); + rootPath.shift(); + const pathAlias = `@${this.nxJson.npmScope}/${rootPath.join('/')}`; + + return JSON.stringify({ + compilerOptions: { + ...compilerOptions, + paths: { + [pathAlias]: paths[pathAlias] ?? [], + }, + }, + }); + } + private readTsConfig() { try { const res = readJsonFile('tsconfig.base.json'); From f060d4ec0309213588ebed1fbcc701c62ab1848a Mon Sep 17 00:00:00 2001 From: jaybell Date: Sun, 4 Jul 2021 19:24:56 -0700 Subject: [PATCH 7/8] docs(core): add explanation of new flag for caching ts config --- docs/angular/guides/configuration.md | 1 + docs/node/guides/configuration.md | 1 + docs/react/guides/configuration.md | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/angular/guides/configuration.md b/docs/angular/guides/configuration.md index 0faba7e2cb5..b122bf8db85 100644 --- a/docs/angular/guides/configuration.md +++ b/docs/angular/guides/configuration.md @@ -373,6 +373,7 @@ Tasks runners can accept different options. The following are the options suppor - `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default. - `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable. - `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value. +- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. `runtimeCacheInputs` are set as follows: diff --git a/docs/node/guides/configuration.md b/docs/node/guides/configuration.md index e27f8ca5e1a..a77acd54744 100644 --- a/docs/node/guides/configuration.md +++ b/docs/node/guides/configuration.md @@ -397,6 +397,7 @@ Tasks runners can accept different options. The following are the options suppor - `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default. - `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable. - `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value. +- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. `runtimeCacheInputs` are set as follows: diff --git a/docs/react/guides/configuration.md b/docs/react/guides/configuration.md index a4214fbfdd1..69d637e209d 100644 --- a/docs/react/guides/configuration.md +++ b/docs/react/guides/configuration.md @@ -393,6 +393,7 @@ Tasks runners can accept different options. The following are the options suppor - `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default. - `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable. - `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value. +- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. `runtimeCacheInputs` are set as follows: From b8e755bc4152fbc49073b5eb843673b430afdc1b Mon Sep 17 00:00:00 2001 From: jaybell Date: Sun, 4 Jul 2021 19:26:52 -0700 Subject: [PATCH 8/8] docs(core): docs(core): add default to description --- docs/angular/guides/configuration.md | 2 +- docs/node/guides/configuration.md | 2 +- docs/react/guides/configuration.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/angular/guides/configuration.md b/docs/angular/guides/configuration.md index b122bf8db85..4bc9295f099 100644 --- a/docs/angular/guides/configuration.md +++ b/docs/angular/guides/configuration.md @@ -373,7 +373,7 @@ Tasks runners can accept different options. The following are the options suppor - `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default. - `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable. - `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value. -- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. +- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. Defaults to `false` `runtimeCacheInputs` are set as follows: diff --git a/docs/node/guides/configuration.md b/docs/node/guides/configuration.md index a77acd54744..5775fee8bf4 100644 --- a/docs/node/guides/configuration.md +++ b/docs/node/guides/configuration.md @@ -397,7 +397,7 @@ Tasks runners can accept different options. The following are the options suppor - `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default. - `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable. - `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value. -- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. +- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. Defaults to `false` `runtimeCacheInputs` are set as follows: diff --git a/docs/react/guides/configuration.md b/docs/react/guides/configuration.md index 69d637e209d..aba22038cb4 100644 --- a/docs/react/guides/configuration.md +++ b/docs/react/guides/configuration.md @@ -393,7 +393,7 @@ Tasks runners can accept different options. The following are the options suppor - `cacheDirectory` defines where the local cache is stored, which is `node_modules/.cache/nx` by default. - `encryptionKey` (when using `"@nrwl/nx-cloud"` only) defines an encryption key to support end-to-end encryption of your cloud cache. You may also provide an environment variable with the key `NX_CLOUD_ENCRYPTION_KEY` that contains an encryption key as its value. The Nx Cloud task runner normalizes the key length, so any length of key is acceptable. - `runtimeCacheInputs` defines the list of commands that are run by the runner to include into the computation hash value. -- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. +- `selectivelyCacheTsConfig` remove all the TypeScript alias paths in the `tsconfig.base.json` that are not the project being hashed. Defaults to `false` `runtimeCacheInputs` are set as follows: