vitejs/vite

"vite-plugin-react can't detect preamble. Something is wrong." when using styled-components

RichardWeug opened this issue ยท 9 comments

Describe the bug

When I'm rendering a styled component, I get the following error:
"Uncaught Error: vite-plugin-react can't detect preamble. Something is wrong. See vitejs/vite-plugin-react#11 (comment)"

Reproduction

When creating a new project I don't run into this problem. However, I'm trying to integrate vite into my existing project. Everything seems to work fine, but when I render a styled-component it crashes.

System Info

  • vite version: "^2.0.0-beta.65"
  • Operating System: macOS Big Sur
  • Node version: v14.15.5
  • Package manager (npm/yarn/pnpm) and version: npm 6.14.11

Logs (Optional if provided reproduction)

vite:cache [304] /@vite/client +0ms
vite:time 1ms /@vite/client +25s
vite:load 7ms [fs] /assets/js/website.tsx +25s
vite:transform 22ms /assets/js/website.tsx +25s
vite:time 33ms /assets/js/website.tsx +33ms
vite:hmr [file change] var/cache/dev/profiler/index.csv +106ms
vite:hmr [no modules matched] var/cache/dev/profiler/index.csv +1ms
vite:hmr [file change] var/log/dev.log +0ms
vite:hmr [no modules matched] var/log/dev.log +0ms
vite:cache [304] /node_modules/vite/dist/client/env.js +172ms
vite:time 1ms /node_modules/vite/dist/client/env.js +139ms
vite:hmr [file change] var/cache/dev/profiler/index.csv +145ms
vite:hmr [no modules matched] var/cache/dev/profiler/index.csv +1ms
vite:cache [304] vite/dynamic-import-polyfill +15ms
vite:time 1ms /@id/vite/dynamic-import-polyfill +16ms
vite:load 2ms [fs] /assets/js/components/dashboard/Dashboard.tsx +181ms
vite:hmr [self-accepts] assets/js/components/dashboard/Dashboard.tsx +24ms
vite:transform 20ms /assets/js/components/dashboard/Dashboard.tsx +178ms
vite:time 23ms /assets/js/components/dashboard/Dashboard.tsx +23ms
vite:cache [304] /@react-refresh +29ms
vite:time 0ms /@react-refresh +5ms
vite:hmr [file change] var/cache/dev/profiler/index.csv +76ms
vite:hmr [no modules matched] var/cache/dev/profiler/index.csv +0ms
vite:hmr [file change] var/log/dev.log +0ms
vite:hmr [no modules matched] var/log/dev.log +0ms
vite:time 1ms /node_modules/.vite/chunk.IXVMP6XR.js.map +103ms
vite:time 1ms /node_modules/.vite/chunk.IXVMP6XR.js.map +60ms
vite:hmr [file change] var/log/dev.log +320ms
vite:hmr [no modules matched] var/log/dev.log +0m

If a newly created project works as expected with styled-components, then you need to provide an actual reproduction.

I managed to reproduce my issue with a simple example. I pushed my code to the following repository:
https://github.com/RichardWeug/vite-backend-integration-preamble-bug

I'm starting my webserver using PHP, using the following command:
php -S localhost:8000

I start vite using npx, using the following command:
npx vite

When you navigate to localhost:8000, it gives the error I described.

Ah, so you are serving the HTML over your PHP server. Unfortunately because of this, Vite plugins (in this case @vitejs/plugin-react-refresh) won't be able to inject its HTML modifications.

Since you are not using Node.js, you can't leverage Vite's programmatic API to inject those HTML modifications, so in this case you'll have to do it manually inject this code into your HTML:

<script type="module">
import RefreshRuntime from "/@react-refresh"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>

This isn't a bug per-se, but we probably want to consider how to improve that.

Ah, so you are serving the HTML over your PHP server. Unfortunately because of this, Vite plugins (in this case @vitejs/plugin-react-refresh) won't be able to inject its HTML modifications.

Since you are not using Node.js, you can't leverage Vite's programmatic API to inject those HTML modifications, so in this case you'll have to do it manually inject this code into your HTML:

<script type="module">
import RefreshRuntime from "/@react-refresh"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>

This isn't a bug per-se, but we probably want to consider how to improve that.

Thanks. I've added the code. However, this doesn't seem to fix the issue. I'm still getting the same error.

<script type="module">
    import RefreshRuntime from "/@react-refresh"
    RefreshRuntime.injectIntoGlobalHook(window)
    window.$RefreshReg$ = () => {}
    window.$RefreshSig$ = () => (type) => type
    window.__vite_plugin_react_preamble_installed__ = true
</script>
<script type="module" src="http://localhost:3000/@vite/client"></script>
<script type="module" src="http://localhost:3000/assets/js/website.js"></script>

Hmm probably import RefreshRuntime from "http://localhost:3000/@react-refresh"

Thanks. That fixes it! However, I'm getting a different error now: "Uncaught ReferenceError: global is not defined". Is there some sort of setup I'm missing?

Thanks. That fixes it! However, I'm getting a different error now: "Uncaught ReferenceError: global is not defined". Is there some sort of setup I'm missing?

Declaring a global var before the scripts solved this for me.

<script>var global = window</script>

Since you are not using Node.js, you can't leverage Vite's programmatic API to inject those HTML modifications, so in this case you'll have to do it manually inject this code into your HTML:

Just wanted to chime and add that this error could also happen when using certain micro-frontend frameworks.

Since each micro front-end can be its own ViteJS app (and server), the HTML that the user sees might not be handled or served by Vite at all.

Vite might only serve an entry point that can be mounted if the root application decides that it should.

One thing I was thinking, without full knowledge about what is possible, is that the code mentionned above perhaps could be programmatically injected by JavaScript instead of being appended in the Vite HTML entry point so that fast refresh works even when the app is mounted on a different server than the Vite server.

That way, perhaps it could be possible to make it so that multiple Vite micro front-end all have independent fast refresh.
This could also be a manual step since it's an edge case like import 'vite/fast-refresh' inside the micro front-end.

(mostly thinking out loud here)

Tagging you @csr632 after I read this comment where you mentioned you were looking for edge cases.

Other resources:

This issue has been locked since it has been closed for more than 14 days.

If you have found a concrete bug or regression related to it, please open a new bug report with a reproduction against the latest Vite version. If you have any other comments you should join the chat at Vite Land or create a new discussion.