Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(compiler): improve performance for isolatedModules: false #1558

Merged
merged 7 commits into from Apr 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 0 additions & 48 deletions appveyor.yml

This file was deleted.

12 changes: 6 additions & 6 deletions e2e/__tests__/__snapshots__/logger.test.ts.snap
Expand Up @@ -22,14 +22,14 @@ Array [
"[level:20] file caching disabled",
"[level:20] initializeLanguageServiceInstance(): create typescript compiler",
"[level:20] compileUsingLanguageService(): creating language service",
"[level:20] readThrough(): no cache",
"[level:20] compileAndCacheResult(): no cache",
"[level:20] compileFn(): compiling using language service",
"[level:20] updateMemoryCache(): update memory cache for language service",
"[level:20] visitSourceFileNode(): hoisting",
"[level:20] compileFn(): computing diagnostics for <cwd>/Hello.spec.ts using language service",
"[level:20] computing cache key for <cwd>/Hello.ts",
"[level:20] processing <cwd>/Hello.ts",
"[level:20] readThrough(): no cache",
"[level:20] compileAndCacheResult(): no cache",
"[level:20] compileFn(): compiling using language service",
"[level:20] updateMemoryCache(): update memory cache for language service",
"[level:20] visitSourceFileNode(): hoisting",
Expand Down Expand Up @@ -63,15 +63,15 @@ Array [
"[level:20] file caching disabled",
"[level:20] initializeLanguageServiceInstance(): create typescript compiler",
"[level:20] compileUsingLanguageService(): creating language service",
"[level:20] readThrough(): no cache",
"[level:20] compileAndCacheResult(): no cache",
"[level:20] compileFn(): compiling using language service",
"[level:20] updateMemoryCache(): update memory cache for language service",
"[level:20] visitSourceFileNode(): hoisting",
"[level:20] compileFn(): computing diagnostics for <cwd>/Hello.spec.ts using language service",
"[level:20] calling babel-jest processor",
"[level:20] computing cache key for <cwd>/Hello.ts",
"[level:20] processing <cwd>/Hello.ts",
"[level:20] readThrough(): no cache",
"[level:20] compileAndCacheResult(): no cache",
"[level:20] compileFn(): compiling using language service",
"[level:20] updateMemoryCache(): update memory cache for language service",
"[level:20] visitSourceFileNode(): hoisting",
Expand Down Expand Up @@ -107,15 +107,15 @@ Array [
"[level:20] file caching disabled",
"[level:20] initializeLanguageServiceInstance(): create typescript compiler",
"[level:20] compileUsingLanguageService(): creating language service",
"[level:20] readThrough(): no cache",
"[level:20] compileAndCacheResult(): no cache",
"[level:20] compileFn(): compiling using language service",
"[level:20] updateMemoryCache(): update memory cache for language service",
"[level:20] visitSourceFileNode(): hoisting",
"[level:20] compileFn(): computing diagnostics for <cwd>/Hello.spec.ts using language service",
"[level:20] calling babel-jest processor",
"[level:20] computing cache key for <cwd>/Hello.ts",
"[level:20] processing <cwd>/Hello.ts",
"[level:20] readThrough(): no cache",
"[level:20] compileAndCacheResult(): no cache",
"[level:20] compileFn(): compiling using language service",
"[level:20] updateMemoryCache(): update memory cache for language service",
"[level:20] visitSourceFileNode(): hoisting",
Expand Down
2 changes: 2 additions & 0 deletions src/__helpers__/fakers.ts
Expand Up @@ -72,6 +72,8 @@ export function makeCompiler({
...jestConfig,
testMatch: ['^.+\\.tsx?$'],
testRegex: jestConfig?.testRegex ? [...testRegex, ...jestConfig.testRegex] : testRegex,
setupFiles: [],
setupFilesAfterEnv: [],
}
const cs = new ConfigSet(getJestConfig(jestConfig, tsJestConfig), parentConfig)

Expand Down
67 changes: 0 additions & 67 deletions src/compiler/compiler-utils.spec.ts

This file was deleted.

9 changes: 3 additions & 6 deletions src/compiler/compiler-utils.ts
Expand Up @@ -12,18 +12,15 @@ import { sha1 } from '../util/sha1'
/**
* @internal
*/
export const hasOwn = Object.prototype.hasOwnProperty
/**
* @internal
*/
export function getResolvedModulesCache(cachedir: string): string {
return join(cachedir, sha1('ts-jest-resolved-modules', '\x00'))
export function getResolvedModulesCache(cacheDir: string): string {
return join(cacheDir, sha1('ts-jest-resolved-modules', '\x00'))
}

/**
* @internal
* Get resolved modules of a test file and put into memory cache
*/
/* istanbul ignore next (we leave this for e2e) */
export function cacheResolvedModules(
fileName: string,
fileContent: string,
Expand Down
100 changes: 49 additions & 51 deletions src/compiler/instance.ts
Expand Up @@ -32,7 +32,7 @@
import { Logger } from 'bs-logger'
import { readFileSync, writeFileSync } from 'fs'
import mkdirp = require('mkdirp')
import { basename, extname, join, normalize } from 'path'
import { basename, extname, join } from 'path'

import { ConfigSet } from '../config/config-set'
import { CompileFn, CompilerInstance, MemoryCache, TSFile, TsCompiler } from '../types'
Expand Down Expand Up @@ -92,60 +92,54 @@ const isValidCacheContent = (contents: string): boolean => {
* cache mode
*/
const compileAndCacheResult = (
cachedir: string | undefined,
cacheDir: string | undefined,
memoryCache: MemoryCache,
compileFn: CompileFn,
getExtension: (fileName: string) => string,
logger: Logger,
) => {
if (!cachedir) {
return (code: string, fileName: string, lineOffset?: number) => {
const normalizedFileName = normalize(fileName)

logger.debug({ normalizedFileName }, 'readThrough(): no cache')

const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset)
return (code: string, fileName: string, lineOffset?: number) => {
function getCompileOutput(): string {
const [value, sourceMap] = compileFn(code, fileName, lineOffset)
const output = updateOutput(value, fileName, sourceMap, getExtension)
memoryCache.outputs[normalizedFileName] = output
memoryCache.files.set(fileName, {
...memoryCache.files.get(fileName)!,
output,
})

return output
}
}

// Make sure the cache directory exists before continuing.
mkdirp.sync(cachedir)
try {
const resolvedModulesCache = readFileSync(getResolvedModulesCache(cachedir), 'utf-8')
/* istanbul ignore next (covered by e2e) */
memoryCache.resolvedModules = JSON.parse(resolvedModulesCache)
} catch (e) {}
if (!cacheDir) {
logger.debug({ fileName }, 'compileAndCacheResult(): no cache')

return (code: string, fileName: string, lineOffset?: number) => {
const normalizedFileName = normalize(fileName)
const cachePath = join(cachedir, getCacheName(code, normalizedFileName))
const extension = getExtension(normalizedFileName)
const outputPath = `${cachePath}${extension}`
try {
const output = readFileSync(outputPath, 'utf8')
if (isValidCacheContent(output)) {
logger.debug({ normalizedFileName }, 'readThrough(): cache hit')
memoryCache.outputs[normalizedFileName] = output
return getCompileOutput()
} else {
const cachePath = join(cacheDir, getCacheName(code, fileName))
const extension = getExtension(fileName)
const outputPath = `${cachePath}${extension}`
try {
const output = readFileSync(outputPath, 'utf8')
if (isValidCacheContent(output)) {
logger.debug({ fileName }, 'compileAndCacheResult(): cache hit')
memoryCache.files.set(fileName, {
...memoryCache.files.get(fileName)!,
output,
})

return output
}
} catch (err) {}
return output
}
} catch (err) {}

logger.debug({ fileName }, 'readThrough(): cache miss')
logger.debug({ fileName }, 'compileAndCacheResult(): cache miss')

const [value, sourceMap] = compileFn(code, normalizedFileName, lineOffset)
const output = updateOutput(value, normalizedFileName, sourceMap, getExtension)
const output = getCompileOutput()

logger.debug({ normalizedFileName, outputPath }, 'readThrough(): writing caches')
logger.debug({ fileName, outputPath }, 'compileAndCacheResult(): writing caches')

memoryCache.outputs[normalizedFileName] = output
writeFileSync(outputPath, output)
writeFileSync(outputPath, output)

return output
return output
}
}
}

Expand All @@ -156,16 +150,13 @@ const compileAndCacheResult = (
export const createCompilerInstance = (configs: ConfigSet): TsCompiler => {
const logger = configs.logger.child({ namespace: 'ts-compiler' })
const {
typescript: { options: compilerOptions, fileNames },
typescript: { options: compilerOptions },
tsJest,
} = configs
const cachedir = configs.tsCacheDir
const cacheDir = configs.tsCacheDir
const ts = configs.compilerModule // Require the TypeScript compiler and configuration.
const extensions = ['.ts', '.tsx']
const memoryCache: MemoryCache = {
contents: Object.create(null),
versions: Object.create(null),
outputs: Object.create(null),
resolvedModules: Object.create(null),
files: new Map<string, TSFile>(),
}
Expand All @@ -174,14 +165,21 @@ export const createCompilerInstance = (configs: ConfigSet): TsCompiler => {
extensions.push('.js')
extensions.push('.jsx')
}
// Initialize files from TypeScript into project.
for (const path of fileNames) {
const normalizedFilePath = normalize(path)
memoryCache.versions[normalizedFilePath] = 1
memoryCache.files.set(normalizedFilePath, {
if (cacheDir) {
// Make sure the cache directory exists before continuing.
mkdirp.sync(cacheDir)
try {
const resolvedModulesCache = readFileSync(getResolvedModulesCache(cacheDir), 'utf-8')
/* istanbul ignore next (covered by e2e) */
memoryCache.resolvedModules = JSON.parse(resolvedModulesCache)
} catch (e) {}
}
/* istanbul ignore next (we leave this for e2e) */
configs.jest.setupFiles.concat(configs.jest.setupFilesAfterEnv).forEach(setupFile => {
memoryCache.files.set(setupFile, {
version: 0,
})
}
})
/**
* Get the extension for a transpiled file.
*/
Expand All @@ -196,7 +194,7 @@ export const createCompilerInstance = (configs: ConfigSet): TsCompiler => {
} else {
compilerInstance = initializeTranspilerInstance(configs, memoryCache, logger)
}
const compile = compileAndCacheResult(cachedir, memoryCache, compilerInstance.compileFn, getExtension, logger)
const compile = compileAndCacheResult(cacheDir, memoryCache, compilerInstance.compileFn, getExtension, logger)

return { cwd: configs.cwd, compile, program: compilerInstance.program }
}