Bug: Cannot import 'react/jsx-runtime' from esm node/webpack 5
nstepien opened this issue · comments
React version: 17.0.1
Steps To Reproduce
- Create a new directory,
cd
to it. - Run
npm i react@17 webpack@5 webpack-cli@4
- Create
index.mjs
with the following content:import * as jsx from 'react/jsx-runtime'; console.log(jsx);
- Run
node index.mjs
- Run
npx webpack-cli path/to/index.mjs
- I had to use an absolute path on my machine or webpack-cli wouldn't find
index.mjs
, don't know why.
- I had to use an absolute path on my machine or webpack-cli wouldn't find
Link to code example: --
The current behavior
> node index.mjs
node:internal/process/esm_loader:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'D:\repos\jsx\node_modules\react\jsx-runtime' imported from D:\repos\jsx\index.mjs
Did you mean to import react/jsx-runtime.js?
at new NodeError (node:internal/errors:277:15)
at finalizeResolution (node:internal/modules/esm/resolve:307:11)
at moduleResolve (node:internal/modules/esm/resolve:742:10)
at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:853:11)
at Loader.resolve (node:internal/modules/esm/loader:85:40)
at Loader.getModuleJob (node:internal/modules/esm/loader:229:28)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:51:40)
at link (node:internal/modules/esm/module_job:50:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
> npx webpack-cli D:\repos\jsx\index.mjs
[webpack-cli] Compilation finished
assets by status 264 bytes [cached] 1 asset
./index.mjs 64 bytes [built] [code generated]
ERROR in ./index.mjs 1:0-41
Module not found: Error: Can't resolve 'react/jsx-runtime' in 'D:\repos\jsx'
Did you mean 'jsx-runtime.js'?
BREAKING CHANGE: The request 'react/jsx-runtime' failed to resolve only because it was resolved as fully specified
(probably because the origin is a '*.mjs' file or a '*.js' file where the package.json contains '"type": "module"').
The extension in the request is mandatory for it to be fully specified.
Add the extension to the request.
webpack 5.4.0 compiled with 1 error in 150 ms
npm ERR! code 1
The expected behavior
No issues importing react/jsx-runtime
with no file extensions.
I can think of two solutions:
- Fix babel, typescript, and all the other tools that automatically add the import to add the file extension.
- That ship has sailed though, I don't think this is right thing to do.
- Add the
exports
field in react'spackage.json
.- This could also open the door to supporting prod/dev builds without depending on
process.env.NODE_ENV
for bundlers. - More discussion here: #11503 (comment)
- https://nodejs.org/dist/latest/docs/api/packages.html
- https://webpack.js.org/guides/package-exports/
- This could also open the door to supporting prod/dev builds without depending on
Same thing with react-dom/server
:
> node .\index.mjs
node:internal/process/esm_loader:74
internalBinding('errors').triggerUncaughtException(
^
Error [ERR_MODULE_NOT_FOUND]: Cannot find module 'D:\repos\jsx\node_modules\react-dom\server' imported from D:\repos\jsx\index.mjs
Did you mean to import react-dom/server.js?
at new NodeError (node:internal/errors:277:15)
at finalizeResolution (node:internal/modules/esm/resolve:307:11)
at moduleResolve (node:internal/modules/esm/resolve:742:10)
at Loader.defaultResolve [as _resolve] (node:internal/modules/esm/resolve:853:11)
at Loader.resolve (node:internal/modules/esm/loader:85:40)
at Loader.getModuleJob (node:internal/modules/esm/loader:229:28)
at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:51:40)
at link (node:internal/modules/esm/module_job:50:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
Is this code created by the babel transform or did you manually add it?
The new JSX transform is not supposed to be used manually:
The functions inside react/jsx-runtime and react/jsx-dev-runtime must only be used by the compiler transform. If you need to manually create elements in your code, you should keep using React.createElement. It will continue to work and is not going away.
The react/jsx-runtime
import is added by the babel preset, I just showed a simplified example for quick bug reproduction.
It can be easily fixed with a simple exports
map in package.json
:
{
"type": "commonjs",
"exports": {
".": "./index.js",
"./jsx-dev-runtime": "./jsx-dev-runtime.js",
"./jsx-runtime": "./jsx-runtime.js",
"./": "./"
},
}
I just showed a simplified example for quick bug reproduction.
Could you show an example that uses the jsx-runtime as it's intended? That would help identify the solution better. For example, a fix could be applied to the transformer instead.
In the repo I work on, we've started publishing the library using the new runtime, using rollup+babel.
If you install it (npm install react-data-grid
), and check node_modules/react-data-grid/lib/bundle.js
, you'll see the import:
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
Some bundlers like webpack 4 or rollup are fine with it, but webpack 5 adopted the newer Node semantics regarding esm, so it expects either a full path with file extension, or react/jsx-runtime
to be matched in an exports
map.
It's also an issue in Node if you try to do server-side rendering from an esm file.
IMO adding an exports
map should be a quick and safe enough fix.
There are multiple transformers that would need fixing otherwise: Babel, TypeScript 4.1, more?
I can go back to the classic runtime so it's not a major issue, but it needs to be fixed upstream one way or the other eventually.
you'll see the import
Could you share a minimal reproduction that produced this code?
I understand that this might seem frustrating since you've already identified a solution that works for you. But the code you're proposing has to be maintained by other people as well so they need to understand what problem it tried to solve. If that problem contains code that is not supposed to be used in that way, then it becomes harder to reason about the fix.
I've set up a minimal repo that'll generate similar bundles:
https://github.com/nstepien/react-20235
Let me know if this is good enough.
I faced the same problem by using creat-react-app.
Looks like the exports
field got added in #20304, which should resolve this issue.
@sebmarkbage When can we expect a patch release for react
17? It would be nice to backport the exports
field to react
16 as well.
For anyone running into this issue, until a fix is released, I also encountered this, and found a way to resolve it.
In my case, I have a few React components exposed from internal packages published to our npm repo. Each component is written in TypeScript, and the published package contains the transpiled files, which already contain the react/jsx-runtime
import.
These components are then used in a React application, also written in typescript, which is then compiled using webpack v4.
When running webpack for the application, I got the Module not found: Error: Can't resolve 'react/jsx-runtime' in '.../app/node_modules/@components/Component/src/index'
error, similar to the one in this issue.
To fix this, I added 'react/jsx-runtime': require.resolve('react/jsx-runtime'),
to my webpack configuration's resolve.alias
field.
I'm reposting this comment of mine from the Babel's tracker but I adjust it slightly to fit better here. You can read it here or in the linked thread.
Adding extensions in the emitted code is being problematic for a couple of reasons and I believe that it should be avoided. I understand that it's unfortunate that things break right now because of it - but node's semantics are very new. The ESM support in node has been released just this month - so it's understandable that some packages are not yet ready in full for it.
The solution for this would be indeed to add exports
map like in this PR: #20304 . It was already a great gesture from the React team to ship runtimes for all~ React versions. I suppose they could add exports map in a similar fashion to all of them, just to avoid confusion etc. It makes sense given how many users they have but it's not up to me to decide about this.
As to the current webpack's situation - just don't use .mjs
for now. If you rename your file to .js
then webpack will gladly resolve the react/jsx-runtime
entrypoint. You just don't have to opt-into the new node's semantics right away and just give time for this issue here to be resolved.
@eps1lon Could you update the labels on this issue?
@Andarist The issue isn't in .mjs
extension, but in a ESM package. If you read the error it says:
or a '*.js' file where the package.json contains '"type": "module"'
My files are just .js
and, of course, I've got the error. All file imports of ESM packages should have extensions by the spec.
Alternative way to specified in #20235 (comment) is to just add the extension manually:
resolve: {
alias: {
"react/jsx-dev-runtime": "react/jsx-dev-runtime.js",
"react/jsx-runtime": "react/jsx-runtime.js"
}
}
The alphas of React 18 have the exports
field, so at least this issue will be fixed when 18.0.0 is released.
I just ran into this issue with react not specifying exports in react@17.0.2
, which caused the build to fail using next@11.1.0
in combination with react-data-grid@7.0.0-beta.2
.
Issue described further in adazzle/react-data-grid#2568 (comment)
By using yarn patch
to apply the fields described in #20235 (comment) fixed the issue completely.
Would be fantastic if this could be patched in for React 17.
For anyone running into this issue, until a fix is released, I also encountered this, and found a way to resolve it.
In my case, I have a few React components exposed from internal packages published to our npm repo. Each component is written in TypeScript, and the published package contains the transpiled files, which already contain the
react/jsx-runtime
import.
These components are then used in a React application, also written in typescript, which is then compiled using webpack v4.
When running webpack for the application, I got theModule not found: Error: Can't resolve 'react/jsx-runtime' in '.../app/node_modules/@components/Component/src/index'
error, similar to the one in this issue.To fix this, I added
'react/jsx-runtime': require.resolve('react/jsx-runtime'),
to my webpack configuration'sresolve.alias
field.
Any chance you could add your whole webpack config?
I have this for my next config and it doesn't appear to work still:
if (!isServer) {
config.resolve.fallback.fs = false;
}
config.resolve.alias = {
...config.resolve.alias,
"react/jsx-dev-runtime": "react/jsx-dev-runtime.js",
"react/jsx-runtime": "react/jsx-runtime.js",
};
return config;
}
Any chance you could add your whole webpack config?
I have this for my next config and it doesn't appear to work still:
if (!isServer) { config.resolve.fallback.fs = false; } config.resolve.alias = { ...config.resolve.alias, "react/jsx-dev-runtime": "react/jsx-dev-runtime.js", "react/jsx-runtime": "react/jsx-runtime.js", }; return config; }
Keep in mind I didn't use next.js, but webpack@4
directly. Try
if (!isServer) {
config.resolve.fallback.fs = false;
}
config.resolve.alias = {
...config.resolve.alias,
"react/jsx-dev-runtime": require.resolve("react/jsx-dev-runtime"),
"react/jsx-runtime": require.resolve("react/jsx-runtime"),
};
return config;
}
@nstepien do you know if there are any pull-requests open for backporting the fix to v17 & v16?
Not that I know of.
Following changes that worked for me, I modified the module Jsk-runtime import statement and restarted the server.
Before : import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
After : import { jsxs, jsx, Fragment } from 'react/jsx-runtime.js';
I am running into the following issue at our company due to the file resolution pointing to a file using require statement when attempting to resolve as an esm module. The problem is specific to yarn 3 I believe but their solution is simply trying to resolve files based on module support. I expect this will present itself beyond yarn 3 (or may have already). Also complicated because the jsx-runtime
import statement is actually coming through @emotion/core
so in this case it's a transitive dependency for the projects of concern.
For people using the recently releasedcreate-react-app@5.0.0
, there's currently an ongoing pull request #11797, expected for the 5.0.1 release.
Until then, here's a solution:
- Install patch-package, which allows you to modify
node_modules
dependency directly in the code - and keep the modification available even after running a fresh npm install.yarn add patch-package postinstall-postinstall
- Add a postinstall hook to your projects
package.json
scripts"postinstall": "patch-package"
- Open the
node_modules/react-scripts/config/webpack.config.js
in your code editor, scroll to about line 320 with the alias and add:
alias: {
+ "react/jsx-dev-runtime": "react/jsx-dev-runtime.js",
+ "react/jsx-runtime": "react/jsx-runtime.js",
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
// Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && {
'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling',
}),
...(modules.webpackAliases || {}),
},
- Apply the patch with
yarn patch-package react-scripts
. This will now create a patch directory in your project root, with the patch file.
Now the patch is available even after a fresh installation.
Also, set a reminder to check for pull request #11797 release to remove the patch. Removing the patch is pretty straightforward. Remove patch-package
postinstall-postinstall
, remove the package.json script & delete the /patch
dir (if you don't use patch-package for anything else).
In addition to #20235 (comment), I suggest not to use alias
, this will be breaking again when 7.0.3
is published, use fallback
instead:
resolve: {
fallback: {
'react/jsx-runtime': 'react/jsx-runtime.js',
'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js',
},
},
This will successfully resolve in 7.0.3
and 18.x
and fallbacks to *.js
when they are not importable.
In addition to #20235 (comment), I suggest not to use
alias
, this will be breaking again when7.0.3
is published, usefallback
instead:resolve: { fallback: { 'react/jsx-runtime': 'react/jsx-runtime.js', 'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js', }, },This will successfully resolve in
7.0.3
and18.x
and fallbacks to*.js
when they are not importable.
Shouldn't this then be mentioned/fixed in CRA #11797?
And any source?
I'm using craco and the problem was solved when I added in craco.config.js
webpack: {
alias: {
'react/jsx-runtime': 'react/jsx-runtime.js',
'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js',
},
},
I'm using react-scripts v5, react 17 with react-data-grid: "7.0.0-beta.8"
I'm using craco and the problem was solved when I added in
craco.config.js
webpack: { alias: { 'react/jsx-runtime': 'react/jsx-runtime.js', 'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js', }, },I'm using react-scripts v5, react 17 with react-data-grid: "7.0.0-beta.8"
I thought CRACO did not support react-scripts 5 yet?
In addition to #20235 (comment), I suggest not to use
alias
, this will be breaking again when7.0.3
is published, usefallback
instead:resolve: { fallback: { 'react/jsx-runtime': 'react/jsx-runtime.js', 'react/jsx-dev-runtime': 'react/jsx-dev-runtime.js', }, },This will successfully resolve in
7.0.3
and18.x
and fallbacks to*.js
when they are not importable.
Using the alias doesn't work for me.
But this one works. Thanks dude you saved me a lot of time.
This is fixed in React 18.
@gaearon Are React 17 and 16 not supported anymore?
What do you mean by “supported”? If there is a security issue, we release a fix for all majors. For other cases, we don’t typically release updates to non-current majors. In this particular case, we don’t believe backporting would even be safe — ESM configurations and setups are very fragile — so we don’t think it’s safe to do in 17 even if it was actively released.
"Unsafe" as in it will be a breaking change for someone else despite it being a minor release.