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

Plugin causes Vite to hang indefinitely after build with React 19.0.0 #3

Open
tim-meredith-acoa opened this issue Jan 17, 2025 · 5 comments

Comments

@tim-meredith-acoa
Copy link

Something about the new version of React seems to interact negatively with this plugin. When I try to use the plugin with React 19.0.0, it will build successfully, but then after the build is done, Vite just doesn't exit, it stays blocking the terminal and seemingly doing nothing, which is mildly annoying in development, but more importantly it completely breaks automated building for deployment.

Steps to reproduce

Make a new React project with Vite:

npm create vite@latest . -- --template react-ts

Go into package.json, and update the following packages to version 19.0.0:

  • react
  • react-dom
  • @types/react
  • @types/react-dom

and then run npm install to install the new version.

Install the plugin:

npm install -D vite-prerender plugin

Replace vite.config.ts with the following:

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { vitePrerenderPlugin } from 'vite-prerender-plugin'

// https://vite.dev/config/
export default defineConfig({
  plugins: [
    react(),
    vitePrerenderPlugin({
      renderTarget: '#root'
    })
  ]
})

Add the prerender attribute to the <script> tag in index.html.

Replace src/main.tsx with the following:

import { StrictMode } from 'react'
import { hydrateRoot } from 'react-dom/client'
import './index.css'
import App from './App.tsx'

const Root = () => {
  return <StrictMode>
    <App />
  </StrictMode>
}

if (typeof window !== 'undefined') {
  hydrateRoot(document.getElementById('root')!, <Root />)
}

export async function prerender() {
  const { renderToString } = await import('react-dom/server')
  const html = renderToString(<Root />)
  return { html }
}

Finally, run npm run build. The build will be successful, but after it finishes, Vite will never exit.

> [email protected] build
> tsc -b && vite build

vite v6.0.7 building for production...
✓ 40 modules transformed.
dist/index.html                           1.09 kB │ gzip:  0.53 kB
dist/assets/react-CHdo91hT.svg            4.13 kB │ gzip:  2.05 kB
dist/assets/main-n_ryQ3BS.css             1.39 kB │ gzip:  0.71 kB
dist/assets/index-CPPIKvJG.js             0.74 kB │ gzip:  0.41 kB │ map:   0.10 kB
dist/assets/server.browser-DcgWWkx7.js  160.51 kB │ gzip: 49.25 kB │ map: 659.32 kB
dist/assets/main-nV0DskNB.js            187.10 kB │ gzip: 59.33 kB │ map: 871.42 kB
✓ built in 1.68s

I'd be happy to help debug this more, but I don't really know what else to try. One thing I've observed is that the import of react-dom/server does seem to be important, because if I keep everything else the same and change the prerender function to this:

export async function prerender() {
  //const { renderToString } = await import('react-dom/server')
  //const html = renderToString(<Root />)
  return { html: "<div>test</div>" }
}

Then it will build without hanging. Hope that helps narrow things down, and let me know if you want me to try out anything else.

@tim-meredith-acoa
Copy link
Author

I wanted to make sure it wasn't just from me doing something weird, so I tried to just build the React example from this repo with the version bumped, but as it turns out, that example doesn't build anyway, even unmodified, it just errors out with Package subpath 'undefined' is not defined by "exports". Not sure what exactly is going on there, maybe it's a Node version mismatch or something.

@tim-meredith-acoa
Copy link
Author

Turns out that error doesn't happen if you also bump the vite-prerender-plugin version before building. If you bump the plugin version and build, it's successful. If you bump both the plugin version and the react version, it still builds fine, but then it exhibits the problem I started out describing here, it hangs indefinitely.

@rschristian
Copy link
Member

The examples haven't been touched in a long time and are missing lock files, I'm guessing something broke at some point or another. Will get them fixed/updated, thanks for mentioning!

As for the React issue, interesting. The plugin writes the files to disk and successfully exits, this might be a Vite issue? I'm not sure what react-dom/server could be doing to not allow Vite to exit though, weird.

@rschristian
Copy link
Member

rschristian commented Jan 17, 2025

I think the best I can recommend for the moment is a silly plugin to force Vite to exit:

function closePlugin() {
    return {
        name: 'close-plugin',
        closeBundle() {
            process.exit(0);
        }
    }
}

Seems like a bug in Vite, perhaps due to something odd that react-dom@19 is doing, not sure. Doesn't appear to be any issue with the plugin that I can see. I was wrong, executing the bundle in Node, outside of Vite, also causes the process to get stuck. This might be a React bug?

@rschristian
Copy link
Member

Okay, this looks indeed like a React bug.

If you run a build (so that node_modules/vite-prerender-plugin/headless-prerender is populated), you can then add a index.js file to the root of your project like so:

import { prerender } from './node_modules/vite-prerender-plugin/headless-prerender/index-<hash>.js';

globalThis.__VITE_PRELOAD__ = [];

const res = await prerender({ url: '/' });
console.log(res);

console.log(process._getActiveHandles());
console.log(process._getActiveRequests());

If you substitute in your file hash and run node index.js (which is basically what this plugin does), you'll see leftover streams that React has not cleaned up. These block Vite from exiting, and will also block node from completing as well. You'll probably need to take this upstream to them, they're not handling this properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants