Skip to content

Commit e66a0e8

Browse files
authored
chore: make requiring from outside the Jest VM easier w/ a Babel plugin (jestjs#10824)
1 parent dbb1290 commit e66a0e8

File tree

6 files changed

+61
-6
lines changed

6 files changed

+61
-6
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
- `[*]` [**BREAKING**] Only support Node LTS releases and Node 15 ([#10685](https://github.com/facebook/jest/pull/10685))
2222
- `[*]` [**BREAKING**] Add `exports` field to all `package.json`s ([#9921](https://github.com/facebook/jest/pull/9921))
23+
- `[*]` Make it easier for Jest's packages to use the VM escape hatch ([#10824](https://github.com/facebook/jest/pull/10824))
2324
- `[jest-config]` [**BREAKING**] Remove `enabledTestsMap` config, use `filter` instead ([#10787](https://github.com/facebook/jest/pull/10787))
2425
- `[jest-resolve]` [**BREAKING**] Migrate to ESM ([#10688](https://github.com/facebook/jest/pull/10688))
2526

babel.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ module.exports = {
5656
['@babel/plugin-transform-modules-commonjs', {allowTopLevelThis: true}],
5757
'@babel/plugin-transform-strict-mode',
5858
'@babel/plugin-proposal-class-properties',
59+
require.resolve('./scripts/babel-plugin-jest-require-outside-vm'),
5960
],
6061
presets: [
6162
[

packages/jest-runtime/src/__tests__/runtime_require_resolve.test.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ describe('Runtime require.resolve', () => {
4444
);
4545
});
4646

47-
describe('with the OUTSIDE_JEST_VM_RESOLVE_OPTION', () => {
47+
describe('with the jest-resolve-outside-vm-option', () => {
4848
it('forwards to the real Node require in an internal context', async () => {
4949
const runtime = await createRuntime(__filename);
5050
const module = runtime.requireInternalModule(

packages/jest-runtime/src/__tests__/test_root/resolve_and_require_outside.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
'use strict';
99

1010
const resolved = require.resolve('./create_require_module', {
11-
[Symbol.for('OUTSIDE_JEST_VM_RESOLVE_OPTION')]: true,
11+
[Symbol.for('jest-resolve-outside-vm-option')]: true,
1212
});
1313
if (typeof resolved !== 'string') {
1414
throw new Error('require.resolve not spec-compliant: must return a string');

packages/jest-runtime/src/index.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,11 @@ const defaultTransformOptions: InternalModuleOptions = {
9292
type InitialModule = Omit<Module, 'require' | 'parent' | 'paths'>;
9393
type ModuleRegistry = Map<string, InitialModule | Module>;
9494

95-
const OUTSIDE_JEST_VM_RESOLVE_OPTION = Symbol.for(
96-
'OUTSIDE_JEST_VM_RESOLVE_OPTION',
95+
const JEST_RESOLVE_OUTSIDE_VM_OPTION = Symbol.for(
96+
'jest-resolve-outside-vm-option',
9797
);
9898
type ResolveOptions = Parameters<typeof require.resolve>[1] & {
99-
[OUTSIDE_JEST_VM_RESOLVE_OPTION]?: true;
99+
[JEST_RESOLVE_OUTSIDE_VM_OPTION]?: true;
100100
};
101101

102102
type StringMap = Map<string, string>;
@@ -1402,7 +1402,7 @@ export default class Runtime {
14021402
resolveOptions,
14031403
);
14041404
if (
1405-
resolveOptions?.[OUTSIDE_JEST_VM_RESOLVE_OPTION] &&
1405+
resolveOptions?.[JEST_RESOLVE_OUTSIDE_VM_OPTION] &&
14061406
options?.isInternalModule
14071407
) {
14081408
return createOutsideJestVmPath(resolved);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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+
const assert = require('assert');
11+
12+
/*
13+
Replace
14+
15+
requireOutside('package')
16+
17+
with
18+
19+
require(require.resolve('package', {
20+
[Symbol.for('jest-resolve-outside-vm-option')]: true,
21+
}));
22+
*/
23+
24+
const REQUIRE_OUTSIDE_FUNCTION_NAME = 'requireOutside';
25+
26+
module.exports = ({template, types: t}) => {
27+
const replacement = template(`
28+
require(require.resolve(IMPORT_PATH, {
29+
[(global['jest-symbol-do-not-touch'] || global.Symbol).for('jest-resolve-outside-vm-option')]: true,
30+
}));
31+
`);
32+
return {
33+
name: 'jest-require-outside-vm',
34+
visitor: {
35+
CallExpression(path) {
36+
const {callee, arguments: args} = path.node;
37+
if (
38+
t.isIdentifier(callee) &&
39+
callee.name === REQUIRE_OUTSIDE_FUNCTION_NAME &&
40+
!path.scope.hasBinding(REQUIRE_OUTSIDE_FUNCTION_NAME)
41+
) {
42+
assert.strictEqual(
43+
args.length,
44+
1,
45+
'requireOutside must be called with exactly one argument',
46+
);
47+
const importPath = args[0];
48+
path.replaceWith(replacement({IMPORT_PATH: importPath}));
49+
}
50+
},
51+
},
52+
};
53+
};

0 commit comments

Comments
 (0)