Le jour où j'ai failli brûler mes frameworks
J'ai un aveu à vous faire. Il y a quelques années, j'étais un fanatique. Un intégriste du framework. Chaque nouveau projet, chaque petite fonctionnalité, chaque modification du DOM, je sortais l'artillerie lourde : React, Vue, Angular… peu importe, du moment que ça brillait et que ça avait une communauté active. Et puis, un jour, j'ai eu cette mission un peu ingrate : reprendre un vieux site statique, avec quelques îlots de JavaScript spaghetti, et y ajouter une fonctionnalité d'édition de contenu en ligne, un peu à la manière d'un CMS light. Mon premier réflexe ? « Vite, un framework ! ».
Sauf que voilà, le projet était minuscule, le budget aussi, et le temps encore plus. Embarquer un framework entier pour quelques champs éditables et des mises à jour textuelles, c'était comme vouloir tuer une mouche avec un bazooka. Le bundle aurait été plus gros que le site lui-même. C'est là que j'ai commencé à fouiller dans les recoins sombres de mon cerveau, à me souvenir des cours de fac sur le DOM, des API natives que j'avais superbement ignorées pendant des années au profit des abstractions. Et ce que j'ai découvert (ou plutôt redécouvert), a été une véritable révélation. Une claque, même.
MutationObserver : le détective privé de votre DOM
On parle souvent de la réactivité des frameworks, de leur capacité à mettre à jour le DOM de manière efficace. Mais saviez-vous que le navigateur lui-même est un maître dans l'art de l'espionnage ? L'API MutationObserver, par exemple, est une petite merveille trop souvent sous-estimée. Elle permet d'écouter les modifications apportées au DOM, qu'il s'agisse d'ajouts ou de suppressions de nœuds, de changements d'attributs ou de modifications de contenu textuel.
const targetNode = document.getElementById('content-editable');
const config = { attributes: true, childList: true, subtree: true, characterData: true };
const callback = function(mutationsList, observer) {
for(const mutation of mutationsList) {
if (mutation.type === 'childList') {
console.log('Un enfant a été ajouté ou supprimé.', mutation.target);
} else if (mutation.type === 'attributes') {
console.log('L'attribut ' + mutation.attributeName + ' a été modifié sur ' + mutation.target + '.');
} else if (mutation.type === 'characterData') {
console.log('Le contenu textuel a été modifié sur ' + mutation.target + '.');
}
}
};
const observer = new MutationObserver(callback);
observer.observe(targetNode, config);
// Plus tard, pour arrêter l'écoute
// observer.disconnect();
Dans mon cas, pour le site statique, j'utilisais un MutationObserver pour surveiller les zones de texte éditables. Dès qu'un utilisateur tapait quelque chose ou modifiait un attribut (comme un data-attribut pour marquer un élément comme modifié), mon observateur le détectait et déclenchait une sauvegarde automatique en arrière-plan. Fini le polling incessant, finie la complexité d'un système de gestion d'état lourd. Juste le navigateur, faisant son travail, discrètement et efficacement. C'est beau, non ?
ContentEditable : le couteau suisse du contenu en ligne
Parlons du saint graal de l'édition en ligne : l'attribut contenteditable. Je me souviens des premiers sites où j'ai vu ça, je trouvais ça magique. Et pourtant, on dirait que beaucoup de développeurs l'ont relégué aux oubliettes, le considérant comme un outil trop basique ou trop difficile à contrôler. Je dois avouer que j'ai longtemps fait partie de ces sceptiques. Le problème, c'est que par défaut, contenteditable est un peu comme un enfant turbulent : il fait ce qu'il veut, avec des comportements parfois imprévisibles, notamment en matière de mise en forme.
Mais avec un peu de discipline et quelques API bien choisies, on peut le dompter. Mon astuce ? Utiliser document.execCommand() avec parcimonie et surtout, écouter attentivement les événements du DOM.
const editableDiv = document.getElementById('my-editable-content');
editableDiv.contentEditable = 'true';
editableDiv.addEventListener('input', (event) => {
console.log('Contenu modifié :', event.target.innerHTML);
// Ici, vous pouvez sauvegarder le contenu, valider, etc.
});
// Pour ajouter un bouton "Bold" par exemple
document.getElementById('bold-button').addEventListener('click', () => {
document.execCommand('bold', false, null);
});
L'événement input est votre meilleur ami ici. Il vous signale quand le contenu a réellement changé. Et avec execCommand, même si elle est considérée comme "dépréciée" dans certaines discussions (ce qui est souvent une manière polie de dire "attention, c'est puissant, utilisez-le avec discernement"), elle reste incroyablement utile pour des fonctionnalités de base comme le gras, l'italique, les listes, etc. Bien sûr, pour un éditeur WYSIWYG complexe, vous irez vers des bibliothèques plus robustes. Mais pour un besoin simple, pourquoi se compliquer la vie ?
Range et Selection : sculpter le texte avec précision
Et si vous voulez aller plus loin dans la manipulation du texte sélectionné par l'utilisateur ? C'est là qu'interviennent les API Range et Selection. Elles vous permettent de savoir exactement ce que l'utilisateur a sélectionné, de le modifier, de le remplacer, ou même d'y insérer du nouveau contenu. Un cas d'usage concret dans mon projet : permettre à l'utilisateur d'insérer des "variables" prédéfinies (comme [NOM_CLIENT]) dans son texte éditable, au point d'insertion du curseur.
function insertTextAtCursor(text) {
const selection = window.getSelection();
if (!selection.rangeCount) return;
const range = selection.getRangeAt(0);
range.deleteContents(); // Supprime le texte sélectionné s'il y en a
range.insertNode(document.createTextNode(text));
// Déplace le curseur après le texte inséré
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);
}
document.getElementById('insert-variable-button').addEventListener('click', () => {
insertTextAtCursor('[NOM_CLIENT]');
});
C'est une puissance incroyable, disponible nativement dans tous les navigateurs modernes. Pas besoin de dépendances externes, pas de poids supplémentaire pour votre bundle. Juste le bon vieux JavaScript et le DOM, travaillant main dans la main.
La leçon : réapprendre l'essentiel
Cette expérience m'a rappelé une chose fondamentale : en tant que développeurs, on a trop souvent tendance à se jeter sur la dernière bibliothèque à la mode, à la recherche de la solution "clé en main", sans prendre le temps d'explorer ce que le navigateur nous offre déjà. Les API natives pour la modification de document sont incroyablement puissantes et, dans de nombreux cas, largement suffisantes. Elles sont performantes, légères et ne vous lieront pas à un écosystème particulier.
Bien sûr, je ne dis pas qu'il faut jeter les frameworks par la fenêtre. Ils ont leur place, et une place importante, pour les applications complexes et les équipes importantes. Mais pour les petits projets, les améliorations progressives, ou simplement pour mieux comprendre les fondations sur lesquelles nos outils préférés sont construits, un retour aux sources s'impose. Alors, la prochaine fois que vous aurez besoin de manipuler le DOM, avant de taper npm install, prenez une minute. Explorez. Vous pourriez être surpris de ce que vous y trouverez. Et vous économiserez peut-être quelques centaines de kilo-octets (et quelques heures de configuration) au passage. Ne serait-ce pas une victoire en soi ?
Commentaires
Aucun commentaire pour le moment. Soyez le premier !