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

HMR always reloading script in SFC when just style is changed if using another vite plugin that transforms the script #211

Closed
8 of 9 tasks
rashfael opened this issue Jul 25, 2023 · 3 comments

Comments

@rashfael
Copy link
Contributor

Related plugins

Describe the bug

When using another vite plugin like @vue-macros/reactivity-transform that transforms the source code, HMR will always update the script part of an SFC even if it's not changed, for example when editing just css. This leads to the whole script being executed again and state being lost.

When changing css I expect this in the console:

[vite] hmr update /src/App.vue?vue&type=style&index=0&scoped=7a7a37b1&lang.css

but with another plugin present I get:

[vite] hmr update /src/App.vue, /src/App.vue?vue&type=style&index=0&scoped=7a7a37b1&lang.css

This most likely happens because handleHotUpdate reads the raw file, parses it, and compares it with the previous version from the cache populated by transformMain, which gets the already transformed code directly from vite. Since the untransformed and transformed source is always different, even if no edits happen, vite-plugin-vue assumes an edit happened and adds the script to the list of affected modules.

I looked a bit into a solution, but neither always caching with the raw source nor always transforming seems straight forward.
Applying the same plugins to the source in the handleHotUpdate hook so it's based on the same code that the transform hook gets is probably preferable, but I couldn't find anything to do that in the vite API.

Reproduction

https://stackblitz.com/edit/vitejs-vite-tzll9a?file=src%2FApp.vue&terminal=dev

Steps to reproduce

  1. Change something in the styles of App.vue
  2. Save file

System Info

System:
    OS: Linux 6.4 Arch Linux
    CPU: (16) x64 AMD Ryzen 7 PRO 6850H with Radeon Graphics
    Memory: 19.42 GB / 30.62 GB
    Container: Yes
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.4.0 - /usr/bin/node
    Yarn: 1.22.19 - /usr/bin/yarn
    npm: 9.8.1 - /usr/bin/npm
    pnpm: 8.6.9 - /usr/bin/pnpm
  Browsers:
    Chromium: 115.0.5790.102

Used Package Manager

npm

Logs

No response

Validations

@rashfael
Copy link
Contributor Author

I found a solution and will submit a PR soon.

rashfael added a commit to rashfael/vite-plugin-vue that referenced this issue Jul 27, 2023
rashfael added a commit to rashfael/vite-plugin-vue that referenced this issue Jul 27, 2023
rashfael added a commit to rashfael/vite-plugin-vue that referenced this issue Jul 27, 2023
@rashfael
Copy link
Contributor Author

rashfael commented Jul 28, 2023

I sketched out two different solutions:

[A] Transform original source with preceding plugins

Code
Since handleHotUpdate reads the original source from the filesystem, we can call the transform hooks of all plugins preceding plugin-vue to get the source to a state that matches what our own transform would get and would write into the cache, at which point the two script versions would match.
This solution could use some more error handling, like wrapping each hook call in a try/catch.

[B] Save original source on our tranform hook

Code
Alternatively, we can save the descriptor of the original source alongside the partially transformed source that we get in our transform hook and compare against that in handleHotUpdate. This solution could also be implemented with a separate "original source" cache.


Which is the better approach? Both have pros and cons.
A populates the cache in a way that's more what is expected by other pieces of code. It's just coincidence that no other code is looking at the cached content while it wrongly contains the original source. But A does not quite call transform hooks of preceding plugins the right way. It's currently missing the plugin context, which I'm not sure how to properly reconstruct. It should do something similar to what vite itself does but I don't want to copy-paste all that code. vue-macros doesn't use the context, so for my specific bug, this detail does not matter.

B does not change current cache behaviour at all, but adds more complexity by additionally caching the original source.

I think A tries to follow the spirit of the cache more.

Other plugins (like svelte) theoretically have the same problem, but using code-transforming macros is pretty niche right now.
The issue that handleHotUpdate does not have access to the same source that transform does might even be tackled in vite itself?

@rashfael
Copy link
Contributor Author

rashfael commented Sep 9, 2023

Fixed by #227

@rashfael rashfael closed this as completed Sep 9, 2023
@github-actions github-actions bot locked and limited conversation to collaborators Sep 24, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant