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

Parcel 2: HMR Broken? #6685

Closed
dioptre opened this issue Aug 4, 2021 · 49 comments · Fixed by #7514
Closed

Parcel 2: HMR Broken? #6685

dioptre opened this issue Aug 4, 2021 · 49 comments · Fixed by #7514
Labels

Comments

@dioptre
Copy link

dioptre commented Aug 4, 2021

🐛 bug report

As per the unresolved issue #6586 I also get:

the browser console just says "console cleared" - have to manually refresh? Also, until there is a code change this shows in browser console - [parcel] 🚨 Connection to the HMR server was lost

🤔 Expected Behavior

This used to update in place on the page a few weeks ago.

😯 Current Behavior

No changes are made but the console was cleared.

💁 Possible Solution

Not sure. How would I debug this? It's hard to see what's happening esp with the console clearing.

🔦 Context

Slowing down dev times.

💻 Code Sample

N/A

🌍 Your Environment

Software Version(s)
Parcel 2.0.0-rc0
Node 14.15.0
npm/Yarn berry (3.0.0)
Operating System mac

Similar issues?

If there's suggestions on how the community can help debug these please provide some insight.

Thanks!

@danieltroger
Copy link
Contributor

It's hard to see what's happening esp with the console clearing.

You can check "preserve log" to prevent this in chrome

@dioptre
Copy link
Author

dioptre commented Aug 4, 2021

I didn't see anything unusual in chrome, but ran it in firefox and see:
Screen Shot 2021-08-04 at 16 20 18

Not sure if that also has something to do with it?

@devongovett
Copy link
Member

Do you have a code sample that can reproduce your issue?

@dioptre
Copy link
Author

dioptre commented Aug 5, 2021 via email

@jeffpeck10x
Copy link
Contributor

I am having this too. It seems like it started when I started using useContext and wrapping things in a Provider.

@MaximeDesRoches
Copy link

MaximeDesRoches commented Aug 11, 2021

After some trial and error, it seems that the HMR_PORT is not set:

parcel serve 'src/(css|js)/index*(*).(scss|ts|js)' \
	--no-cache \
	--target main-dev \
	--public-url /assets \
	--dist-dir dist/assets \
	--cert ./.ssl/fullchain.pem \
	--key ./.ssl/privkey.pem \
	--host localhost \

with the target:

"main-dev": {
	"sourceMap": {
		"inline": true,
		"inlineSources": true
	}
},

image

Upon inspection, HMRRuntime.js doesn't seem to add the webserver port in the config and is instead using the current port (80).

var HMR_HOST = null;
var HMR_PORT = null;
var HMR_SECURE = true;
var HMR_ENV_HASH = "3df1cf77e366c81c";

Testing with postman, the connection is working when we specify the correct port:

image

@mischnic mischnic added the HMR Hot Module Reloading label Aug 11, 2021
@kayomarz
Copy link

For me, this issue was related to <script> using this command:

parcel serve src/index.html
  --dist-dir ../dist
  --public-url /foo/

hmr ok for the below src/index.html:

<!doctype html>
<html lang="en">
  <body>
    <p>Hello</p>
    <script type="module" src="./index.js"></script>
  </body>
</html>

hmr broken after adding another <script> tag:

(browser console just says "console cleared" - have to manually refresh)

<!doctype html>
<html lang="en">
  <body>
    <p>Hello</p>
    <script type="module" src="./index.js"></script>
    <script> // HMR broke after adding this, needed manual refresh. 
      console.log('hello);
    </script>
  </body>
</html>

hmr fixed after adding type="module" for second <script>

<!doctype html>
<html lang="en">
  <body>
    <p>Hello</p>
    <script type="module" src="./index.js"></script>
    <script type="module"> // HMR fixed after adding type="module" 
      console.log('hello);
    </script>
  </body>
</html>

Debugging

I tried debugging in the browser and observed that when hmr is broken, the asset change gets detected by the websocket but because asset.envHash does not match HMR_ENV_HASH, the change gets ignored in the next step (filtered out).

In case it helps, you can try this in the browser, putting a break-point inside the following filter function:

var assets = data.assets.filter(function(asset) {
  return asset.envHash === HMR_ENV_HASH; // put a breakpoint here.
}); // Handle HMR Update

@pickfire
Copy link

pickfire commented Aug 30, 2021

Same issue with adding a 3rd party script like bootstrap (multiple <script>). However, importing bootstrap from javascript module doesn't seemed to have this issue.

@domenkozar
Copy link

It seems like HMR works for html, but not for the transformers (Elm in my case).

@AshotN
Copy link

AshotN commented Sep 20, 2021

Changing my script type from application/javascript to module resolved HMR not working for me.

@smcallis
Copy link

smcallis commented Sep 26, 2021

I was importing a typescript module: <script type="module" src="./main.ts"></script> and changes weren't getting reflected in the browser, if I add a query string to it seems to work, at least for a little: <script type="module" src="./main.ts?ugh"></script>

@devongovett
Copy link
Member

We fixed some issues with HMR recently. Does this still happen if you use the latest nightly version?

@jeffpeck10x
Copy link
Contributor

Just tried with the latest parcel 2.0.0-nightly.855 and when I make an update and save, I get

Console was cleared

yet, I need to manually refresh the page.

If I "Preserve Logs", I only get:

console.clear() was prevented due to 'Preserve log'

@maxbaun
Copy link

maxbaun commented Oct 6, 2021

Just tried with the latest parcel 2.0.0-nightly.855 and when I make an update and save, I get

Console was cleared

yet, I need to manually refresh the page.

If I "Preserve Logs", I only get:

console.clear() was prevented due to 'Preserve log'

I am seeing the same issue

@devongovett
Copy link
Member

Can either of you give any other details about your project or setup? Like how can we reproduce this?

@jeffpeck10x
Copy link
Contributor

jeffpeck10x commented Oct 6, 2021

@devongovett I tried to create a small project that reproduces this issue this morning, however HMR is working perfectly there.

And even as I bring in various “complexities”, like the use of a context provider and multiple components, and asynchronous fetching to update state, HMR still continues to work flawlessly.

I am trying to narrow down exactly what the problem is, as it is still happening in my larger application (that I cannot share).

I will update here if I find anything, and will post a demo if reproducible.

@jeffpeck10x
Copy link
Contributor

jeffpeck10x commented Oct 6, 2021

I cannot figure this out.

When I pull out pieces of my project, the behavior described above of it not refreshing and just printing "Console was cleared" continues to happen.

Then, after some point of pulling away pieces of the project, it stops happening and HMR works perfectly. I then revert the last thing that I undid.. and HMR still works perfectly. :(

I have tried deleting .parcel-cache, deleting node_modules, and deleting yarn.lock and installing everything anew. I have tried different versions of parcel. I cannot seem to figure out what is the critical thing that causes HMR to break.

I even had the idea that maybe my IDE (PyCharm) was the issue because it sometimes reformats the file and saves a second time (causing two quick file changes), but even making changes from a different editor does not have any affect.

@jeffpeck10x
Copy link
Contributor

Ok, I got something!

My project is a monorepo with different packages. I found when I removed one particular package, HMR works in parcel. When I put that package back, it breaks.

So, what's the package?....

storybook.

In particular, if I remove this one dependency from packages/storybook/package.json:

"@storybook/react": "^6.1.17"

HRM is fixed.

So, that should help, right?

I will see about making a small demo of this to test yourself.

@jeffpeck10x
Copy link
Contributor

jeffpeck10x commented Oct 7, 2021

@devongovett I have made a small repo that consistently demonstrates the issue that I am having:
https://github.com/jeffpeck10x/parcel-hmr-test

Please try the steps in the README.

For anyone finding this thread, it seems that the issue is that the @storybook/react dependency is interfering with parcel's updating of the react components.

It looks like the specific dependencies of @storybook/react that are the culprits are:

  {
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
    "react-refresh": "^0.8.3"
  }

i.e. if your project has those dependencies, even indirectly, it may cause parcel HMR to not work.

@devongovett
Copy link
Member

It seems you are ending up with multiple copies of react-refresh in your project:

$ find . -name react-refresh
./node_modules/react-refresh
./node_modules/@parcel/runtime-react-refresh/node_modules/react-refresh
./node_modules/@parcel/transformer-react-refresh-wrap/node_modules/react-refresh

This is because @storybook/react and @pmmmwh/react-refresh-webpack-plugin depend on "^0.8.3", and @parcel/runtime-react-refresh and @parcel/transformer-react-refresh-wrap depend on "^0.9.0". Yarn is for some reason hoisting the former, and duplicating the latter. Because the Parcel runtime and transformer have different copies, things are broken.

@jeffpeck10x
Copy link
Contributor

jeffpeck10x commented Oct 7, 2021

Aha!

So, adding this to my top-level package.json seems to fix parcel HMR:

  "resolutions": {
    "react-refresh": "0.9.0"
  }

I have not yet checked if it breaks storybook. And it looks like storybooks still works as expected too.

But, in general, re:

Yarn is for some reason hoisting the former, and duplicating the latter. Because the Parcel runtime and transformer have different copies, things are broken.

Is there anything that can be done to ensure that Parcel runtime is using the same dependencies?

Alternatively, maybe Parcel can issue a warning when multiple copies are found. Deck.gl does this and will not run if there are multiple versions of a dependency luma.gl.

It seems like there are several threads about this issue of broken HMR, and even just issuing a warning would make it easy for somebody to get to the bottom of. Like, Multiple versions of react-refresh detected. HMR may not work as expected.

@maxbaun
Copy link

maxbaun commented Oct 7, 2021

I seem to have fixed the HMR issue too. There were two things I did:

  1. I had next installed as a dependency, which was using react-refresh 0.8.3... no idea how next was installed as a dependency, but got rid of it, but that alone didn't fix the HMR issue

  2. I removed any javascript code directly in my index.html and all of a sudden HMR started working. When I put any embedded javascript back into my index.html HRM breaks again.

@maxbaun
Copy link

maxbaun commented Oct 7, 2021

I was able to recreate this issue with a newly created project so that you can reproduce the issue. Steps are in the README of this git repo

https://github.com/maxbaun/parcel-hmr-issue

@devongovett
Copy link
Member

@maxbaun React Refresh requires the entry component passed to ReactDOM.render to be in a separate file. See this tips listed here: https://parceljs.org/recipes/react/#fast-refresh

@hugihlynsson
Copy link

hugihlynsson commented Oct 28, 2021

I had this exact issue (console clear without any changes) in a project where I was using React 16. Upgrading to React 17 fixed fast-refresh.

@tonyhallett
Copy link
Contributor

@andreafdaf
I tracked down why it was not working for me, perhaps it helps.

I was also having an issue where
a) I build - ok
b) I change my tsx file
c) Build - no change

An initial the solution was to delete the .parcel-cache. Looking at it further

The change I made is found by parcel here

async function loadRequestGraph(options): Async<RequestGraph> {
  if (options.shouldDisableCache) {
    return new RequestGraph();
  }

  let cacheKey = getCacheKey(options);
  let requestGraphKey = hashString(`${cacheKey}:requestGraph`);
  let requestGraph = await options.cache.get<RequestGraph>(requestGraphKey);

  if (requestGraph) {
    let opts = getWatcherOptions(options);
    let snapshotKey = hashString(`${cacheKey}:snapshot`);
    let snapshotPath = path.join(options.cacheDir, snapshotKey + '.txt');
    // ******************* event found
    // array containg 
    /*
        { path:"full-path-to/src/app.tsx",type:"update"}
    */
    let events = await options.inputFS.getEventsSince(
      options.projectRoot,
      snapshotPath,
      opts,
    );
    requestGraph.invalidateUnpredictableNodes();
    requestGraph.invalidateEnvNodes(options.env);
    requestGraph.invalidateOptionNodes(options);
    requestGraph.respondToFSEvents(
      events.map(e => ({
        type: e.type,
        path: toProjectPath(options.projectRoot, e.path),
      })),
    );

    return requestGraph;
  }

  return new RequestGraph();
}

respondToFSEvents(events) {
    let didInvalidate = false;

    for (let {
      path: _filePath,
      type
    } of events) {
      let filePath = (0, _projectPath.fromProjectPathRelative)(_filePath);
      let hasFileRequest = this.hasContentKey(filePath);  // ************ filePath is src/app.tsx

But in the map below it was being stored as src/App.tsx ! So the change was being ignored by the build.

hasContentKey(contentKey) {
    return this._contentKeyToNodeId.has(contentKey);
  }

The reason it was stored in this way was due to the import in index.tsx. By correcting this the build issue is resolved and so is hmr.

import ReactDOM from "react-dom";
import { App } from "./App";// ********************
const app = document.getElementById("app");
ReactDOM.render(<App/>, app);

@Ciberusps
Copy link

Ciberusps commented Nov 27, 2021

@devongovett I have made a small repo that consistently demonstrates the issue that I am having: https://github.com/jeffpeck10x/parcel-hmr-test

Please try the steps in the README.

For anyone finding this thread, it seems that the issue is that the @storybook/react dependency is interfering with parcel's updating of the react components.

It looks like the specific dependencies of @storybook/react that are the culprits are:

  {
    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
    "react-refresh": "^0.8.3"
  }

i.e. if your project has those dependencies, even indirectly, it may cause parcel HMR to not work.

Thanks a lot lost 4h, it was f... storybook@6.2.9

So I added this resolution as @jeffpeck10x advised

"resolutions": {
    "react-refresh": "0.9.0"
  }, 

and yarn install

@pricebaldwin
Copy link

I have been working on this error for the better part of today. I eventually "fixed" the problem, but I have no idea why what I did works.

I moved my index.html file into the project root (from src/) and then removed all ~ inclusions across the source code. Instead I set a different alias in both package.json and tsconfig.json, since it seemed like it wouldn't let me override `~' to point to 'src/'.

After moving the index file and refactoring all usage of ~, all code and HMR work as expected.

Before moving index.html, changing some files (the ones including the component file, in this case index.html and index.tsx) would cause a HMR reload, but changing the included Test.tsx component would trigger a console clear, but not a reload.

Further confusing me, I was not able to replicate this issue in another project, even when using the exact same tsconfig.json. Our project has no secondary usage of react-refresh, so there's a possibility it's a different issue all together.

Also, I noticed that .parcel_cache was being generated within src/ when index.html was in src/, but it moved to the root when I moved index.html, which seemed a bit suspicious.

I wish any of this were more concrete, but I figured I should report what I saw in case it helps get to a resolution.

@devongovett
Copy link
Member

@andreafdaf I tried your example but it worked for me...

@nikhilgupta345
Copy link

nikhilgupta345 commented Jan 26, 2022

Still having the exact same issue as @andreafdaf (React v17, TypeScript, Parcel v2.2.1, MacOS using VSCode through SSH on Ubuntu box). Curious -- were you able to figure out what the issue was?

@andreafdaf
Copy link

Hi @nikhilgupta345 I have updated to parcel@^2.2.1 and it now works fine, which version are you on? I was having this problem on 2.0.1.

@devongovett I guess #7514 fixed things also for this case, at least for me. Thanks 👏 🎉

@nikhilgupta345
Copy link

nikhilgupta345 commented Jan 26, 2022

I'm having the problem on v2.2.1 unfortunately. I'll continue looking but it seems we're getting the updates via the websocket, but they're not getting applied on the browser.

I stepped through the code and the hashes being sent match what react-refresh knows about and the hmrApply function is being run, but the actual bundle is not being updated for some reason. Only updates to the file referenced by the html file are reloading properly (index.tsx), but any other files referenced by index.tsx are not.

@chriscanossi
Copy link

chriscanossi commented Jan 31, 2022

I'm also seeing identical behavior, using v2.21, described by @nikhilgupta345. The WebSocket receives an update notification with the console cleared, but no update is applied. Interestingly, if I touch, i.e., edit without changing, the package.json or .parcelrc file, this will cause a content refresh.

@chriscanossi
Copy link

Hi @nikhilgupta345. I managed to solve my problem by switching relative imports to tilde spcifiers. Works like a charm now - very fast.

@ibqn
Copy link

ibqn commented Mar 28, 2022

I have a very similar issue to the one @andreafdaf has described. Here, you can find an exemplary project with parcel and preact https://github.com/ibqn/preact-alias.

So, if index.jsx gets modified new changes can be observed. If header.jsx is modified, no changes are seen, until page is reloaded manually.

@XtraKrispi
Copy link

I have the same issue as @andreafdaf and @nikhilgupta345 on v2.7.0 of Parcel, only instead of React, I'm using Elm.
Symptoms are the same though, I change my main file and it will reload, but changing any other files, no reload.
I also see the change come in via the websocket and it does have my code changes, they just don't get applied properly.

I'm on a Mac running zsh through iterm2.

https://github.com/XtraKrispi/board-game-framework for reference

@DevAlvaroF
Copy link

DevAlvaroF commented Mar 8, 2023

Hi @nikhilgupta345. I managed to solve my problem by switching relative imports to tilde spcifiers. Works like a charm now - very fast.

This worked temporarily with Firefox. After a couple of saves the issue re-appeared

OLD:
<script type="module" src="./src/js/controller.js"></script>

NEW:
<script type="module" src="~/src/js/controller.js"></script>

The OLD approach only generates the issue with both Firefox and Firefox Dev

Chrome works fine with both

Edit: Error re-appeared

@numan
Copy link

numan commented Mar 24, 2023

I'm also seeing identical behavior, using v2.21, described by @nikhilgupta345. The WebSocket receives an update notification with the console cleared, but no update is applied. Interestingly, if I touch, i.e., edit without changing, the package.json or .parcelrc file, this will cause a content refresh.

I'm having this issue on 2.8.3. None of the suggested workarounds have worked for me so far.

@wisammechano
Copy link

wisammechano commented Mar 28, 2023

For me, parcel is receiving the HMR payload, and it is updating the main index.hash.js file, but the changes don't reflect on the DOM until a hard reload.

No workaround is working. Tried the tilde import, relative import, and all the same. Only a refresh would update the content (from hey to hey there below).

Update: A solution for me is to install react as a dependency instead of aliasing the package in package.json. Now it is working.

image

@truesteps
Copy link

What fixed the issue for me was not seeting the port explicitly in the hmrOptions while running parcel through parcel API

@bjornhanson
Copy link

bjornhanson commented Sep 1, 2023

I'm seeing this issue on Parcel v2.9.3 with React 18 on macOS 13.5.1. We're not using storybook and the only react-refresh dependencies are v0.9.0 from Parcel. If I save the index.jsx file that is pulled in from the html file, the page reloads, but if I save App.jsx or anything down the tree, nothing happens. I see parcel HMR websocket messages coming in, but the page doesn't update. We're not setting the hmrOptions manually. Just running the parcel command, passing in index.html, and using the --dist-dir argument. Does anyone have any suggestions? We've been stuck on Parcel 1 because Parcel 2 hasn't worked yet and this seems like another failed attempt to update it.

UPDATE: I should note that I see Console was cleared in the console. If I enabled "Preserve logs" then I don't see anything more, just that the console was unable to clear. And I can update CSS (in a .scss file) and see that change automatically apply to the page. The problem is seeing any React components to update or cause a page reload (either would be better than nothing).

@programmist
Copy link

programmist commented Oct 3, 2023

I set up a dead simple Typescript web project and am having the same issue as mentioned many times in this thread. I could see the changes being received by the Parcel HMR code in my debugger, but it never reloaded the page, which was needed to update the DOM.

@mischnic
Copy link
Member

mischnic commented Oct 3, 2023

@bjornhanson @programmist Can you provide a reproduction? Otherwise there's nothing we can do here

@programmist
Copy link

Hi @mischnic . Apologies - I would have done so, but I assumed this wasn't being worked on as the issue was closed.

Here's a github repo with a super simple node web app using TypeScript that reproduces the issue:
https://github.com/programmist/parcel-hmr-issue-repro

I created this project by initializing TS and Node projects in a new directory...

mkdir hello-web
cd hello-web
tsc --init
npm init -y

...and then adding an index.html file which references index.ts. The TS file adds text to an empty <h1> element when it is loaded.

To Reproduce the Issue:

  • Clone this repo, cd into the parcel-hmr-issue-repro directory, and run npx parcel index.html
  • Open http://localhost:1234 in your browser
  • You should see a page with an <h1> element containing the text "Hello World"
  • With the Parcel server still running, change title.textContent in index.ts to something different and save the file.

At this point I would have expected to see the text on the page update, but it doesn't. All I see is a "console was cleared" message in the JS console. In order to see an update I must manually refresh the browser page.

Incidentally, I went to the line of code which clears the console and set a breakpoint a few lines earlier in the onmessage handler, just below where the HMRMessage is being parsed. Then I made another update to my index.ts file. When inspecting the data, I can see the TS changes I made in data.assets[0].output.

image

@iacobucci
Copy link

I was importing a typescript module: <script type="module" src="./main.ts"></script> and changes weren't getting reflected in the browser, if I add a query string to it seems to work, at least for a little: <script type="module" src="./main.ts?ugh"></script>

Strangely enough this is the only way the hmr is working for my setup: firefox, typescript, p5js

@zopelee
Copy link

zopelee commented Nov 29, 2023

Migrated from cra (Create React App), we found
yarn remove react-scripts
made HMR works.

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

Successfully merging a pull request may close this issue.