parcel
parcel copied to clipboard
HMR doesn't work in a monorepo folder structure
🐛 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 |
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.
I've created a reproduction here: https://github.com/lilyannh/parcel-issue-7853
This is resolved by making sure that parcel is a dependency of each package and not a dependency of the project itself.
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.
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.
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!
@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"
}
No I only have one version of react-refresh in my project :(
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 seededuped
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 onreact-refresh
that was a different version -
Workaround: use
package.json
'soverrides
field to pin the correct version- You need npm>8.3 and will likely need to blow away
node_modules
andpackage-lock.json
to get a fresh install. If you're on a monorepo,overrides
has to go on the rootpackage.json
.
- You need npm>8.3 and will likely need to blow away
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.
@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?
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
.
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.