- Cash est une très petite bibliothèque alternative à jQuery qui fournit une syntaxe de style jQuery pour manipuler le DOM dans les navigateurs modernes IE11+
- Elle exploite les fonctionnalités des navigateurs modernes pour réduire la base de code et permet d’utiliser des méthodes chaînables familières avec une taille de fichier bien plus faible
- Elle ne vise pas une parité fonctionnelle à 100 % avec jQuery, mais couvre la plupart des cas d’usage du quotidien, et les API implémentées sont globalement compatibles avec jQuery
- Sa taille est de 6 Ko en minified & gzipped, soit 76,6 % de moins que les 24,4 Ko de jQuery Slim 3.4.1, et elle peut encore être réduite grâce aux builds partiels
- Elle prend en charge une base de code TypeScript, des types TypeScript générés depuis le code, les événements à espace de noms, ainsi que les builds partiels permettant d’exclure des méthodes individuelles
Le problème que résout Cash
- Cash est une alternative à jQuery pour les navigateurs modernes, qui fournit le sélecteur
$() de style jQuery et des méthodes de collection chaînables pour manipuler le DOM
- Les navigateurs ciblés sont IE11+
- L’objectif n’est pas de réimplémenter toutes les fonctionnalités de jQuery à l’identique, mais les fonctionnalités implémentées par Cash sont conçues pour être majoritairement compatibles avec l’API jQuery
- Les utilisateurs qui migrent depuis jQuery peuvent consulter le guide de migration
Comparaison de taille et de fonctionnalités
- Dans la comparaison des tailles de fichier, Cash est plus petit que Zepto 1.2.0 et jQuery Slim 3.4.1
- Unminified : 36,5 Ko
- Minified : 16 Ko
- Minified & Gzipped : 6 Ko
- jQuery Slim 3.4.1 pèse 24,4 Ko en minified & gzipped, et Cash réduit cette taille de 76,6 %
- Si vous avez besoin d’un bundle plus petit, vous pouvez utiliser les builds partiels
- Côté fonctionnalités, Cash propose la prise en charge des navigateurs modernes, une maintenance active, les événements à espace de noms, une base de code TypeScript et des types TypeScript générés depuis le code
- Les builds partiels permettent, avec Cash, d’exclure des méthodes individuelles, tandis que Zepto et jQuery Slim indiquent une exclusion par modules entiers
Utilisation
- Cash peut être chargé depuis jsDelivr et utilisé directement dans le navigateur
<script src="https://cdn.jsdelivr.net/npm/cash-dom/…;
<script>
$(function () {
$('html').addClass ( 'dom-loaded' );
$('<footer>Appended with Cash</footer>').appendTo ( document.body );
});
</script>
- Le paquet npm est disponible sous le nom
cash-dom
npm install --save cash-dom
import $ from "cash-dom";
$(function () {
$('html').addClass ( 'dom-loaded' );
$('<footer>Appended with Cash</footer>').appendTo ( document.body );
});
Structure de l’API
$() est la méthode de sélection centrale de Cash et renvoie une collection de nœuds manipulable
- Si une fonction est passée, elle est exécutée lorsque le DOM est prêt
$() peut recevoir un selector, un nœud DOM, une nodeList, une chaîne HTML, une collection Cash ou un callback document ready
- Cash propose globalement trois types d’API
- Sélecteur de requête
- Méthodes de collection
- Méthodes de bibliothèque de l’objet global
$
Méthodes de collection
- Les méthodes de collection s’appellent après avoir créé une collection avec
$(), par exemple $(element).addClass(className)
- Les catégories proposées se répartissent en attributs, collections, CSS, données, dimensions, effets, événements, formulaires, manipulation du DOM, offsets et navigation
- Les principales méthodes incluent notamment
- Classes/attributs :
addClass, removeClass, toggleClass, attr, prop, removeAttr
- Traitement des collections :
add, each, eq, filter, first, get, map, slice
- Manipulation du DOM :
append, prepend, before, after, html, text, clone, remove, replaceWith, wrap
- Événements :
on, off, one, ready, trigger
- Navigation :
find, children, closest, parent, parents, siblings, next, prev
- Certaines méthodes supplémentaires sont fournies, mais elles sont désactivées par défaut
$.fn est le prototype principal des collections et permet d’ajouter des méthodes personnalisées à toutes les collections, à la manière d’un plugin
Méthodes globales de Cash
- L’objet global
$ inclut des méthodes de vérification de type et des utilitaires
- Les méthodes de vérification de type proposées sont
$.isArray, $.isFunction, $.isNumeric, $.isPlainObject et $.isWindow
- Les utilitaires incluent
$.guid, $.each, $.extend, $.parseHTML et $.unique
$.extend étend un objet cible avec les propriétés d’objets source et prend aussi en charge l’extension profonde
$.parseHTML renvoie une collection à partir d’une chaîne HTML, et $.unique renvoie un nouveau tableau dont les doublons ont été supprimés
Extension et contribution
- Cash peut être étendu avec des méthodes personnalisées, et la manière de l’étendre est décrite dans extending Cash
- Les problèmes ou demandes de fonctionnalités peuvent être ouverts via les issues GitHub
- Le workflow de pull request consiste à cloner le dépôt, installer les dépendances, lancer la recompilation automatique avec
npm run dev, exécuter les tests avec npm run test, puis mettre à jour le README si nécessaire
- La licence est MIT
1 commentaires
Avis sur Hacker News
Les navigateurs sont devenus si bons aujourd’hui que, pour simplifier la manipulation du DOM, ces deux lignes d’alias suffisent souvent
dqs = document.querySelector.bind(document);dqsA = document.querySelectorAll.bind(document);On peut donc écrire
dqs('#country')au lieu dedocument.querySelector('#country'), etdqsA('.city')au lieu dedocument.querySelectorAll('.city')Pour le reste, les fonctions natives du navigateur conviennent très bien, et on les importe généralement depuis un module, par exemple
import { dqs, dqsA } from '/lib/js/dqs.js';https://github.com/no-gravity/dqs.js
querySelector/querySelectorAllsemblent utiles et raisonnables, mais les importer avecimport, c’est excessifCe ne sont que deux lignes simples : inutile d’en faire une dépendance, autant les copier-coller
Par exemple, pour gérer plusieurs événements,
$.fn.one()ou$.fn.on()sont plus faciles à utiliser avec jQuery/Cash, et quand on regarde l’implémentation interne, il y a pas mal de travail : https://github.com/fabiospampinato/cash/blob/master/src/even...querySelectorAll()n’est pas une collection live, donc je le transforme souvent directement en tableau comme cecidqsA = s => Array.from(document.querySelectorAll(s));Ainsi, on peut utiliser directement des méthodes de tableau comme
.map()ou.filter()sur le résultat, ce qui garde une sensation proche de jQueryPar exemple, pendant les tests, Safari ne déclenchait tout simplement pas l’événement
selectsur un certain élément, et dans certains navigateurs l’événement ne se déclenchait pas quand seul le curseur se déplaçaitMême sans avoir besoin des fonctionnalités de React comme les composants, l’état ou les props, les seules fonctions natives du navigateur ne suffisaient pas, et la valeur de React DOM pour masquer les différences entre navigateurs est apparue clairement
Une fois presque tous les polyfills retirés, l’avantage durable de jQuery reste selon moi le traitement automatique des listes
La capacité à décocher tous les boutons d’un formulaire en un seul appel reste difficile à égaler ailleurs, et c’est pareil pour les requêtes sur les parents
Cela dit, le plus gros problème de l’implémentation, c’est qu’elle échoue silencieusement quand la liste est vide
J’ai corrigé beaucoup trop de bugs de ce genre, apparus après des refactorings ultérieurs de l’arbre DOM pour des raisons de mise en page ; si je recréais jQuery aujourd’hui, par défaut un ensemble vide provoquerait une erreur, avec des appels chaînés ou un flag pour échouer silencieusement seulement quand on s’en moque vraiment
J’avais passé quelques heures autrefois à voir si l’on pouvait retirer Sizzle et modifier les choses dans ce sens, mais je ne suis pas allé plus loin
Au fond, jQuery est aussi lié au vieux débat bibliothèque contre framework, et après avoir fait pendant longtemps des applications monopages avec d’énormes frameworks, j’ai l’impression qu’on approche à nouveau de la vallée de la désillusion
Quand on demande de masquer tous les
.foo, s’ils existent ils sont masqués, sinon rien ne se passe : c’est une approche fire and forget, proche de CSSSi l’on écrit
.foo { color: red; }et qu’il n’y a pas de.foodans le document, il n’y a pas d’effet de bord hormis un faible surcoûtdocument.querySelectorAll('input[type=checkbox]').forEach((i) => i.checked = false);C’est une approche qui s’appuie sur des
NodeListitérables et des helpers d’itérateurBeaucoup de requêtes vers les parents peuvent être traitées avec
element.closest()Avec du code basé sur jQuery, chaque développeur doit connaître tous les sélecteurs du projet et les mettre à jour quand le DOM change, ce qui est évidemment impossible
Remplacer la fonction d’initialisation jQuery par une implémentation maison qui impose une vérification de longueur semble faisable
Dans un contexte où les sites web grand public servent littéralement des mégaoctets de JavaScript, je ne vois pas l’intérêt de réécrire toute une bibliothèque avec moins de fonctionnalités pour économiser 50 Ko
Beaucoup d’articles s’opposent à l’usage de jQuery à cause de la taille du paquet et des contraintes de bande passante, tout en défendant des frameworks SPA qui consomment bien plus de bande passante
C’est un raisonnement de culte du cargo totalement absurde
Dans les trois cas, la réponse est la même : le gros problème n’est pas moi, et moi je fais autre chose, de plus petit
Une autre réponse, c’est que si le problème est d’être trop gros, devenir plus petit ressemble à une solution
Au fond, la vraie question semble être pourquoi un développeur passerait du temps à réécrire une bibliothèque, mais ce n’est pas si étonnant
Une grande partie de la programmation consiste à refaire des choses qui existent déjà, parce que le travail l’exige, parce qu’on a besoin d’un comportement ou de caractéristiques de performance légèrement différents, ou simplement parce qu’on veut comprendre comment ça fonctionne
Si vous cherchez une alternative à jQuery, j’ai fini par créer ma propre sorte de jQuery après avoir attendu trop longtemps jQuery 4.0, avec quelques différences importantes
Les animations, tweens et timelines utilisent du CSS pur au lieu du système personnalisé de jQuery, gèrent de façon transparente les éléments uniques et les listes, et visent une utilisation inline
me()est décrit comme renvoyant un seul élément, ou le premier élément, ounull, etany()comme renvoyant un tableau ou un tableau videMais les exemples plus bas, comme
any('button')?.forEach(...)etany('button')?.map(...), suggèrent que cela peut aussi êtrenullJe ne sais pas si
any()renvoie toujours un tableau comme indiqué plus haut, ou s’il peut aussi renvoyernullcomme dans les exemples plus basJe m’intéresse particulièrement à la localité du comportement
Je me demande quelle a été votre expérience avec
currentScript.parentElementQuand j’avais rapidement regardé le mois dernier, j’avais eu l’impression que ce n’était probablement pas fiable dans certains cas de niche, mais je ne me souviens plus exactement quand
Je n’ai pas creusé davantage, et je suis content de voir que vous l’avez fait fonctionner correctement
En supposant que ce ne soit ni
asyncnimodule, il me semble que même en chargeant 3 scripts consécutifs,currentScript.parentElementdevrait toujours fonctionner dans tous les navigateursSvelteKit a aussi eu cette discussion et a finalement implémenté des ID aléatoires pour désigner l’élément cible : https://github.com/sveltejs/kit/issues/2221
En parcourant le guide de migration, j’ai découvert quelques fonctionnalités que jQuery sait faire mais pas Cash, que je ne connaissais pas et qui pourraient servir un jour
https://github.com/fabiospampinato/cash/blob/master/docs/mig...
Comme objectif d’extension, ce serait bien d’utiliser la magie des chaînes de gabarit TypeScript pour inférer précisément le type des éléments
Par exemple, on pourrait inférer statiquement que
$('div#name')est unHTMLDivElementtyped-query-selectorUn exemple d’utilisation réel se trouve ici : https://github.com/GoogleChrome/lighthouse/blob/main/types/i...
Je ne sais pas si c’est possible en TypeScript, et je ne vois pas bien comment on pourrait faire
J’ai entendu dire que jQuery 4 était une alternative à jQuery pour les navigateurs modernes
Je l’ai d’abord utilisé dans une extension de navigateur que je développe, mais j’ai finalement migré vers une bibliothèque JSX
Dès qu’on dépasse le domaine des « applications simples », jQuery devient vite du code difficile à raisonner, et je le ressens aussi en tant que personne ayant créé une bibliothèque inspirée de jQuery
Au final, il faut utiliser l’outil adapté au travail
[1] : https://github.com/aleclarson/dough
Si vous arrivez à bien gérer jQuery dans des applications moyennes à grandes, très bien, mais ce n’est pas mon goût
À l’époque où j’essayais de réduire la quantité de JS, j’utilisais https://github.com/filamentgroup/shoestring
La raison principale était qu’il proposait des builds personnalisés avec seulement ce dont on avait vraiment besoin
Cash semble avoir une fonctionnalité similaire, mais elle est un peu plus cachée dans la documentation : https://github.com/fabiospampinato/cash/blob/master/docs/par...
Si je devais l’utiliser, c’est probablement ce que j’essaierais en premier
Cela dit, je pense toujours qu’utiliser directement ce que les navigateurs modernes fournissent est un meilleur choix
En pratique, c’est assez bon, et jQuery n’est plus vraiment indispensable
D’autant plus que même une petite alternative à jQuery fait 6 ko, alors que Preact, une bibliothèque de type React, fait la moitié de cette taille
Je ne suis pas sûr que cela apporte beaucoup plus que de donner des alias à des API Web déjà existantes