vite icon indicating copy to clipboard operation
vite copied to clipboard

[Vite 3] `@vitejs/plugin-vue` breaks HMR when used with `vite-plugin-ssr`

Open brillout opened this issue 1 year ago • 11 comments

Describe the bug

HMR doesn't work.

== EDIT == The root cause seems to be that @vitejs/plugin-vue is not respecting ecosystem query parameters. See discussion below. =========

I had a quick look at it: the signal is not being sent to the browser.

Note that the socket message {"type":"update","updates":[{"type":"js-update","timestamp":1658677022754,"path":"/pages/index.page.client.vue?extractExportNames&lang.vue" is not enough (it only updates the ?extractExportNames version of the module).

The terminal says:

5:38:42 PM [vite] hmr update /pages/index.page.client.vue?extractExportNames&lang.vue

But that's not correct as it should say:

5:38:42 PM [vite] hmr update /pages/index.page.client.vue?extractExportNames&lang.vue
5:38:42 PM [vite] hmr update /pages/index.page.client.vue

The last line is missing.

Reproduction

https://github.com/brillout/vps-issue-client-only-hmr

System Info

System:
    OS: Linux 5.10 Debian GNU/Linux 10 (buster) 10 (buster)
    CPU: (2) x64 Intel(R) Celeron(R) N4020 CPU @ 1.10GHz
    Memory: 224.54 MB / 2.71 GB
    Container: Yes
    Shell: 5.0.3 - /bin/bash
  Binaries:
    Node: 18.0.0 - ~/.config/nvm/versions/node/v18.0.0/bin/node
    Yarn: 1.22.17 - /usr/local/bin/yarn
    npm: 8.6.0 - ~/.config/nvm/versions/node/v18.0.0/bin/npm
  Browsers:
    Firefox: 97.0.1
  npmPackages:
    @vitejs/plugin-vue: ^3.0.1 => 3.0.1 
    vite: ^3.0.2 => 3.0.2

Used Package Manager

pnpm

Logs

No response

Validations

brillout avatar Jul 24 '22 15:07 brillout

Really looking forward to seeing this resolved! Using vite-plugin-ssr isn't quite complete without it because HMR doesn't work at all while rendering a page in SPA (client-only) mode.

AaronBeaudoin avatar Jul 28 '22 21:07 AaronBeaudoin

Not sure if this is related to the same issue as this, but I'm having issues getting HMR working with the react plugin on Vite 3, client-side only. Weirdly enough, if I change the vite config while hosting, HMR starts to work. Are you able to get the same behavior with Vue?

I'll open a separate issue if they're not related.

jdpt0 avatar Jul 28 '22 23:07 jdpt0

Also https://twitter.com/youyuxi/status/1552640407057547264.

Not sure if these have the same root cause, but something seems wrong with HMR and Vite 3.

brillout avatar Jul 29 '22 13:07 brillout

Cause:

vite-plugin-ssr module id (url) looks like this: /pages/index.page.client.vue?extractExportNames&lang.vue

plugin-vue assumes that it is a main vue module because there is no type= in query string and updates it instead of module with id /pages/index.page.client.vue:

https://github.com/vitejs/vite/blob/364aae13f0826169e8b1c5db41ac6b5bb2756958/packages/plugin-vue/src/handleHotUpdate.ts#L36-L38

Demivan avatar Jul 29 '22 20:07 Demivan

We can either change vite detection of main module or add type={something} to vite-plugin-ssr module ids

Demivan avatar Jul 29 '22 20:07 Demivan

Ok I see, but I don't think it's vite-plugin-ssr that should add type though, right? Since that's a Vue thing.

From vite-plugin-ssr's side the ?extractExportNames addition does respect prior queries: https://github.com/brillout/vite-plugin-ssr/blob/96531877247328f64a1371b6d4a16a9201c96ccf/vite-plugin-ssr/node/plugin/plugins/extractExportNamesPlugin.ts#L68-L78.

So I'm thinking it's the Vue plugin that can't cope with ?extractExportNames?

brillout avatar Jul 31 '22 12:07 brillout

As a user, one of the things I love about vite-plugin-ssr is that it tries to be as framework agnostic as possible. Forcing it to accommodate some type URL parameter specific to Vue SFC files definitely seems like the wrong solution to me.

It just sounds like the URL patterns in plugin-vue are too narrow.

AaronBeaudoin avatar Aug 05 '22 13:08 AaronBeaudoin

I updated the ticket to reflect the latest findings.

So it seems like a @vitejs/plugin-vue problem.

I think it's probably best if someone familiar with the Vue plugin has a look at this.

brillout avatar Aug 12 '22 08:08 brillout

Yeah it seems plugin-vue is failing to find the correct main module as @Demivan said https://github.com/vitejs/vite/issues/9341#issuecomment-1199914922. (Changing that line to the code below worked)

  const mainModule = modules.find(
    (m) => (!/type=/.test(m.url) || /type=script/.test(m.url)) && !m.url.includes('extractExportNames')
  )

I think there's two ways to fix this but I'm not sure if either of these is a good way.

  1. somehow change this modules.find's callback to obtain the correct main module
    • I'm not sure if this is possible. The main module is normally imported with import foo from './foo.vue' so we could find the one without any queries. But this might break other codes like import foo from './foo.vue?query'.
  2. change this module.find into module.filter
    • I'm not sure if this works.

sapphi-red avatar Aug 16 '22 11:08 sapphi-red

If we want to be agnostic, we should define that any query param that isn't part of the submodule scheme of plugin-vue defines a new module. This sounds like a feature request to me, and it may not be a bad addition. Do all other framework plugins work in this way?

About extractExportNames in particular, if you have vite-plugin-ssr handleHotUpdate hook before plugin-vue, you could narrow down the affected modules to remove it before it reaches plugin-vue. But if it is affected, and you need to leave it in place you have the same issue.

One problem I see with allowing {name}.vue?customQuery, is that the namespace is shared between vue and others. We have this problem everywhere though with queries, maybe it would have been good to namespace them (vue_type, plugin-ssr-extractExportNames).

I think one way out is to define that plugin-vue will reload every module with custom queries, and the plugin is expected to narrow it down if it wants to avoid the reload (that I imagine is what vite-plugin-ssr is already doing). We could try to do this change in 3.1. About the implementation, we could first filter any module that has an unrecognized plugin-vue query.

patak-dev avatar Aug 16 '22 12:08 patak-dev

Just pinging this issue to see if there's been any progress in the last 3 weeks.

AaronBeaudoin avatar Sep 07 '22 19:09 AaronBeaudoin

I made a PR solving this: https://github.com/vitejs/vite/pull/10794.

brillout avatar Nov 05 '22 12:11 brillout