vite
vite copied to clipboard
Fails to hmr accept virtual modules
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
- run
yarn && yarn dev
- open browser to
http://localhost:3000
- open console
- observe the page reloading when the interval fires
- try the same but for the real module:
const mod = devServer.moduleGraph.getModuleById(path.resolve("./src/bar.js"));
- 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
- [X] Follow our Code of Conduct
- [X] Read the Contributing Guidelines.
- [X] Read the docs.
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- [X] The provided reproduction is a minimal reproducible example of the bug.
Re-opening as fix is reverted in https://github.com/vitejs/vite/pull/13734
I think this should still be open? @bluwy ?
I believe I've run into a similar issue, a virtual module has broken my build https://github.com/vitejs/vite/discussions/16142
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 variousconsole.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 theauto-routes
with a modified time. After, asrouter.ts
is not reloading whenauto-routes
changes anymore, its timestamp is not modified. So SFC doesn't actually reload it. And nothing fetches/reloadsauto-routes
.~~