preactjs/prefresh

prefresh-vite is not preserving the state of a component

SuperDisk opened this issue · 12 comments

I'm making my own prefresh integration for fun, and I decided to compare the behavior of mine to a known working implementation so I could verify how it works. My custom integration (done by basically following the blog post and reading a bit of the prefresh-vite code) works, and when I update a component it preserves state unless I add or remove hooks.

I tried prefresh-vite however and it's actually not working-- I created a sample application with npm init preact and put this code in index.jsx:

import { render } from 'preact';
import {useState} from 'preact/hooks';

export function App() {
  const [ctr, setCtr] = useState(0);
  return (
    <div>
      <p>The counter: {ctr}</p>
      <button onClick={() => setCtr(ctr+1)}>Increment</button>
    </div>
  );
}

render(<App />, document.getElementById('app'));

When I modify something (like just changing some text inconsequentially) it instantly updates in the browser but also resets the counter to 0 every time. I'm not sure what's happening, I put a breakpoint in flushUpdates and it doesn't throw an exception (I don't think).

Hey, it's been a while since I looked at this repo. I tried running the tests which fail on full browser reload as well as made a new vite app with Preact and it worked. Do you have a repro or do you want to work on a fix?

Hmm, so you couldn't reproduce it? The code above is pretty much it. Here's the behavior I'm seeing:

prefresh-.2.mp4

My vite.config.js is the default:

import { defineConfig } from 'vite';
import preact from '@preact/preset-vite';

// https://vitejs.dev/config/
export default defineConfig({
	plugins: [preact()],
});

I just tried creating a Preact app with preact-cli (which I think uses webpack?) and the behavior there seems to work-- that is, updating the code doesn't reset the counter. So it's potentially an issue with the Vite integration?

npm init preact creates a vite one which seemed to work, your vite configuration should work unless you have to explicitly enable prefresh. Or it's a bug in a recent vite version

What does npx vite --version show for you in your npm init preact project?

Not at home atm but the tests use v5 https://github.com/preactjs/prefresh/blob/main/test/fixture/vite/package.json that being said, let's not make this issue a debugging session. I can either look at it in the next few weeks or as you have a working impl feel free to look into it

Just got back to this seems to work just fine on #544

FWIW this still doesn't work for me with a freshly generated npm init preact project. I also changed vite to latest in package.json and it has the same problem.

Mind creating a reproduction then?

preact-reproducer.zip

For me, when I modify anything in index.jsx, the whole state gets reset.

But that's the function that contains render, that's expected because as mentioned in the memory leak issue, ESM HMR creates a new copy of the file. Also creating a repro in stackblitz etc makes it a lot easier to talk about.

i.e. if I move your Counter to a new file, that does not contain render() everything works just fine.

Yep you're right, sorry for the confusion. I guess looking back it should have been obvious that HMR is re-executing all that stuff. Thanks.