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

React Fast Refresh doesn't work in a monorepo folder structure #7798

Closed
lilyannh opened this issue Mar 4, 2022 · 12 comments
Closed

React Fast Refresh doesn't work in a monorepo folder structure #7798

lilyannh opened this issue Mar 4, 2022 · 12 comments
Labels

Comments

@lilyannh
Copy link

lilyannh commented Mar 4, 2022

🐛 bug report

Fast refresh changes don't apply when making code changes

🎛 Configuration

My folder structure is as follows:

- /app1
    - /src
    - package.json (just scripts and aliases)
- /app2
    - /src
    - package.json (just scripts and aliases)
- /super-simple-test-react-app
    - /src
    - package.json
- /packages
    - /package1
    - /package2
- package.json (has all dependencies)

😯 Current Behavior

Websocket sees the update come in, the console clears, but the page doesn't actually update.

💁 Possible Solution

When I move the src folder from my test to the root, HMR works as expected.

- /app1
    - /src
    - package.json (just scripts and aliases)
- /app2
    - /src
    - package.json (just scripts and aliases)
- /src-from-super-simple-test-react-app <---- move to root
- /packages
    - /package1
    - /package2
- package.json (has all dependencies) <----add parcel serve script here

🌍 Your Environment

Software Version(s)
Parcel 2.3.2
Node 16.13.0
npm/Yarn 8.1.4
Operating System Windows 10
@denysonique
Copy link

I had a similar problem and creating a separate frontend only package.json and launching from the a separate frontend CWD solved the problem. In my case I believe this was due to babel plugins and other settings interfering with parcel.

To further investigate your issue it would be very helpful if you could upload a sample repo demonstrating the problem.

@lilyannh
Copy link
Author

I've created a reproduction here: https://github.com/lilyannh/parcel-issue-7853

@probablykabari
Copy link

This is resolved by making sure that parcel is a dependency of each package and not a dependency of the project itself.

@BlackFenix2
Copy link

I'm having the same issue in my monorepo. Unfortunately it's not open sourced(contracted).

I do have parcel installed only in the package with the react app.

@BlackFenix2
Copy link

welp, i found the culprit. i had to run yarn why react-refresh and found that @storybook/react was using react-refresh v11 when parcel was using v9. i removed @storybook/react to troubleshoot and now my monorepo HMR is working like a charm.

@lilyannh try running yarn why react-refresh or npm ls react-refresh and see if you get more than one version.

@Southclaws
Copy link

Southclaws commented May 16, 2022

This worked for me, I have a browser extension in one directory and a Next.js website in another. Next.js was using React refresh 0.8.3 and the browser extension (which uses Parcel) was on 0.9.0 so I updated Next.js and it works like a charm now!

Thanks @BlackFenix2 you saved my thousands of F5 presses!

@Offirmo
Copy link

Offirmo commented May 19, 2022

@BlackFenix2 same situation of having Storybook in a monorepo, I just forced a resolution of react-refresh and it seems to be working much better!

	"resolutions": {
		"**/react-refresh": "^0"
	}

@lilyannh
Copy link
Author

No I only have one version of react-refresh in my project :(

@shz
Copy link

shz commented Jul 18, 2022

I believe I've tracked down a root cause here (at least, for one version of this scenario that seems to match the above).

TL;DR for people trying to work around this

  • The parcel plugin setup for fast refresh is brittle and needs react-refresh to be deduped
  • If you run npm ls react-refresh and don't see deduped by @parcel/runtime-react-refresh and @parcel/transformer-react-refresh-wrap, you'll be affected by this bug
  • Example: react-native caused this issue for me by having a transitive dependency on react-refresh that was a different version
  • Workaround: use package.json's overrides field to pin the correct version
    • You need npm>8.3 and will likely need to blow away node_modules and package-lock.json to get a fresh install. If you're on a monorepo, overrides has to go on the root package.json.

Root cause

React's Fast Refresh is implemented across two Parcel plugins -- @parcel/runtime-react-refresh and @parcel/transformer-react-refresh-wrap -- these both have a dependency on react-refresh. Crucially they must load the same version of react-refresh, as that library uses some module level state. If the plugins have different modules, fast refresh doesn't work.

The key problem here is that npm will happily get into a state where the react-refresh module lives in a different place for those two plugins, even if the version is the same. You can confirm this with npm ls react-refresh -- if it doesn't have a deduped for the versions used by the plugins, they live in different places and resolve to different modules when imported by each of those plugins.

This is easy to have bite you if you have some other transitive dependency. In my case it came from react-native.

The fix?

TBH I'm not sure what the right approach is here. The core issue is having react-refresh get used/required by two different plugins. You're at the mercy of NPM's deduping which is a little inscrutable.

Maybe having some intermediary wrapping library over react-refresh would work? It'd be much less likely to be non-deduped, at least.

@robert-w-gries
Copy link

@shz Thank you!! This issue has been driving me crazy and it was very difficult to find the root cause. For me, the issue wasn't even different versions of the module, it was the fact that an identical version was not de-duped. See the following dep tree:

$ npm ls react-refresh
[email protected]
└─┬ [email protected]
  └─┬ @parcel/[email protected]
    ├─┬ @parcel/[email protected]
    │ └── [email protected]
    └─┬ @parcel/[email protected]
      └── [email protected]

Workaround

npm dedupe react-refresh

Running the above resulted in the following dependency tree and fixed react-refresh for me:

[email protected]
└─┬ [email protected]
  └─┬ @parcel/[email protected]
    ├─┬ @parcel/[email protected]
    │ └── [email protected]
    └─┬ @parcel/[email protected]
      └── [email protected] deduped

Maybe @parcel/runtime-react-refresh should list react-refresh as a peer dependency?

@mischnic mischnic changed the title HMR doesn't work in a monorepo folder structure React Fast Refresh doesn't work in a monorepo folder structure Nov 18, 2022
@alcercu
Copy link

alcercu commented Jan 19, 2023

I'm also working on a monorepo and if I want to see the changes that I made to the code reflected on the browser I need to stop the dev server, delete .parcel-cache, and start the server again 😢

yarn why react-refresh returns this:

├─ @parcel/runtime-react-refresh@npm:2.8.3
│  └─ react-refresh@npm:0.9.0 (via npm:^0.9.0)
│
└─ @parcel/transformer-react-refresh-wrap@npm:2.8.3
   └─ react-refresh@npm:0.9.0 (via npm:^0.9.0)

yarn dedupe react-refresh doesn't solve the issue, neither does setting the version on package.json

edit: I did some digging and it works fine with @parcel/watcher@npm:2.0.7 breaks with 2.1.0.

@github-actions
Copy link

This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs.

@github-actions github-actions bot added the Stale Inactive issues label Jul 19, 2023
@github-actions github-actions bot closed this as completed Aug 3, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

10 participants