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

Disable Fast Refresh #13268

Closed
slava-lu opened this issue May 23, 2020 · 33 comments
Closed

Disable Fast Refresh #13268

slava-lu opened this issue May 23, 2020 · 33 comments
Labels
please add a complete reproduction Please add a complete reproduction.

Comments

@slava-lu
Copy link

How can I revert back to the old (9.3 ) HMR in 9.4? Is there any config parameter?
It looks like fast refresh does not work very well with third party design systems like e.g. baseweb

@Timer
Copy link
Member

Timer commented May 23, 2020

Please provide reproducible code and we can figure out why Fast Refresh isn't working as intended.

@Timer Timer added the please add a complete reproduction Please add a complete reproduction. label May 23, 2020
@montezume

This comment has been minimized.

@montezume

This comment has been minimized.

@idlefingers
Copy link

Some libraries have bugs which cause things to not work well with fast refresh. Here's a reproducible example of xstate's useMachine hook not updating when the page is refreshed: https://github.com/idlefingers/next-xstate-fast-refresh-bug

And issue on xstate's repo: statelyai/xstate#995

@njbarrett
Copy link

I would also like to see the option available to not use fast refresh, its a blocker for me using 9.4

@Timer
Copy link
Member

Timer commented May 29, 2020

@idlefingers I'd argue it's a good thing that Fast Refresh is exposing bugs in libraries, and is not grounds to disable it in Next.js.
Please work with the library author to fix their package!


@njbarrett could you explain why? You didn't provide any reproduction or reason.

@idlefingers
Copy link

@Timer yeah, for sure. Makes it a pain to develop with in the meantime though.

@mrassili
Copy link

mrassili commented Jun 4, 2020

ditto, this should be configurable

@Timer
Copy link
Member

Timer commented Jun 4, 2020

Closing as no reproduction has been provided. Happy to fix any bugs users find and can provide a demo for.

@Timer Timer closed this as completed Jun 4, 2020
@steveruizok
Copy link

@idlefingers I'd argue it's a good thing that Fast Refresh is exposing bugs in libraries, and is not grounds to disable it in Next.js.
Please work with the library author to fix their package!

Do you have a guide for package authors on how to ensure that state works correctly with next's implementation of Fast Refresh? Would any advice from React Native's implementation also work in Next, or are there nuances that authors should know about?

@Timer
Copy link
Member

Timer commented Jun 10, 2020

The impl and nuances are identical to that of React Native.

@nfantone
Copy link

nfantone commented Jul 3, 2020

@Timer Today, I stumbled upon another example of library incompatibility with the new Fast Refresh implementation. use-debounce stops working altogether after any changes to code are made.

You can see a reproduction example here: https://codesandbox.io/s/hardcore-sara-ueu2k

Looks fine on first load, but doesn't call the input callback anymore after refresh.

After initial load

After [Fast Refresh] done

@xnimorz
Copy link

xnimorz commented Jul 3, 2020

Hi @nfantone , @Timer
The main tricky thing, why lots of third party libraries get crashed during fast-refresh updates, is fast-refresh re-calls (with cleanups) all useEffects inside custom hooks, components, etc.

I mean, the following code wouldn't work properly:

function MyComponent() {
  const isComponentUnmounted = useRef(false);
  useEffect(() => () => {isComponentUnmounted.current = true}, []); 
}

In the example above, we change ref to the truth inside useEffect cleanup function (which is handy to prevent unnecessary timers, callbacks, etc).
Usually, this code works correctly. But fast-refresh re-runs all useEffects, which leads to all cleanups call, and then useEffect would be called again.

I've fixed it, by publishing a new version: [email protected].

Here is an example of such fixes, I hope it could be helpful: xnimorz/use-debounce@2ac1732

@xnimorz
Copy link

xnimorz commented Jul 3, 2020

Thank you for the issue and the example!

Also, I've fixed the example by updating the version of use-debounce: https://codesandbox.io/s/hungry-architecture-4z46m?file=/pages/index.js (so that it works now)

@bzztbomb
Copy link

bzztbomb commented Jul 6, 2020

#12753 is an example where it'd be useful to disable fast refresh

@Lwdthe1
Copy link

Lwdthe1 commented Aug 8, 2020

It'd be great if we could disable this. I want to use the new NextJs, but I don't want to go through all my components and add names to my anonymous functions ...

@timneutkens
Copy link
Member

@Lwdthe1 You can run this codemod to update your codebase: https://github.com/vercel/next-codemod#name-default-component

@weyert
Copy link

weyert commented Sep 30, 2020

Yes, is there any update for this? Using Fast Refresh with IE11 can sometime be beneficial to be able to disable it; as Fast Refresh can make IE11 unresponsive is my experience.

@mlynch
Copy link

mlynch commented Oct 15, 2020

Here's an issue I found using Pullstate (https://lostpebble.github.io/pullstate/). On fast-refresh the store will not update so the input value will not change.

Repro:

import Head from 'next/head'
import { Store } from 'pullstate';
import { useCallback, useState } from 'react'

const store = new Store({
  value: 'hello'
});

export default function Home() {
  const value = store.useState(s => s.value);

  const updateValue = useCallback((v) => {
    store.update(s => {
      s.value = v;
    });
  }, [store]);


  return (
    <div className="container">
      <input type="text" value={value} onChange={e => updateValue(e.target.value)} />
    </div>
  )
}

@gaearon
Copy link
Contributor

gaearon commented Oct 15, 2020

Hey folks, sorry to hear that Fast Refresh has been occasionally frustrating. I don't think we've seen any case of the Fast Refresh logic itself being broken in React, but it's definitely true not all libraries are 100% compatible with its constraints today.

However, it so happens that the constraints of Fast Refresh are similar (and slightly stricter) than the existing StrictMode, so getting StrictMode-compatible is a good first step anyway! (For example, pullstate which was just referenced above is not: lostpebble/pullstate#60.)

Another important note is that some of the upcoming React features will take advantage of the same set of constraints. So it's not just about "fixing a library for Fast Refresh" but also about making it compatible with powerful features like built-in animation support which we may add in the following couple of years.

We have documented Fast Refresh constraints here and there's another detailed explanation here. I understand the frustration of having to adjust your code to work within these constraints, but it makes your library more resilient overall, and creates a lot of benefit in the long run.

@osequi
Copy link

osequi commented Dec 5, 2020

@Timer Would this repo help? https://github.com/osequi/test-xstate/releases/tag/0.1.0
It works with browser button navigation and breaks on next/link navigation

Thanks a lot!

@connorlanigan
Copy link

connorlanigan commented Dec 12, 2020

As a workaround, you can disable Fast Refresh for a single file by adding a non-React export, e.g.:

export const thisIsAnUnusedExport = "this export only exists to disable fast refresh for this file";

export function MyComponent() {
	// ...
}

You'll have to add this to every file where you want a full reload to happen on change.

This matches the warning that NextJS will show in the browser console (emphasis added):

[Fast Refresh] performing full reload

Fast Refresh will perform a full reload when you edit a file that's imported by modules outside of the React rendering tree.
You might have a file which exports a React component but also exports a value that is imported by a non-React component file.
Consider migrating the non-React component export to a separate file and importing it into both files.

It is also possible the parent component of the component you edited is a class component, which disables Fast Refresh.
Fast Refresh requires at least one parent function component in your React tree.

(It seems that you don't actually have to import that exported value, you only have to export it.)


Thank you to @gaearon for the context, which helps a lot in understanding the reasoning for this in React.


Regarding NextJS, I'd like to add two use cases where having this functionality natively in NextJS would be useful to developers, and I'm curious if there are other workarounds for these situations:

  • In many cases, "Please work with the library author to fix their package" is not viable. For example, I'm currently trying out a new library, but I don't want to burden its maintainers with opening a Github issue for its incompatibility with Fast Refresh, especially since I don't know if I will continue to be a user of that library in the future. If I do open a Github issue there, it can take potentially months or longer until a fix is released. Disabling Fast Refresh in NextJS would be a temporary workaround until then.

  • Another use case for disabling Fast Refresh is when building something that changes over time - for example, I encountered this issue while working on a long-running animation/visualisation using react-three-fiber (a React wrapper for the 3D graphics library three.js). Here I purposefully want to view the whole animation/pageload from the beginning whenever I change something in the code.

@meglio
Copy link

meglio commented Apr 7, 2021

Dear team, I cannot a) ask every library developer to fix their libraries to work with Next.js Fast Refresh; and b) wait for them to complete the updates.

Why can't we just switch Fast Refresh OFF with a configuration option and move on with using custom 3rd party packages with Next.js?

Please reopen this issue - it is an issue as it's simply not a viable option to get all libraries respect requirements imposed by the Fast Refresh feature of Next.js

For instance, I'd like to turn it off entirely for the whole project as I am using a 3rd party in-house library that is not compatible with Fast Refresh and will not be made so in the next year at least, if at all.

@dustinlacewell
Copy link

I just invested a week building a project with Next just to discover and track down a subtle bug caused by the constraints of Fast Fresh and I'm quite beside myself learning there's just straight up no way to disable it so I can move on.

@akiszka
Copy link

akiszka commented Aug 11, 2021

In my experience, Fast Refresh has been insanely bad. Every time I change the littlest thing, I have to waste at least 10 seconds while my webpage jumps all over the place. Sometimes it just doesn't stop and the only way to fix it is Ctrl+Shift+R. The correct way to go about this would be to research my problem and possibly post a bug report, but I don't have the time or resources to do that and providing a way to disable Fast Refresh would solve my problems instantly. Right now the only viable solution is switching to Gatsby.

I tested this on Linux, on a fresh next.js install with no additional yarn packages on both Chromium (92.0.4515.131, no plugins) and Firefox (90.0.2, no plugins), so I'm almost entirely sure this doesn't stem from a weird configuration issue that I have.

@meglio
Copy link

meglio commented Aug 13, 2021

Dear Next.js team, could you please react to our concerns described in detail above?

@benatkin
Copy link
Contributor

benatkin commented Aug 15, 2021

I've decided to just reload manually (with ⌘L ). I tried Chrome's request blocking, but my settings wouldn't persist, so I decided to use a simple node proxy instead.

proxy.js
import { createServer } from 'http'
import httpProxy from 'http-proxy'
import url from 'url'

const proxyPort = Number(process.env.PROXY_PORT)
const targetPort = Number(process.env.PORT)

const proxy = httpProxy.createProxyServer({
  target: `http://localhost:${targetPort}`,
})

const corsHeaders = {
  'access-control-allow-origin': `http://localhost:${targetPort}`,
  'access-control-allow-methods':
    'GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS',
  'access-control-allow-headers': 'Content-Type, Authorization',
}

proxy.on('proxyRes', function(proxyRes, req, res) {
  if (req.headers.origin === `http://localhost:${targetPort}`) {
    for (const key of Object.keys(corsHeaders)) {
      proxyRes.headers[key] = corsHeaders[key]
    }
  }
})

const server = createServer(function(req, res) {
  const parsedUrl = url.parse(req.url)
  const pathName = parsedUrl.pathname
  if (req.method === 'OPTIONS') {
    res.writeHead(204, { ...corsHeaders })
    res.end()
  } else if (pathName.endsWith('/webpack-hmr') || pathName.endsWith('.hot-update.json')) {
    res.writeHead(500, { ...corsHeaders })
    res.end()
  } else {
    proxy.web(req, res, {
      target: `http://localhost:${targetPort}`,
    })
  }
})

server.listen(proxyPort, '127.0.0.1', () => {
  console.info(`Proxying http://127.0.0.1:${proxyPort} to ${targetPort}...`)
})

Then I run my next server on port 3001 instead:

yarn next dev -p 3001

And to run the proxy:

npm i http-proxy
node proxy.js

@aalvarado
Copy link

I've been trying to set the following on webpack :

devServer: {
  hot: false
}

By following: https://webpack.js.org/guides/hot-module-replacement/

and trying it this way https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config

But it didn't change anything for me. My guess that the setting gets an override somewhere when booting Next or it is ignored.

@arodik
Copy link

arodik commented Nov 12, 2021

I've been trying to set the following on webpack :

devServer: {
  hot: false
}

By following: https://webpack.js.org/guides/hot-module-replacement/

and trying it this way https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config

But it didn't change anything for me. My guess that the setting gets an override somewhere when booting Next or it is ignored.

It doesn't work because Next.js doesn't use Webpack Dev Server

@aalvarado
Copy link

I was able to achieve this by blocking any hmr refresh requests from the browser networking tab.

@meglio
Copy link

meglio commented Nov 14, 2021

So, why is this issue closed? It's unsolved and no official response exists.

@kesupile
Copy link

Could we get an update on whether or not there is a plan to turn fast refresh off? Personally I just find it annoying and would like my app only to rebuild when I explicitly save the file after editing.

@vercel vercel locked as off-topic and limited conversation to collaborators Dec 10, 2021
@leerob
Copy link
Member

leerob commented Dec 13, 2021

@kesupile We are not planning to allow turning off Fast Refresh as it's a critical part of Next.js that we strongly encourage using. We'd also like to fix issues where Fast Refresh isn't working as you'd expect.

I would like my app only to rebuild when I explicitly save the file after editing.

This is how it should work by default – if it isn't, please open a bug with a reproduction and we can take a look 🙏

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
please add a complete reproduction Please add a complete reproduction.
Projects
None yet
Development

No branches or pull requests