pmmmwh / react-refresh-webpack-plugin

A Webpack plugin to enable "Fast Refresh" (also previously known as Hot Reloading) for React components.
MIT License
3.13k stars 194 forks source link

fix: Avoid unnecessary memory leaks due to prevExports #766

Closed naruaway closed 1 year ago

naruaway commented 1 year ago

When fast-refreshing the following code:

const DATA = Array.from({ length: 100000 }, (_, i) => Math.random());

export const App = () => {
  return (
    <div>
      <div>REWRITE_HERE</div>
      <div>{DATA.length}</div>
    </div>
  );
};

each refresh will not purge the previous DATA since we chain prevExports, which references App, which closes over DATA. For reproducible example and more detailed explanation, please check https://github.com/naruaway-sandbox/fast-refresh-hmr-memory-leak-demo

Historical list of DATA is retained like the following via prevExports:

prev-exports-chain-leak

This PR breaks the chain by only passing absolutely necessary data across fast-refreshes, which is signature: string[] and isReactRefreshBoundary: boolean. So it will be impossible to accidentally form this kind of reference chain.

Note that I also tried to fix the same issue in Next.js https://github.com/vercel/next.js/pull/53797

Verification

I verified using this PR with https://github.com/naruaway-sandbox/fast-refresh-hmr-memory-leak-demo and confirmed that Fast Refresh itself is working well while not causing the memory leak