Description
React version: 16.13.1
Steps To Reproduce
This code works fine when using plain Node.js, but fails: when esm module is enabled:
const { act } = require('react-dom/test-utils');
act(async () => {
console.log('something');
}).then(
() => console.log('success'),
() => console.log('error')
);
$ node test.js
something
success
$ node -r esm test.js
something
Warning: This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning.
error
The warning is caused by an exception happened in this try/catch
block:
react/packages/shared/enqueueTask.js
Lines 15 to 23 in 72d00ab
This is happening because esm
module brings its own implementation of the module
object with slightly different behavior which requires this
context to be properly preserved.
This one-line change should do the fix:
-enqueueTaskImpl = nodeRequire('timers').setImmediate;
+enqueueTaskImpl = nodeRequire.call(module, 'timers').setImmediate;
This issue has also been reported to React-testing-library, which has similar code: testing-library/react-testing-library#614
Why should this be a fix in React and not in ESM?
React relied on undocumented behavior of Node modules loader. It was never guaranteed that it will work without proper this
context.
In fact, it will not work as expected if you try it with any non built-in module
const nodeRequire = module.require;
nodeRequire('timers'); // built-in module, works
require('react') // proper require, also works
nodeRequire('react'); // Error: Cannot find module 'react', even though the m
546B
odule is installed
The current code in React may break in future if timers
module will be replaced with anything else, or if Node.js changes their internal implementation.