Skip to content

Commit 570f088

Browse files
committed
perf(jest-runtime): load chalk only once per worker
1 parent 5ba0cc9 commit 570f088

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@
8484

8585
### Performance
8686

87+
- `[jest-runtime]` Load `chalk` only once per worker ([#10864](https://github.com/facebook/jest/pull/10864))
88+
8789
## 26.6.3
8890

8991
### Fixes

packages/jest-runtime/src/__tests__/runtime_internal_module.test.js

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ describe('Runtime', () => {
3232
runtime.requireModule(modulePath);
3333
}).toThrow(new Error('preprocessor must not run.'));
3434
});
35-
3635
it('loads internal modules without applying transforms', async () => {
3736
const runtime = await createRuntime(__filename, {
3837
transform: {'\\.js$': './test_preprocessor'},
@@ -56,7 +55,6 @@ describe('Runtime', () => {
5655
const exports = runtime.requireModule(modulePath);
5756
expect(exports).toEqual({foo: 'foo'});
5857
});
59-
6058
it('loads internal JSON modules without applying transforms', async () => {
6159
const runtime = await createRuntime(__filename, {
6260
transform: {'\\.json$': './test_json_preprocessor'},
@@ -68,5 +66,29 @@ describe('Runtime', () => {
6866
const exports = runtime.requireInternalModule(modulePath);
6967
expect(exports).toEqual({foo: 'bar'});
7068
});
69+
70+
const OPTIMIZED_MODULE_EXAMPLE = 'chalk';
71+
it('loads modules normally even if on the optimization list', () =>
72+
createRuntime(__filename).then(runtime => {
73+
const modulePath = path.resolve(
74+
path.dirname(runtime.__mockRootPath),
75+
'require-by-name.js',
76+
);
77+
const requireByName = runtime.requireModule(modulePath);
78+
expect(requireByName(OPTIMIZED_MODULE_EXAMPLE)).not.toBe(
79+
require(OPTIMIZED_MODULE_EXAMPLE),
80+
);
81+
}));
82+
it('loads internal modules from outside if on the optimization list', () =>
83+
createRuntime(__filename).then(runtime => {
84+
const modulePath = path.resolve(
85+
path.dirname(runtime.__mockRootPath),
86+
'require-by-name.js',
87+
);
88+
const requireByName = runtime.requireInternalModule(modulePath);
89+
expect(requireByName(OPTIMIZED_MODULE_EXAMPLE)).toBe(
90+
require(OPTIMIZED_MODULE_EXAMPLE),
91+
);
92+
}));
7193
});
7294
});
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
'use strict';
9+
10+
module.exports = moduleName => require(moduleName);

packages/jest-runtime/src/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,16 @@ const defaultTransformOptions: InternalModuleOptions = {
9595
type InitialModule = Omit<Module, 'require' | 'parent' | 'paths'>;
9696
type ModuleRegistry = Map<string, InitialModule | Module>;
9797

98+
// These are modules that we know
99+
// * are safe to require from the outside (not stateful, not prone to errors passing in instances from different realms), and
100+
// * take sufficiently long to require to warrant an optimization.
101+
// When required from the outside, they use the worker's require cache and are thus
102+
// only loaded once per worker, not once per test file.
103+
// Note that this only applies when they are required in an internal context;
104+
// users who require one of these modules in their tests will still get the module from inside the VM.
105+
// Prefer listing a module here only if it is impractical to use the jest-resolve-outside-vm-option where it is required,
106+
// e.g. because there are many require sites spread across the dependency graph.
107+
const INTERNAL_MODULE_REQUIRE_OUTSIDE_OPTIMIZED_MODULES = new Set(['chalk']);
98108
const JEST_RESOLVE_OUTSIDE_VM_OPTION = Symbol.for(
99109
'jest-resolve-outside-vm-option',
100110
);
@@ -660,6 +670,12 @@ export default class Runtime {
660670

661671
requireInternalModule<T = unknown>(from: Config.Path, to?: string): T {
662672
if (to) {
673+
const require = (
674+
nativeModule.createRequire ?? nativeModule.createRequireFromPath
675+
)(from);
676+
if (INTERNAL_MODULE_REQUIRE_OUTSIDE_OPTIMIZED_MODULES.has(to)) {
677+
return require(to);
678+
}
663679
const outsideJestVmPath = decodePossibleOutsideJestVmPath(to);
664680
if (outsideJestVmPath) {
665681
return require(outsideJestVmPath);

0 commit comments

Comments
 (0)