main
js 92 lines 3.21 KB
Raw
1 /**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
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 'use strict';
8
9 // Most of our tests call jest.resetModules in a beforeEach and the
10 // re-require all the React modules. However, the JSX runtime is injected by
11 // the compiler, so those bindings don't get updated. This causes warnings
12 // logged by the JSX runtime to not have a component stack, because component
13 // stack relies on the the secret internals object that lives on the React
14 // module, which because of the resetModules call is longer the same one.
15 //
16 // To workaround this issue, use a transform that calls require() again before
17 // every JSX invocation.
18 //
19 // Longer term we should migrate all our tests away from using require() and
20 // resetModules, and use import syntax instead so this kind of thing doesn't
21 // happen.
22
23 module.exports = function replaceJSXImportWithLazy(babel) {
24 const {types: t} = babel;
25
26 function getInlineRequire(moduleName) {
27 return t.callExpression(t.identifier('require'), [
28 t.stringLiteral(moduleName),
29 ]);
30 }
31
32 return {
33 visitor: {
34 CallExpression: function (path, pass) {
35 let callee = path.node.callee;
36 if (callee.type === 'SequenceExpression') {
37 callee = callee.expressions[callee.expressions.length - 1];
38 }
39 if (callee.type === 'Identifier') {
40 // Sometimes we seem to hit this before the imports are transformed
41 // into requires and so we hit this case.
42 switch (callee.name) {
43 case '_jsxDEV':
44 path.node.callee = t.memberExpression(
45 getInlineRequire('react/jsx-dev-runtime'),
46 t.identifier('jsxDEV')
47 );
48 return;
49 case '_jsx':
50 path.node.callee = t.memberExpression(
51 getInlineRequire('react/jsx-runtime'),
52 t.identifier('jsx')
53 );
54 return;
55 case '_jsxs':
56 path.node.callee = t.memberExpression(
57 getInlineRequire('react/jsx-runtime'),
58 t.identifier('jsxs')
59 );
60 return;
61 }
62 return;
63 }
64 if (callee.type !== 'MemberExpression') {
65 return;
66 }
67 if (callee.property.type !== 'Identifier') {
68 // Needs to be jsx, jsxs, jsxDEV.
69 return;
70 }
71 if (callee.object.type !== 'Identifier') {
72 // Needs to be _reactJsxDevRuntime or _reactJsxRuntime.
73 return;
74 }
75 // Replace the cached identifier with a new require call.
76 // Relying on the identifier name is a little flaky. Should ideally pick
77 // this from the import. For some reason it sometimes has the react prefix
78 // and other times it doesn't.
79 switch (callee.object.name) {
80 case '_reactJsxDevRuntime':
81 case '_jsxDevRuntime':
82 callee.object = getInlineRequire('react/jsx-dev-runtime');
83 return;
84 case '_reactJsxRuntime':
85 case '_jsxRuntime':
86 callee.object = getInlineRequire('react/jsx-runtime');
87 return;
88 }
89 },
90 },
91 };
92 };