Le remplacement de module à chaud (HMR) vous permet de mettre à jour des modules dans une application en cours d'exécution sans avoir besoin d'un rechargement complet de la page. Cela préserve l'état de l'application et améliore l'expérience de développement.
NOTE
Le HMR est activé par défaut lors de l'utilisation du serveur de développement full-stack de Bun.Référence de l'API import.meta.hot
Bun implémente une API HMR côté client calquée sur l'API import.meta.hot de Vite. Elle peut être vérifiée avec if (import.meta.hot), ce qui permet l'élimination de code mort en production.
if (import.meta.hot) {
// Les API HMR sont disponibles.
}Cependant, cette vérification n'est souvent pas nécessaire car Bun éliminera le code mort de tous les appels aux API HMR dans les constructions de production.
// Tout cet appel de fonction sera supprimé en production !
import.meta.hot.dispose(() => {
console.log("dispose");
});NOTE
L'API HMR est toujours en cours de développement. Certaines fonctionnalités sont manquantes. Le HMR peut être désactivé dans `Bun.serve` en définissant l'option development à `{ hmr: false }`.Méthodes de l'API
| Méthode | Statut | Notes |
|---|---|---|
hot.accept() | ✅ | Indique qu'une mise à jour à chaud peut être remplacée gracieusement. |
hot.data | ✅ | Persiste les données entre les évaluations de module. |
hot.dispose() | ✅ | Ajoute une fonction de rappel exécutée lorsqu'un module est sur le point d'être remplacé. |
hot.invalidate() | ❌ | |
hot.on() | ✅ | Attache un écouteur d'événement |
hot.off() | ✅ | Supprime un écouteur d'événement de on. |
hot.send() | ❌ | |
hot.prune() | 🚧 | NOTE : Le rappel n'est actuellement jamais appelé. |
hot.decline() | ✅ | No-op pour correspondre à import.meta.hot de Vite |
import.meta.hot.accept()
La méthode accept() indique qu'un module peut être remplacé à chaud. Lorsqu'elle est appelée sans arguments, elle indique que ce module peut être remplacé simplement en réévaluant le fichier. Après une mise à jour à chaud, les importateurs de ce module seront automatiquement corrigés.
// index.ts
import { getCount } from "./foo.ts";
console.log("count is ", getCount());
import.meta.hot.accept();
export function getNegativeCount() {
return -getCount();
}Cela crée une limite de rechargement à chaud pour tous les fichiers que index.ts importe. Cela signifie que chaque fois que foo.ts ou l'une de ses dépendances est enregistré, la mise à jour remontera jusqu'à index.ts qui sera réévalué. Les fichiers qui importent index.ts seront ensuite corrigés pour importer la nouvelle version de getNegativeCount(). Si seul index.ts est mis à jour, seul ce fichier sera réévalué et le compteur dans foo.ts est réutilisé.
Cela peut être utilisé en combinaison avec import.meta.hot.data pour transférer l'état du module précédent vers le nouveau.
Avec rappel
Lorsqu'un rappel est fourni, import.meta.hot.accept fonctionnera comme dans Vite. Au lieu de corriger les importateurs de ce module, il appellera le rappel avec le nouveau module.
export const count = 0;
import.meta.hot.accept(newModule => {
if (newModule) {
// newModule est undefined lorsqu'une SyntaxError se produit
console.log("mis à jour : count est maintenant ", newModule.count);
}
});Accepter d'autres modules
import { count } from "./foo";
import.meta.hot.accept("./foo", () => {
if (!newModule) return;
console.log("mis à jour : count est maintenant ", count);
});Indique qu'un module de dépendance peut être accepté. Lorsque la dépendance est mise à jour, le rappel sera appelé avec le nouveau module.
Avec plusieurs dépendances
import.meta.hot.accept(["./foo", "./bar"], newModules => {
// newModules est un tableau où chaque élément correspond au module mis à jour
// ou undefined si ce module avait une erreur de syntaxe
});Indique que les modules de plusieurs dépendances peuvent être acceptés. Cette variante accepte un tableau de dépendances, où le rappel recevra les modules mis à jour, et undefined pour ceux qui avaient des erreurs.
import.meta.hot.data
import.meta.hot.data maintient l'état entre les instances de module pendant le remplacement à chaud, permettant le transfert de données des versions précédentes vers les nouvelles. Lorsque import.meta.hot.data est écrit, Bun marquera également ce module comme capable de s'auto-accepter (équivalent à appeler import.meta.hot.accept()).
import { createRoot } from "react-dom/client";
import { App } from "./app";
const root = (import.meta.hot.data.root ??= createRoot(elem));
root.render(<App />); // réutiliser une racine existanteEn production, data est inline pour être {}, ce qui signifie qu'il ne peut pas être utilisé comme support d'état.
import.meta.hot.dispose()
Attache un rappel on-dispose. Ceci est appelé :
- Juste avant que le module ne soit remplacé par une autre copie (avant que le suivant ne soit chargé)
- Après que le module est détaché (suppression de toutes les importations vers ce module, voir
import.meta.hot.prune())
const sideEffect = setupSideEffect();
import.meta.hot.dispose(() => {
sideEffect.cleanup();
});Retourner une promesse retardera le remplacement du module jusqu'à ce que le module soit disposé. Tous les rappels dispose sont appelés en parallèle.
import.meta.hot.prune()
Attache un rappel on-prune. Ceci est appelé lorsque toutes les importations vers ce module sont supprimées, mais que le module était précédemment chargé.
Cela peut être utilisé pour nettoyer les ressources qui ont été créées lorsque le module a été chargé. Contrairement à import.meta.hot.dispose(), cela correspond beaucoup mieux avec accept et data pour gérer les ressources avec état. Un exemple complet gérant un WebSocket :
import { something } from "./something";
// Initialiser ou réutiliser une connexion WebSocket
export const ws = (import.meta.hot.data.ws ??= new WebSocket(location.origin));
// Si l'import du module est supprimé, nettoyer la connexion WebSocket.
import.meta.hot.prune(() => {
ws.close();
});import.meta.hot.on() et off()
on() et off() sont utilisés pour écouter les événements du runtime HMR. Les noms d'événements sont préfixés avec un préfixe pour que les plugins n'entrent pas en conflit les uns avec les autres.
import.meta.hot.on("bun:beforeUpdate", () => {
console.log("avant une mise à jour à chaud");
});Lorsqu'un fichier est remplacé, tous ses écouteurs d'événements sont automatiquement supprimés.
Événements intégrés
| Événement | Émis quand |
|---|---|
bun:beforeUpdate | avant qu'une mise à jour à chaud ne soit appliquée. |
bun:afterUpdate | après qu'une mise à jour à chaud soit appliquée. |
bun:beforeFullReload | avant qu'un rechargement complet de page ne se produise. |
bun:beforePrune | avant que les rappels prune ne soient appelés. |
bun:invalidate | lorsqu'un module est invalidé avec import.meta.hot.invalidate() |
bun:error | lorsqu'une erreur de construction ou d'exécution se produit |
bun:ws:disconnect | lorsque la connexion WebSocket HMR est perdue. Cela peut indiquer que le serveur de développement est hors ligne. |
bun:ws:connect | lorsque le WebSocket HMR se connecte ou se reconnecte. |
NOTE
Pour la compatibilité avec Vite, les événements ci-dessus sont également disponibles via le préfixe `vite:*` au lieu de `bun:*`.