diff --git a/CHANGELOG.md b/CHANGELOG.md index 2e96c04a5d4a..099ba311f489 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ ### Performance -- `[jest-core]` Cache micromatch in SearchSource globsToMatcher and avoid recreating RegExp instances in regexToMatcher ([#10131](https://github.com/facebook/jest/pull/10131)) +- `[jest-core, jest-transform]` Improve Jest startup time and test runtime, particularly when running with coverage, by caching micromatch and avoiding recreating RegExp instances ([#10131](https://github.com/facebook/jest/pull/10131)) ## 26.0.1 diff --git a/packages/jest-transform/src/shouldInstrument.ts b/packages/jest-transform/src/shouldInstrument.ts index d9fcdcd268c3..bd71314076de 100644 --- a/packages/jest-transform/src/shouldInstrument.ts +++ b/packages/jest-transform/src/shouldInstrument.ts @@ -8,7 +8,7 @@ import * as path from 'path'; import type {Config} from '@jest/types'; import {escapePathForRegex} from 'jest-regex-util'; -import {replacePathSepForGlob} from 'jest-util'; +import {globsToMatcher, replacePathSepForGlob} from 'jest-util'; import micromatch = require('micromatch'); import type {ShouldInstrumentOptions} from './types'; @@ -16,6 +16,20 @@ const MOCKS_PATTERN = new RegExp( escapePathForRegex(path.sep + '__mocks__' + path.sep), ); +const cachedRegexes = new Map(); +const getRegex = (regexStr: string) => { + if (!cachedRegexes.has(regexStr)) { + cachedRegexes.set(regexStr, new RegExp(regexStr)); + } + + const regex = cachedRegexes.get(regexStr); + + // prevent stateful regexes from breaking, just in case + regex.lastIndex = 0; + + return regex; +}; + export default function shouldInstrument( filename: Config.Path, options: ShouldInstrumentOptions, @@ -33,15 +47,15 @@ export default function shouldInstrument( } if ( - !config.testPathIgnorePatterns.some(pattern => !!filename.match(pattern)) + !config.testPathIgnorePatterns.some(pattern => + getRegex(pattern).test(filename), + ) ) { if (config.testRegex.some(regex => new RegExp(regex).test(filename))) { return false; } - if ( - micromatch([replacePathSepForGlob(filename)], config.testMatch).length - ) { + if (globsToMatcher(config.testMatch)(replacePathSepForGlob(filename))) { return false; } } @@ -59,10 +73,9 @@ export default function shouldInstrument( // still cover if `only` is specified !options.collectCoverageOnlyFrom && options.collectCoverageFrom.length && - micromatch( - [replacePathSepForGlob(path.relative(config.rootDir, filename))], - options.collectCoverageFrom, - ).length === 0 + !globsToMatcher(options.collectCoverageFrom)( + replacePathSepForGlob(path.relative(config.rootDir, filename)), + ) ) { return false; }