remix-run / remix

Build Better Websites. Create modern, resilient user experiences with web fundamentals.
https://remix.run
MIT License
29.81k stars 2.51k forks source link

Vite dev server crashes Remix / React when reloading after finding new dependencies to optimize #10156

Open astonfuture opened 2 days ago

astonfuture commented 2 days ago

Reproduction

https://github.com/astonfuture/remix-vite-optimize-dependency-crash

  1. Run the dev server and force clear vite's cache: npm run dev -- --force or delete node_module/.vite then npm run dev

  2. Navigate to the index http://localhost:5173

  3. Directly navigate to page-two by typing http://localhost:5173/page-two in the address bar and hitting enter

  4. Vite detects the new dependency (lodash-es), runs the optimization and reloads the page which causes it to crash with hydration errors.

System Info

System:
    OS: macOS 14.6.1
    CPU: (12) arm64 Apple M3 Pro
    Memory: 68.77 MB / 18.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 21.7.1 - /opt/homebrew/bin/node
    npm: 10.7.0 - /opt/homebrew/bin/npm
    Watchman: 2024.04.08.00 - /opt/homebrew/bin/watchman
  Browsers:
    Brave Browser: 130.1.71.114
    Chrome: 130.0.6723.60
    Safari: 17.6
  npmPackages:
    @remix-run/cloudflare: ^2.13.1 => 2.13.1 
    @remix-run/dev: ^2.13.1 => 2.13.1 
    @remix-run/react: ^2.13.1 => 2.13.1 
    @remix-run/server-runtime: ^2.13.1 => 2.13.1 
    vite: ^5.4.10 => 5.4.10

Used Package Manager

npm

Expected Behavior

There should not be hydration errors which crash the page as you navigate

Actual Behavior

The reproduction repo above is the official Remix Cloudflare workers template with one extra route added. The new route imports a package (lodash-es) and uses it in the component. When you navigate to that page, vite detects the new package and runs its optimizer which causes a page reload. This causes all manner of errors and the page crashes.

Starting the dev server

> remix vite:dev --force

Forced re-optimization of dependencies
  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h + enter to show help

When navigating to a page with new dependencies:

7:09:40 AM [vite] ✨ new dependencies optimized: lodash-es
7:09:40 AM [vite] ✨ optimized dependencies changed. reloading

Page crashes with a white screen with console errors in the browser such as:

Uncaught TypeError: Cannot read properties of null (reading 'useState')
Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.
Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

Reloading the page after it crashes works fine, leading me to believe this has something to do with the HMR that happens when vite reloads.

clgeoio commented 2 days ago

I have seen a similar thing before, but it was hard to reproduce. I was able to reproduce the behaviour with the above repo using both Safari and Brave browsers 👍

rorcores commented 2 days ago

A fix for this would be great please, thank you

brampono commented 1 day ago

I'm also experiencing this issue! Would love to see a fix 🙏

joshbuddy commented 1 day ago

From what I understand, its causing a hook error due to two versions of React. But this is sort of beyond my React paygrade to solve.

clgeoio commented 1 day ago

@joshbuddy, I found a similar issue on Github that suggested the same thing about different react versions. I tried adding dedupe: ['react', 'react-dom'] to the vite.config, as suggested in that issue, however that did not fix.

I'll keep poking around to see what can I do to find where this other version of React is coming from 👀

joshbuddy commented 1 day ago

My guess at what is happening under the hood is that the two versions of react are coming from two different builds, and both builds are being loaded simultaneously. Conspicuously, if I do a hard refresh, Safari behaves normally again.

astonfuture commented 1 day ago

I think the hard refresh fix is due to the fact that the new optimized dependency is already loaded in node_modules/.vite and so it's available when you refresh. The error is something to do with the fact that the optimization and reload happens in a HMR-ey way while the page is still loaded.