Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transpiling external react modules causes multiple react copies #3102

Closed
jaschaio opened this issue May 5, 2022 · 5 comments
Closed

Transpiling external react modules causes multiple react copies #3102

jaschaio opened this issue May 5, 2022 · 5 comments

Comments

@jaschaio
Copy link

jaschaio commented May 5, 2022

This seems related to #1423

What version of Remix are you using?

1.4.3

Steps to Reproduce

Here is a sample repository with the below steps: https://github.com/jaschaio/remix-bug

Create a new directory

mkdir monorepo
cd monorepo

Create a new package directory within it

mkdir packages
cd packages

Within the packages directory create a new remix project

npx create-remix@latest

Choose "Just the basics" and "Express Server" (this doesn't matter) and install the dependencies.

Create another directory within the /packages directory

mkdir ../controls
cd ../controls

Run npm init, name the package @local/controls and add react and react-dom as peerDependencies into the package.json

{
  "name": "@local/controls",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
+  "peerDependencies": {
+    "react": "^17.0.2",
+    "react-dom": "^17.0.2"
+  }
}

Create a React Component, for example Text.js within the /packages/controls directory. The important thing is that you use some hook like useCallback:

import React, { useCallback } from 'react';

const Text = ( { handleChange, value } ) => {

    const onChange = useCallback( ( event ) => handleChange( event.target.value ), [ handleChange ] );

    return (
        <input
            type="text"
            onChange={ onChange }
            value={ value }
        />
    );

};

export default Text;

Go back to the /packages/website directory and install the other local package via:

npm i ../controls

Add it as a dependency to the serverDependenciesToBundle within the /packages/website/remix.config.js:

/**
 * @type {import('@remix-run/dev').AppConfig}
 */
module.exports = {
  ignoredRouteFiles: ["**/.*"],
+  serverDependenciesToBundle: [
+    /@local\/controls/,
+  ],
  // appDirectory: "app",
  // assetsBuildDirectory: "public/build",
  // serverBuildPath: "build/index.js",
  // publicPath: "/build/",
};

Within the /packages/website/app/routes/index.jsx directory, import the component, remove the default content and place the Component within it:

import { useState } from 'react';
import Text from '../components/Text';

export default function Index() {

    const [ value, setValue ] = useState( '' );

    return (
        <div>
            <Text value={ value } handleChange={ setValue } />
        </div>
    );
}

Run npm run dev from within the /packages/website directory

When visiting localhost:3000 you will get the Following error:

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.

Expected Behavior

Using react components from other modules should work without throwing errors.

Actual Behavior

I can't use hooks within other react modules that are added to serverDependenciesToBundle

Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
@jaschaio
Copy link
Author

jaschaio commented May 5, 2022

Might be related to evanw/esbuild#475 (comment)

@MiguelNiblock
Copy link

I think it might be using the react installation from the local package, instead of the one from the main node_modules

@MiguelNiblock
Copy link

MiguelNiblock commented May 29, 2022

Oh yeah that does seem like esbuild has issues with duplicate packages, independently of Remix. I think the Remix team should seriously consider providing a fallback compilation strategy that uses webpack and allows users to opt-out of the non-configurable esbuild setup. This is what Nextjs does. They offer a fast and shiny SWC compiler (also non-configurable), and for those who prioritize configurability over speed, the build will automatically use the webpack/babel compiler if it detects a babel.config.js.

This is necessary for using universal component libraries from react-native, that also work on web. Take this https://docs.nativebase.io/install-next as an example

@agcty
Copy link

agcty commented Jun 2, 2022

duplicate of #2987

@machour
Copy link
Collaborator

machour commented Jun 10, 2022

Closing in favor of #2987

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants