HMR: use environment API to replace ssrLoadModule
// appModule = await server.ssrLoadModule(entry)
appModule = await server.environments.ssr.runner.import(entry);
The main issue is that ssrLoadModule causes hot updates to fail.
Since Hono runs in a Node.js environment, deep submodule imports cannot be collected by Vite's moduleGraph, leading to hot updates not taking effect. (This is my guess, but the problem genuinely exists).
We could consider replacing it with the environment API: https://vite.dev/guide/api-environment-frameworks.html#environments-and-frameworks
I've tested this with Vite 7, and it works, even though the entire Hono application is re-run. However, that's still better than hot updates not working at all.
Hono does not update when duplicate routes are registered; instead, it ignores them. This prevents the use of import.meta.hot.accept for fine-grained HMR. related: https://github.com/honojs/hono/issues/4147, https://github.com/honojs/hono/issues/3817
related: https://github.com/honojs/vite-plugins/issues/124
@hono/vite-dev-server v0.20.0
Thanks. I'll work on it.
@lovetingyuan
Hono does not update when duplicate routes are registered; instead, it ignores them. This prevents the use of
import.meta.hot.acceptfor fine-grained HMR.
I would like to understand your method for enabling fine-grained HMR for Hono. For example, like the flow below (I'm not sure if this is correct or not):
- If
/ais updated, only routes (handlers) registered for/awill be updated. - The routes (handlers) not related to
/awill not be updated.
Yes. In simple terms, it's like this: we assume the user places each different route into a separate module.
app.get('/api/foo', getHandler)
app.post('/api/foo', postHandler)
- In the simple case, if the user modifies the handler's implementation or adds a new routing method, Vite will re-execute this module during HMR. If Hono supported route updates, re-executing this module could achieve the hot update effect (however, Hono currently appends new routes using an array, and due to the principle of closest match, previously registered routes will not use the new handler).
- A more complex scenario is when the user deletes previous routes or changes the path of a route. The ideal way to handle this is to first unload or remove the original route, and then execute the new module. (This is a more unified and standard approach. For a good development experience, some compilation methods might be needed to achieve this, such as automatically injecting
import.meta.hotrelated code, but some conventions might be required to identify which modules are route handlers).
Hot Module Replacement (HMR) is relatively mature in frontend development because frontend frameworks are component-based, with each component being a module, ultimately forming a tree structure. These characteristics make it easy for tools to inject HMR code. In contrast, implementing HMR on the server side does present some challenges, especially without good engineering conventions.
Hi @lovetingyuan @JacobNWolf
Regarding server-side HMR, can you provide a minimal project/code with HMR? It's better not to use Hono, but you can use only a plain app like export default { fetch: () => new Response('Hi') }. I want to imagine the mechanism of server-side HMR before reviewing https://github.com/honojs/hono/pull/4430