create-react-app icon indicating copy to clipboard operation
create-react-app copied to clipboard

Feedback wanted: New Hot Reloading

Open gaearon opened this issue 5 years ago • 44 comments

I’m working on hot reloading again. Got a very raw alpha version working. It preserves state but only for function components. Works with Hooks.

You can try the alpha version (not production ready, super experimental):

Trying in a New Project (NOT FOR PRODUCTION)

npx create-react-app demo --scripts-version wonky-scripts

Trying in an Existing Project (NOT FOR PRODUCTION)

  1. Replace react-scripts dependency with [email protected]
  2. Keep scripts the same
  3. Delete node_modules/.cache
  4. Run Yarn/npm
  5. Start the project and try editing your React components

What It Looks Like

It’s expected that it will work something like on this gif: https://twitter.com/dan_abramov/status/1139876172903395329

Constraints (Library Authors, Read This!)

If your Hook or Component doesn't work with hot reload, keep in mind that:

  • useMemo and useCallback caches are dropped on every edit (otherwise there wouldn't be a way to edit them 😅). If this breaks your code, consider useRef which gives you a semantics guarantee about not getting re-created. Like here. Usually there's a way to restructure the code to be more resilient.
  • Same goes for useEffect. During hot reload, dependency array will be ignored, and even effects with [] dependencies will re-run. If this breaks your component or Hook, there's likely a way to restructure it to fix this. As a bonus, this will make it easier for you to later add more dependencies to it if needed.
  • However, state and refs get preserved between edits. (As an escape hatch for quickly editing mounting animations and similar, note that users can add // @hot reset to the file they're editing, and this will force state reset. This is not a final syntax but we'll document some way to do it.)

If you need help getting your library working, please post in this thread.

Known issues

  • [ ] Hot reload gets stuck if you save a file without changing it
  • [ ] Editing a file that declares Context doesn't preserve state, currently you need to move Context definition to another module and import it
  • [ ] Errors after hot reload don't always get reported (e.g. try importing a non-existent component and then adding a file without exports)
  • [ ] Lint warnings are confusingly duplicated on save
  • [ ] Some libraries don't work with it (please post which ones in this thread)

Please Share Feedback!

In this thread I’d love to hear first feedback from the brave folks who are willing to try this version on their projects. (Remember: it’s NOT usable in production, it’s just an experiment. This is why it has a funny name.)

Does it work for you? Can you make a gif of how it feels in your app, assuming it’s not a secret?

Thanks!

gaearon avatar Jun 15 '19 13:06 gaearon

Works great, but when changing inside a form from react-hook-form, it dropped the state. It doesn't seem to do this with unmanaged inputs specifically, so it seems like a library collision or something.

Here is a link to the file I was testing with, if you can't recreate it with a basic setup

Here is a webm of it happening

EDIT: After rendering the exact same component with hooks in a separate project, i can't get it to reproduce. I think it has something to do with the components wrapping it. Maybe contextapi? The quest continues...

ar1a avatar Jun 15 '19 13:06 ar1a

Thanks. Any chance you can get a minimal reproducing project up so I can look closer at why it loses state?

gaearon avatar Jun 15 '19 13:06 gaearon

import React, { useContext } from 'react';

const App: React.FC = () => {
  return (
    <form>
      {/* Change component here */}
      <input name="content" />
    </form>
  );
};

const ExampleContext = React.createContext(5);

const Feed = () => {
  const ctx = useContext(ExampleContext);
  return <App />;
};

const WrappedApp = () => (
  <ExampleContext.Provider value={5}>
    <Feed />
  </ExampleContext.Provider>
);

export default WrappedApp;

It has to do with the contexts! not react-hook-form at all.

Webm of it happening with this example!

ar1a avatar Jun 15 '19 13:06 ar1a

Oh yeah — for now you’d have to move context definition into a separate file (and import it from the component). That should work.

gaearon avatar Jun 15 '19 14:06 gaearon

(I do have a version without this limitation but it’s a bit more invasive so I left it out.)

gaearon avatar Jun 15 '19 14:06 gaearon

[EDIT] I removed .npmrc and it worked after that.

For some reason I am ahving trouble pulling wonky scripts:

@@ -67,7 +67,7 @@
-    "react-scripts": "^3.0.1",
+    "wonky-scripts": "0.0.5",
info There appears to be trouble with your network connection. Retrying...
error Couldn't find package "[email protected]" required by `client`  on the "npm" registry.

revert replacing wonky-scripts with react-scripts and yarn has no issues..

Also tried with a tiny app and npm, can't get it work either.

[EDIT] I removed .npmrc and it worked after that.

bugzpodder avatar Jun 15 '19 17:06 bugzpodder

It works perfectly especially with useEffect ;-) Many Thanks 👏🏻

wonky-scripts

le-du6 avatar Jun 15 '19 18:06 le-du6

Ran into an issue hot.js:167 Uncaught TypeError: findHostNodesForHotUpdate is not a function

bugzpodder avatar Jun 15 '19 18:06 bugzpodder

@bugzpodder It is supposed to be there if you use the ReactDOM that this package internally aliases. So this sounds strange.

gaearon avatar Jun 15 '19 18:06 gaearon

hr-hooks Shouldn't the bottom Hooked instance maintain its state ?

EDIT: seems like this is the expected behaviour as react sees a different tree in place of Hooked (replaced with div) hence it unmounts the existing component.If thats the case this is a non issue.

niwsa avatar Jun 15 '19 19:06 niwsa

seems like this is the expected behaviour as react sees a different tree in place of Hooked (replaced with div) hence it unmounts the existing component.If thats the case this is a non issue.

Yeah, that's the reason. Not sure there's anything we can do for that case.

gaearon avatar Jun 15 '19 21:06 gaearon

This is a super cool feature, I’m really excited!

Will it be possible to set it up without CRA in a raw webpack setup?

mlshv avatar Jun 16 '19 05:06 mlshv

@niwsa what happens if you explicitly set the key prop on the Hooked elements?

thetrompf avatar Jun 16 '19 06:06 thetrompf

@thetrompf setting a stable key worked,the instance state was preserved...

niwsa avatar Jun 16 '19 08:06 niwsa

@gaearon still working for me, like the gif in the tweet mentioned above

soufDev avatar Jun 16 '19 13:06 soufDev

@gaearon Adding a side effect (useEffect) on the fly resets the state.Is that expected ?

niwsa avatar Jun 16 '19 18:06 niwsa

Adding a side effect (useEffect) on the fly resets the state.Is that expected ?

Yeah. Any change to call order will reset the state. We could in theory supporting adding Hooks at the end without resetting the state but it doesn't seem super important right now.

Additionally, it's expected that effects will always reset on every edit, even with []. This is intentional. If it breaks your effects you might wanna rethink how they're structured. Since it also makes it difficult for you to add new dependencies to them when needed.

gaearon avatar Jun 16 '19 19:06 gaearon

Will it be possible to set it up without CRA in a raw webpack setup?

Yes, with some work.

gaearon avatar Jun 16 '19 19:06 gaearon

I noticed a bug: it gets "stuck" if you save a file without actually editing it. 😛 Will need to look into this closer to an actual release.

gaearon avatar Jun 16 '19 19:06 gaearon

Reading the documentation for hooks the first time and trying out the examples in that .. I may raise some false alarms with regard to hot reloading 😄 ... If you have some pointers, as to what to watch out for it would be great. UPDATE Just saw the known issues update now :)

niwsa avatar Jun 16 '19 19:06 niwsa

I added some info in the original post about constraints. Hope this is helpful for library authors.

gaearon avatar Jun 16 '19 19:06 gaearon

Couldn't make it work with CRA wonky-scripts:

yarn run v1.15.2
warning ../../package.json: No license field
$ react-scripts start

There might be a problem with the project dependency tree.
It is likely not a bug in Create React App, but something you need to fix locally.

The wonky-scripts package provided by Create React App requires a dependency:

  "jest": "24.7.1"

Don't try to install it manually: your package manager does it automatically.
However, a different version of jest was detected higher up in the tree:

  /Users/adamklein/projects/reusable/node_modules/jest (version: 24.8.0) 

Manually installing incompatible versions is known to cause hard-to-debug issues.

If you would prefer to ignore this check, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That will permanently disable this message but you might encounter other issues.

To fix the dependency tree, try following the steps below in the exact order:

  1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.
  2. Delete node_modules in your project folder.
  3. Remove "jest" from dependencies and/or devDependencies in the package.json file in your project folder.
  4. Run npm install or yarn, depending on the package manager you use.

In most cases, this should be enough to fix the problem.
If this has not helped, there are a few other things you can try:

  5. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
     This may help because npm has known issues with package hoisting which may get resolved in future versions.

  6. Check if /Users/adamklein/projects/reusable/node_modules/jest is outside your project directory.
     For example, you might have accidentally installed something in your home folder.

  7. Try running npm ls jest in your project folder.
     This will tell you which other package (apart from the expected wonky-scripts) installed jest.

If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That would permanently disable this preflight check in case you want to proceed anyway.

P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

adamkleingit avatar Jun 18 '19 17:06 adamkleingit

SKIP_PREFLIGHT_CHECK=true worked though

Couldn't make it work with CRA wonky-scripts:

yarn run v1.15.2
warning ../../package.json: No license field
$ react-scripts start

There might be a problem with the project dependency tree.
It is likely not a bug in Create React App, but something you need to fix locally.

The wonky-scripts package provided by Create React App requires a dependency:

  "jest": "24.7.1"

Don't try to install it manually: your package manager does it automatically.
However, a different version of jest was detected higher up in the tree:

  /Users/adamklein/projects/reusable/node_modules/jest (version: 24.8.0) 

Manually installing incompatible versions is known to cause hard-to-debug issues.

If you would prefer to ignore this check, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That will permanently disable this message but you might encounter other issues.

To fix the dependency tree, try following the steps below in the exact order:

  1. Delete package-lock.json (not package.json!) and/or yarn.lock in your project folder.
  2. Delete node_modules in your project folder.
  3. Remove "jest" from dependencies and/or devDependencies in the package.json file in your project folder.
  4. Run npm install or yarn, depending on the package manager you use.

In most cases, this should be enough to fix the problem.
If this has not helped, there are a few other things you can try:

  5. If you used npm, install yarn (http://yarnpkg.com/) and repeat the above steps with it instead.
     This may help because npm has known issues with package hoisting which may get resolved in future versions.

  6. Check if /Users/adamklein/projects/reusable/node_modules/jest is outside your project directory.
     For example, you might have accidentally installed something in your home folder.

  7. Try running npm ls jest in your project folder.
     This will tell you which other package (apart from the expected wonky-scripts) installed jest.

If nothing else helps, add SKIP_PREFLIGHT_CHECK=true to an .env file in your project.
That would permanently disable this preflight check in case you want to proceed anyway.

P.S. We know this message is long but please read the steps above :-) We hope you find them helpful!

error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

adamkleingit avatar Jun 18 '19 18:06 adamkleingit

Ok, sorry but I have no reproducable scenario because I switched back after a day of trying it out. The biggest problem for me was that the build used to fail on typescript errors and it no longer did that.

hmeerlo avatar Jun 20 '19 09:06 hmeerlo

More concrete information than “fail” would be really helpful. Fail how?

(I haven’t really tried it with TypeScript so not sure what kind of issues it might run into.)

gaearon avatar Jun 20 '19 10:06 gaearon

yeah sorry I totally agree. With react-scripts 3.0.0 my build fails in the terminal whenever I have a typescript error. I run the terminal in my IDE, so I immediately see it and fix the error (even though the IDE points me to the errors as well). But with the wonky-scripts it no longer fails the build in the terminal. It does show the typescript warning though. So I constantly assumed my IDE was wrong with the typescript errors, where it was actually right and the build just didn't show them anymore.

hmeerlo avatar Jun 20 '19 10:06 hmeerlo

Does it require the use of create react app or I can just add it to existing package.json and use ?

tonyfrolov avatar Jun 22 '19 20:06 tonyfrolov

This is great, very exciting. I know a lot of people will love this.

For clarity, I understand that classes will not be supported by this work, even once completed. Is that correct?

mrmckeb avatar Jun 23 '19 14:06 mrmckeb

For clarity, I understand that classes will not be supported by this work, even once completed. Is that correct?

Class-based components would be recreated, preserving the underlaying tree, but not the component itself.

theKashey avatar Jun 24 '19 22:06 theKashey

example

I tested it on this library, it seems like everything is working as expected.

suren-atoyan avatar Jun 25 '19 12:06 suren-atoyan