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

Fails to hmr accept virtual modules #12912

Open
7 tasks done
Janpot opened this issue Apr 19, 2023 · 4 comments · Fixed by #13073 or mui/toolpad#3193
Open
7 tasks done

Fails to hmr accept virtual modules #12912

Janpot opened this issue Apr 19, 2023 · 4 comments · Fixed by #13073 or mui/toolpad#3193
Labels
feat: hmr p3-minor-bug An edge case that only affects very specific usage (priority)

Comments

@Janpot
Copy link

Janpot commented Apr 19, 2023

Describe the bug

I'm trying to hot reload a virtual module, but it doesn't seem to be able to accept it:

// server.mjs
import { createServer } from "vite";

async function main() {
  const devServer = await createServer({
    clearScreen: false,
    plugins: [
      {
        name: "my-plugin",
        async resolveId(id) {
          if (id === "virtual:my-plugin:foo") {
            return "\0virtual:my-plugin:foo";
          }
          return null;
        },
        async load(id) {
          if (id === "\0virtual:my-plugin:foo") {
            return `export default Math.random();`;
          }
          return null;
        },
      },
    ],
  });

  await devServer.listen(3000);
  devServer.printUrls();

  setInterval(() => {
    const mod = devServer.moduleGraph.getModuleById("\0virtual:my-plugin:foo");
    if (mod) {
      console.log("reloading virtual module");
      devServer.reloadModule(mod);
    }
  }, 2000);
}

main();
// bar.js
export default Math.random();
// main.js
import foo from "virtual:my-plugin:foo";
import bar from "./bar";

console.log("loading foo ", foo);
console.log("loading bar ", bar);

if (import.meta.hot) {
  import.meta.hot.accept("virtual:my-plugin:foo", (newFoo) => {
    console.log(`hmr accepting ${newFoo.default} from "virtual:my-plugin:foo"`);
  });

  import.meta.hot.accept("./bar", (newBar) => {
    console.log(`hmr accepting ${newBar.default} from "./bar"`);
  });
}

Reproduction

https://github.com/Janpot/vitejs-virtual-hmr

Steps to reproduce

  1. run yarn && yarn dev
  2. open browser to http://localhost:3000
  3. open console
  4. observe the page reloading when the interval fires
  5. try the same but for the real module: const mod = devServer.moduleGraph.getModuleById(path.resolve("./src/bar.js"));
  6. observe the module being hot accepted

I tried using /@id/__x00__virtual:my-plugin:foo, but that doesn't work neither

System Info

System:
    OS: macOS 13.3.1
    CPU: (8) arm64 Apple M1
    Memory: 101.66 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 16.20.0 - ~/.nvm/versions/node/v16.20.0/bin/node
    Yarn: 1.22.19 - ~/.nvm/versions/node/v16.20.0/bin/yarn
    npm: 8.19.4 - ~/.nvm/versions/node/v16.20.0/bin/npm
  Browsers:
    Chrome: 112.0.5615.121
    Firefox: 111.0.1
    Safari: 16.4
  npmPackages:
    vite: ^4.3.0-beta.2 => 4.3.0-beta.8

Used Package Manager

yarn

Logs

No response

Validations

@bluwy
Copy link
Member

bluwy commented Aug 3, 2023

Re-opening as fix is reverted in #13734

@patricklx
Copy link
Contributor

I think this should still be open? @bluwy ?

@Janpot Janpot reopened this Feb 23, 2024
@grctest
Copy link

grctest commented Apr 14, 2024

I believe I've run into a similar issue, a virtual module has broken my build #16142

@jods4
Copy link
Contributor

jods4 commented Sep 6, 2024

Please ignore everything I wrote below

I turns out that in my Vite config I got confused between invalidating the server module, which leads to the transitive reloading that I observed below, and actively pushing an HMR update with moduleGraph.reloadModule(mod).

If I push an HMR everything works as expected.

I think I've run into this, or a very similar issue.

I'm using unplugin-vue-router to generate a virtual routes module.

My problem is that when I save a Vue SFC component, the routes are invalidated, which reloads the module that creates the router, then there are multiple routers cached in various places in the application in things quickly break down.

I have used import.meta.hot.accept("__vue-router/auto-routes", newRoutes => ...) to create a HMR boundary and manually handle the route table change without actually reloading the module and creating a new router.

This almost works, but the following seems to be a bug:

  • hot.accept("__vue-router/auto-routes", ...) partially works: my module is not reloaded anymore. If I remove this line or change the module name, my module is reloaded again. So the HMR boundary seems to work.
  • Yet the callback is not called. I've put debugger and various console.log(..) in the callback and they're never hit. This means that I cannot manually process the new module changes.

EDIT: one observation that might be useful is that the __vue-router/auto-routes is not reloaded in front-end (looking at >Network tab), which explains why the callback is not called.

Before, the SFC would reload my router.ts with a modified time, which itself reloads the auto-routes with a modified time.
After, as router.ts is not reloading when auto-routes changes anymore, its timestamp is not modified. So SFC doesn't actually reload it. And nothing fetches/reloads auto-routes.~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat: hmr p3-minor-bug An edge case that only affects very specific usage (priority)
Projects
None yet
5 participants