Création de bibliothèque
Si vous publiez une bibliothèque Vite qui utilise $debug en interne, le paquet publié doit contenir deux variantes parallèles : les consommateurs obtiennent les logs de débogage en développement sans en payer le coût en production. Le plugin produit les deux variantes en un seul build quand vous activez library: { debugBuild: true } :
// vite.config.ts de B (la bibliothèque)
import mtDebug from "@mars-tech/vite-debug-plugin";
export default defineConfig({
plugins: [mtDebug({ library: { debugBuild: true } })],
build: {
lib: { entry: "src/index.ts", formats: ["es", "cjs"] },
rollupOptions: { external: ["vue", "pinia"] },
sourcemap: true,
},
});L'option library remplace allowDebugBuild et libraryPrefix de la 0.6. Les deux fonctionnent encore, avec un avertissement, jusqu'à la 2.0 : voir Options renommées et ce qui change pour les auteurs de bibliothèques.
Sortie du build
Après vite build, le dist/ de la bibliothèque contient :
dist/
├── index.js ← variante standard, chaque appel $debug remplacé par `void 0`
├── index.cjs
├── index.d.ts ← fichier de types unique, partagé
├── index.js.map
├── index.cjs.map
└── debug/
├── index.js ← variante de débogage, appels $debug conservés + shim de secours ajouté en tête
└── index.cjsPourquoi l'arborescence de débogage n'a pas de source maps
L'arborescence debug/ ne contient aucune source map : la seule qui pourrait y être attachée décrirait le chunkdont les appels ont été supprimés, et pour un artefact de développement que l'on lit directement, pas de source map vaut mieux qu'une source map fausse. L'arborescence est copiée depuis le chunk à la dernière étape renderChunk du plugin : tout ce que Vite fait au chunk avant cette étape s'y trouve, la transpilation build.target et la minification par esbuild (par défaut sous Vite 6 et 7) ou terser. Le minificateur par défaut de Vite 8 intervient plus tard et la laisse non minifiée.
Code de développement uniquement
L'arborescence debug/ est du code de développement dont les appels n'ont pas été supprimés : chaque appel $debug y est conservé tel qu'écrit, avec les expressions de ses charges utiles. Elle n'existe que pour être résolue par les serveurs de développement de vos consommateurs, via la condition d'export development (ci-dessous). Si library.debugBuild est activé sur une application, dist/debug/ se trouve à côté des vrais fichiers produits : tenez-la à l'écart de ce que vous déployez.
Les appels des web workers et des scripts que Vite copie au lieu de les regrouper sont supprimés dans les deux variantes : dist/debug/ garde les appels de votre code principal, pas les leurs.
Câbler les exports conditionnels
Déclarez des exports conditionnels dans le package.json de la bibliothèque pour que Vite choisisse automatiquement la bonne variante :
{
"exports": {
".": {
"types": "./dist/index.d.ts",
"development": {
"import": "./dist/debug/index.js",
"require": "./dist/debug/index.cjs"
},
"import": "./dist/index.js",
"require": "./dist/index.cjs"
}
}
}Si vous activez library.debugBuild mais que les exports de votre package.json n'ont aucune condition development qui pointe vers la variante debug/, le plugin affiche un avertissement de build, une fois par build, avec l'extrait exact à coller. Sans cette condition, la variante de débogage est générée mais jamais résolue, et les consommateurs n'ont aucun log de développement.
Résolution de chaque côté
Trois étages sont en jeu : A est ce plugin, B votre bibliothèque, C l'application qui la consomme.
| Étage | Phase | Ce qui se passe |
|---|---|---|
| A plugin (ce paquet) | — | Fournit l'environnement d'exécution et la transformation en double build. |
| B bibliothèque (par ex. un plugin Pinia) | vite build | library: { debugBuild: true } → dist/index.* sans appels, dist/debug/index.* garde les appels et reçoit un shim de secours ajouté automatiquement en tête. |
| C application finale avec A | vite (développement) | Vite choisit la condition development → variante de débogage résolue → l'environnement d'exécution navigateur de A définit le vrai $debug en premier → le shim de secours n'y touche pas → les logs apparaissent. |
| C application finale avec A | vite build | Vite choisit la condition par défaut → variante standard résolue → aucune référence à $debug dans le bundle de C, quoi que C fasse dans son propre code. |
| C application finale sans A | vite (développement) | Variante de débogage résolue → le shim de secours installe un $debug inerte et émet un console.warn unique conseillant d'installer A. |
| C application finale sans A | vite build | Variante standard résolue → appels déjà supprimés → silencieux, aucun plantage. |
Avec library.debugBuild, les consommateurs n'ont rien à savoir de ce plugin. Les auteurs de bibliothèque n'écrivent pas non plus de shim de secours à la main : le plugin l'ajoute en tête de chaque chunk d'entrée de la variante de débogage.
Les appels bruts échouent à l'exécution, pas au build
Une bibliothèque qui livre des appels $debug(...) bruts ne casse pas le build de l'application consommatrice : le build réussit, et la ReferenceError survient à l'exécution, en production, là où se trouve l'appel. Le correctif appartient à la bibliothèque : la construire avec library.debugBuild, qui ne demande aucune configuration côté application. Si vous ne contrôlez pas la bibliothèque, demandez à son auteur, ou installez vous-même une globale inerte (voir Tests pour sa forme).
Appels optionnels et templates Vue
$debug?.(…) est supprimé comme n'importe quel autre appel, quelle que soit la valeur de build.target. Dans la variante debug/, il devient un appel protégé, typeof $debug === "function" ? $debug(…) : void 0, qui saute toujours l'appel quand aucun $debug n'est installé. globalThis?.$debug(…) est traité de la même façon.
Dans une bibliothèque de composants Vue, un appel $debug dans un template (@click="$debug('info', …)") est traité comme un appel dans <script> : la variante standard n'en contient aucun, quels que soient le minificateur et le build.target du build, et dans la variante de débogage il appelle le $debug global de l'application consommatrice (ou le relais brandPrefix). Vous n'avez pas besoin de app.config.globalProperties.$debug.
Le masquage appartient à l'application consommatrice
La variante debug/ ne contient aucune de vos entrées redact / redactDefaults : elles ne masquent que votre propre vite dev. Dans une application consommatrice, la sortie $debug de votre bibliothèque passe par l'instance du plugin de cette application et elle est masquée par sa configuration, ou pas du tout. C'est voulu : une entrée chaîne est généralement le secret lui-même, et debug/ est publié avec votre paquet. Ne passez jamais un secret à $debug dans le code d'une bibliothèque : journalisez plutôt sa présence, sa longueur ou une empreinte.
Déclarer le plugin en dépendance pair optionnelle
Dans le package.json de B, gardez le plugin en dépendance pair (peer dependency) optionnelle, pour que les consommateurs qui ne veulent pas de logs puissent quand même installer votre bibliothèque :
{
"peerDependencies": {
"@mars-tech/vite-debug-plugin": ">=1.0.0"
},
"peerDependenciesMeta": {
"@mars-tech/vite-debug-plugin": { "optional": true }
}
}Marquer les logs de bibliothèque avec brandPrefix
Par défaut, les appels $debug d'une bibliothèque s'affichent avec le préfixe de l'application consommatrice : c'est l'instance du plugin de l'application qui installe le $debug global, et les appels bruts de la bibliothèque héritent du préfixe configuré. Un log venant de l'intérieur de votre bibliothèque apparaît donc comme [App] …, sans indiquer au développeur qu'il provient de votre bibliothèque.
Activez brandPrefix: true avec debugBuild pour que les logs de votre bibliothèque gardent son propre préfixe partout où elle est utilisée :
// vite.config.ts de la bibliothèque
plugins: [
mtDebug({ library: { debugBuild: true, brandPrefix: true }, prefix: "foo" }),
];Chaque log de la bibliothèque s'affiche alors avec foo, quel que soit le préfixe de l'application consommatrice (ici l'application est configurée avec prefix: "bar") :
foo Info [cart/action] - cart.add(Widget ×2) ← depuis la bibliothèque
bar Info - user clicked checkout (src/views/Checkout.vue:14:4) ← depuis l'applicationFonctionnement : la variante de débogage reçoit en tête de chaque chunk un petit $debug local au module, qui remplace la globale dans ce module. Il relaie vers le vrai $debug de l'application, dont la configuration (masquage compris) s'applique comme d'habitude, mais impose { prefix } en dernière écriture : le préfixe de la bibliothèque ne peut pas être remplacé par le consommateur ni par une option d'appel. Votre code reste un simple $debug(...) : rien à retenir à chaque appel, rien que les consommateurs puissent désactiver. Si l'application consommatrice n'a aucun $debug, ce relais avertit une fois puis ne fait rien (même sécurité que le shim de secours).
Un build de débogage umd ou iife est destiné à une balise <script>, où les déclarations de premier niveau sont partagées par toute la page. Le relais et le chunk y sont enveloppés dans un bloc, pour que le relais reste local à votre bibliothèque : les appels $debug propres à la page gardent le préfixe de l'application, et deux bibliothèques marquées de cette façon se chargent côte à côte. Les sorties es et cjs ont déjà leur propre portée de module.
Les formes marquées sont l'appel de base, $debug.ns(...) et $debug.assert(...). Les fonctions utilitaires (time, count, group) ne prennent pas d'options d'appel : leur sortie garde le préfixe du consommateur. brandPrefix n'a aucun effet sans debugBuild, et le plugin avertit quand il est réglé ainsi.
Les logs de bibliothèque n'ont pas de localisation source
Le relais règle showSource: false par défaut : une ligne marquée s'affiche donc sans le (fichier:ligne:colonne) final. Une position à l'intérieur de votre bibliothèque n'est pas exploitable par le développeur consommateur (il ne débogue pas vos internes), et comme le relais enveloppe chaque appel, le parcours de pile de l'environnement d'exécution aurait de toute façon désigné le cadre de pile du relais plutôt que votre site d'appel. Si vous la voulez malgré tout, passez explicitement { showSource: true } à l'appel : cette option reste prioritaire.
Voir aussi l'option library et le Dépannage.