vitejs / vite-plugin-vue

Vite Vue Plugins
MIT License
498 stars 153 forks source link

Allow configuring how the hmr Id is generated in @vitejs/plugin-vue #21

Open PPetau opened 2 years ago

PPetau commented 2 years ago

Description

I was trying to import a Vue component from another instance of vite.

The problem lies here: https://github.com/vitejs/vite/blob/c78e4099e502876a2ab23fd8163455d8172ff5b7/packages/plugin-vue/src/utils/descriptorCache.ts#L30 Due to how the id on the descriptor is generated it is impossible to me to change how the css-Scope/__hmrId ... will be generated resulting in a broken hmr runtime and conflicting css.

Using the isProduction flag is not viable because it disables the hmr runtime on vue components.

Suggested solution

Could we introduce another flag or an option to specify how this Id would generate?

There could be an Option that works like isProduction to include the source when creating the id hash

Alternative

No response

Additional context

Repro in StackBlitz: https://stackblitz.com/edit/vitejs-vite-kr3fdz?file=vite-1/index.html

If we then edit the vite-1/src/App.vue the other app gets broken because their internal _hmrId is the same.

Validations

bluwy commented 2 years ago

This feels like a very niche usecase which many plugins won't support, so it's not only a problem with plugin-vue. What is your usecase needing to accessing Vue components from a different server?

PPetau commented 2 years ago

I am trying to create some kind of micro-frontend where I am importing other Vue apps from different packages within a workspace. I would like to have multiple vite instances serving the different projects so that the main application can dynamically import these and still utilize the hot reload functionality. Because how the projects are structured, the logic determining how the _hmrId is generated, results in the same id for every component that have the same root-relative path (ex. src/App.vue => "7a7a37b1").

I have written one workaround that tries to rewrite the generated id after the plugin transformed the SFC, but was unable to catch every place where the generated id is used.

arnoson commented 2 years ago

@PPetau could you share your workaround? I have a similar usecase: I have a production app that is extendable with plugins. While the user develops a new plugin I want HMR. I can consume the plugin component in my app directly from the plugin's vite dev server, but the ids won't match so only global styles and scripts are working right now.

PPetau commented 2 years ago

Hi @arnoson, this is the snipped that runs in the transform hook and replaces the generated hmrIds (only of the .vue files).

const hmrUniqueIdentifier = "your_custom_id_namespace";

if (/\.vue/.test(id)) {
  if (code.includes("_sfc_main.__hmrId")) {
    const magicString = new MagicString(code);
    const hmrId = code.match(
      /_sfc_main\.__hmrId\s*\=\s*["'](.+)["']/m
    )?.[1];
    if (hmrId) {
      magicString.replace(
        new RegExp(hmrId, "g"),
        hmrId + hmrUniqueIdentifier
      );
    return {
      code: magicString.toString(),
      map: magicString.generateMap()
    };
  }
}