From f5d9d4b9c0b5440ab14ddb4a636ea84d384e3408 Mon Sep 17 00:00:00 2001 From: Ahn Date: Fri, 18 Dec 2020 16:06:13 +0100 Subject: [PATCH] perf(compiler): reuse `cacheFS` from jest to reduce file system reading (#679) --- src/__tests__/index.spec.ts | 6 ++++-- src/__tests__/ng-jest-compiler.spec.ts | 16 ++++++++-------- src/compiler/compiler-host.ts | 24 +++++++++++++----------- src/compiler/ng-jest-compiler.ts | 4 ++-- src/index.ts | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/__tests__/index.spec.ts b/src/__tests__/index.spec.ts index 0ac98b24f8..d4dbd6e5d7 100644 --- a/src/__tests__/index.spec.ts +++ b/src/__tests__/index.spec.ts @@ -10,6 +10,7 @@ describe('NgJestTransformer', () => { () => { const obj1 = { config: { cwd: process.cwd(), extensionsToTreatAsEsm: [], globals: {}, testMatch: [], testRegex: [] }, + cacheFS: new Map(), }; const obj2 = { ...obj1, config: { ...obj1.config, globals: {} } }; // eslint-disable-next-line @@ -24,6 +25,7 @@ describe('NgJestTransformer', () => { test('should return the same config set for same values with jest config objects', () => { const obj1 = { config: { cwd: process.cwd(), extensionsToTreatAsEsm: [], globals: {}, testMatch: [], testRegex: [] }, + cacheFS: new Map(), }; const obj2 = { ...obj1 }; // eslint-disable-next-line @@ -84,7 +86,7 @@ describe('NgJestTransformer', () => { const input = { fileContent: 'const foo = 1', // eslint-disable-next-line - options: { config: { ...jestCfg } as any, instrument: false, rootDir: '/foo' }, + options: { config: { ...jestCfg } as any, instrument: false, rootDir: '/foo', cacheFS: new Map(), }, }; // eslint-disable-next-line const ngJestTransformer = require('../'); @@ -121,7 +123,7 @@ describe('NgJestTransformer', () => { }; const input = { // eslint-disable-next-line - options: { config: { ...jestCfg } as any, instrument: false, rootDir: '/foo' }, + options: { config: { ...jestCfg } as any, instrument: false, rootDir: '/foo', cacheFS: new Map(), }, }; // eslint-disable-next-line const ngJestTransformer = require('../'); diff --git a/src/__tests__/ng-jest-compiler.spec.ts b/src/__tests__/ng-jest-compiler.spec.ts index a83e6a4fe7..bb3fecc5d1 100644 --- a/src/__tests__/ng-jest-compiler.spec.ts +++ b/src/__tests__/ng-jest-compiler.spec.ts @@ -45,7 +45,7 @@ describe('NgJestCompiler', () => { // Isolated modules true doesn't have downlevel ctor so this snapshot test should produce different input than with Program test('should return result', () => { const fileName = join(__dirname, '__mocks__', 'foo.service.ts'); - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8'))!; @@ -60,7 +60,7 @@ describe('NgJestCompiler', () => { ...ngJestConfig.parsedTsConfig, rootNames: [fileName], }; - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8'))!; @@ -79,7 +79,7 @@ describe('NgJestCompiler', () => { ...ngJestConfig.parsedTsConfig, rootNames: [], }; - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const emittedResult = compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8'))!; @@ -94,7 +94,7 @@ describe('NgJestCompiler', () => { ...ngJestConfig.parsedTsConfig, rootNames: [fileName], }; - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const emittedResult = compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8'))!; @@ -109,7 +109,7 @@ describe('NgJestCompiler', () => { ...ngJestConfig.parsedTsConfig, rootNames: [], }; - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); expect(() => compiler.getCompiledOutput('foo.ts', readFileSync(fileName, 'utf-8')), @@ -122,7 +122,7 @@ describe('NgJestCompiler', () => { ...ngJestConfig.parsedTsConfig, rootNames: [fileName], }; - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); expect(() => compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8')), @@ -136,7 +136,7 @@ describe('NgJestCompiler', () => { rootNames: [fileName], }; ngJestConfig.shouldReportDiagnostics = jest.fn().mockReturnValueOnce(false); - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); expect(() => compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8'))).not.toThrowError(); }); @@ -148,7 +148,7 @@ describe('NgJestCompiler', () => { ...ngJestConfig.parsedTsConfig, rootNames: [fileName], }; - const compiler = new NgJestCompiler(ngJestConfig); + const compiler = new NgJestCompiler(ngJestConfig, new Map()); // eslint-disable-next-line @typescript-eslint/no-non-null-assertion const emittedResult = compiler.getCompiledOutput(fileName, readFileSync(fileName, 'utf-8'))!; diff --git a/src/compiler/compiler-host.ts b/src/compiler/compiler-host.ts index 5fe4027e02..e5af60ad7e 100644 --- a/src/compiler/compiler-host.ts +++ b/src/compiler/compiler-host.ts @@ -9,12 +9,11 @@ import type { CompilerOptions } from '@angular/compiler-cli'; export class NgJestCompilerHost implements ts.CompilerHost { private readonly _sourceFileCache: Map = new Map(); - private readonly _memoryHost: Map = new Map(); private readonly _emittedResult: [string, string] = ['', '']; private readonly _ts: TTypeScript; private readonly _moduleResolutionCache: ts.ModuleResolutionCache; - constructor(private logger: Logger, private ngJestCfg: NgJestConfig) { + constructor(readonly logger: Logger, readonly ngJestCfg: NgJestConfig, readonly jestCacheFS: Map) { this._ts = this.ngJestCfg.compilerModule; this._moduleResolutionCache = this._ts.createModuleResolutionCache(this.ngJestCfg.cwd, (x) => x); } @@ -24,10 +23,10 @@ export class NgJestCompilerHost implements ts.CompilerHost { } updateMemoryHost(fileName: string, fileContent: string): void { - const previousContents = this._memoryHost.get(fileName); + const previousContents = this.jestCacheFS.get(fileName); const contentsChanged = previousContents !== fileContent; if (contentsChanged) { - this._memoryHost.set(fileName, fileContent); + this.jestCacheFS.set(fileName, fileContent); } } @@ -92,15 +91,18 @@ export class NgJestCompilerHost implements ts.CompilerHost { readFile(fileName: string): string | undefined { const normalizedFileName = normalize(fileName); - let fileContent = this._memoryHost.get(normalizedFileName); - if (!fileContent) { - this.logger.debug( - { fileName: normalizedFileName }, - 'readFile: file does not exist in memory cache, read file with file system', - ); + let fileContent = this.jestCacheFS.get(normalizedFileName); + this.logger.debug( + { fileName: normalizedFileName }, + 'readFile: file does not exist in memory cache, read file with file system', + ); + + if (!fileContent) { fileContent = this._ts.sys.readFile(normalizedFileName) ?? undefined; - this._memoryHost.set(normalizedFileName, fileContent); + if (fileContent) { + this.jestCacheFS.set(normalizedFileName, fileContent); + } } return fileContent; diff --git a/src/compiler/ng-jest-compiler.ts b/src/compiler/ng-jest-compiler.ts index 3ac8fa3410..6431fc2dc5 100644 --- a/src/compiler/ng-jest-compiler.ts +++ b/src/compiler/ng-jest-compiler.ts @@ -18,7 +18,7 @@ export class NgJestCompiler implements CompilerInstance { private readonly _logger: Logger; private readonly _ts: TTypeScript; - constructor(readonly ngJestConfig: NgJestConfig) { + constructor(readonly ngJestConfig: NgJestConfig, readonly jestCacheFS: Map) { this._logger = this.ngJestConfig.logger; this._ts = this.ngJestConfig.compilerModule; this._setupOptions(this.ngJestConfig); @@ -117,7 +117,7 @@ export class NgJestCompiler implements CompilerInstance { '_setupOptions: creating Compiler Host using @angular/compiler-cli createCompilerHost', ); - this._tsHost = new NgJestCompilerHost(this._logger, this.ngJestConfig); + this._tsHost = new NgJestCompilerHost(this._logger, this.ngJestConfig, this.jestCacheFS); this._compilerHost = createCompilerHost({ options: this._compilerOptions, tsHost: this._tsHost, diff --git a/src/index.ts b/src/index.ts index abc2125923..581589c548 100644 --- a/src/index.ts +++ b/src/index.ts @@ -74,7 +74,7 @@ class NgJestTransformer extends TsJestTransformer { this._logger.info('no matching config-set found, creating a new one'); ngJestConfig = new NgJestConfig(jestConfig); - this._compiler = new NgJestCompiler(ngJestConfig); + this._compiler = new NgJestCompiler(ngJestConfig, transformOptions.cacheFS); this._transformCfgStr = new JsonableValue({ ...jestConfig, ...ngJestConfig.parsedTsConfig,