algolia / react-element-to-jsx-string

Turn a ReactElement into the corresponding JSX string
MIT License
489 stars 80 forks source link

The requested module 'react-is/index.js' does not provide an export named 'ForwardRef' #662

Open malekpour opened 2 years ago

malekpour commented 2 years ago

Recent minor release breaks storybook for react compilation. I think the issue exists in 14.3.3 and 14.3.4 versions and my workaround was to add the following to package.josn:

"resolutions": {
    "**/react-element-to-jsx-string": "14.3.2"
 }
armandabric commented 2 years ago

Thanks for reporting that, I will have a look today (ping @Andarist)

armandabric commented 2 years ago

I'm not sure of what happens here. The react-is@17.0.2 package is exporting the ForwardRef object: https://unpkg.com/react-is@17.0.2/cjs/react-is.production.min.js

Can you check that you have the 17.0.2 version of react-is?

armandabric commented 2 years ago

Everything seems to works in CRA env: https://codesandbox.io/s/clever-haze-tx9di?file=/src/App.js

Andarist commented 2 years ago

@malekpour could you provide a repro case?

malekpour commented 2 years ago

I just create a repo to reproduce the error. Instead of CRA I am using vite. I can confirm react-is@17.0.2 is resolved but the way react-element-to-jsx-string import it, is not compatible with ESNext bundlers such as vite or snowpack and perhaps webpack@5.

https://github.com/malekpour/vite-react-element-to-jsx-string clone, yarn and then yarn run storybook to see the error.

DanielRamosAcosta commented 2 years ago

I'm having the same error, started from scratch creating a new React Vite project @malekpour

auberryberry commented 2 years ago

+1 on this, new vite react app with storybook + storybook-builder-vite, for anyone doing the yarn berry or canary dance you want the following in your config and then run yarn again to do the resolution step. Thanks, @malekpour for the workaround! "resolutions": { "react-element-to-jsx-string": "14.3.2" },

armandabric commented 2 years ago

I'm sorry but I did not have the time theses days to have a look on this. If someone have hints or want to make a PR I will try to help/review it quickly as I can.

Andarist commented 2 years ago

This happens because Vite serves react-is "as-is" - without transforming it anyhow and Vite relies on native modules in the browser. The "imported" file is this:

'use strict';

if ("development" === 'production') {
  module.exports = require('./cjs/react-is.production.min.js');
} else {
  module.exports = require('./cjs/react-is.development.js');
}

and as we can see this is just a CJS file.

According to the Vite docs this should be transformed during a "pre-bundle" step: https://vitejs.dev/guide/features.html#npm-dependency-resolving-and-pre-bundling

From my PoV, it looks like an issue with Vite - I'm not familiar with it enough to say what's exactly broken. The react-is is using the very same "structure" of distributed files etc as React itself so this should just be handled in the same way - and I'm unsure why it isn't in this case. Could you report this to the Vite team? Maybe they would have some pointers regarding this problem.

teyc commented 1 year ago

I'm new to Vite, so I'm not sure how this works, but it seems the following helps:

// vite.config.ts
import * as reactPlugin from 'vite-plugin-react'
import type { UserConfig } from 'vite'

const config: UserConfig = {
  jsx: 'react',
  optimizeDeps: {
    include: [
     'react-is',
    ]
  },
  plugins: [reactPlugin]
}

export default config

and if you have a look at node_modules/.vite_opt_cache/react-is.js it looks like it creates an ESM

reactIs = { isAsyncMode: ..., isSuspense: ... }
:
:
export { reactIs as default }