C'était une journée de patch normale. J'ai corrigé et mis à niveau mes dépendances npm sans apporter de modifications au code, et tout à coup, certains de mes tests unitaires ont échoué.
Wtf!
Mes tests ont échoué car Jest a rencontré un jeton inattendu ; ils ont échoué parce que Jest ne peut pas gérer les packages ESM uniquement prêts à l'emploi. En fait, Jest est écrit en CommonJS.
Mais qu'est ce que ça veut dire? Pour ce faire, nous devons comprendre pourquoi CommonJS et ESM existent.
Au début du développement Web, JavaScript était principalement utilisé pour manipuler le modèle objet de document (DOM) avec des bibliothèques comme jQuery. Cependant, l’introduction de Node.js a également conduit à l’utilisation de JavaScript pour la programmation côté serveur. Ce changement a augmenté la complexité et la taille des bases de code JavaScript. En conséquence, il est apparu nécessaire de disposer d’une méthode structurée pour organiser et gérer le code JavaScript. Des systèmes de modules ont été introduits pour répondre à ce besoin, permettant aux développeurs de diviser leur code en unités gérables et réutilisables1.
CommonJS a été créé en 2009, initialement nommé ServerJS2. Il a été conçu pour JavaScript côté serveur, fournissant des conventions pour définir les modules. Node.js a adopté CommonJS comme système de modules par défaut, ce qui le rend répandu parmi les développeurs JavaScript backend. CommonJS utilise require pour importer et module.exports pour exporter des modules. Toutes les opérations dans CommonJS sont synchrones, ce qui signifie que chaque module est chargé individuellement.
En 2015, ECMAScript a introduit un nouveau système de modules appelé ECMAScript Modules (ESM), ciblant principalement le développement côté client. ESM utilise des instructions d'importation et d'exportation et ses opérations sont asynchrones, permettant aux modules d'être chargés en parallèle3. Initialement, ESM était destiné aux navigateurs, alors que CommonJS était conçu pour les serveurs. C’est devenu de plus en plus un standard pour l’écosystème JS. De nos jours, les environnements d'exécution JavaScript modernes prennent en charge les deux systèmes de modules. Les navigateurs ont commencé à prendre en charge ESM de manière native en 2017. Même Typescript a adapté la syntaxe ESM, et chaque fois que vous l'apprenez, vous apprenez également ESM inconsciemment.
La vérité est qu'il existe beaucoup plus de packages CommonJS (CJS) uniquement que de packages uniquement ESM4.
Il existe cependant une tendance claire. Le nombre de packages ESM uniquement ou à deux modules est en augmentation, tandis que moins de packages uniquement CJS sont créés. Cette tendance souligne la préférence croissante pour ESM et soulève la question de savoir combien de packages uniquement CJS sont activement maintenus.
Une comparaison intéressante entre CommonJS et ESM implique des benchmarks de performances. En raison de sa nature synchrone, CommonJS est plus rapide lorsqu'il utilise directement les instructions require et import. Considérons l'exemple suivant :
// CommonJS -> s3-get-files.cjs const s3 = require('@aws-sdk/client-s3'); new s3.S3Client({ region: 'eu-central-1' }); // ESM -> s3-get-files.mjs import { S3Client } from '@aws-sdk/client-s3'; new S3Client({ region: 'eu-central-1' });
J'ai utilisé le client S3 aws-sdk car il prend en charge deux modules. Ici, nous instancions le client puis l'exécutons avec node :
hyperfine --warmup 10 --style color 'node s3-get-files.cjs' 'node s3-get-files.mjs' Benchmark 1: node s3-get-files.cjs Time (mean ± σ): 82.6 ms ± 3.7 ms [User: 78.5 ms, System: 16.7 ms] Range (min … max): 78.0 ms … 93.6 ms 37 runs Benchmark 2: node s3-get-files.mjs Time (mean ± σ): 93.9 ms ± 4.0 ms [User: 98.3 ms, System: 18.1 ms] Range (min … max): 88.1 ms … 104.8 ms 32 runs Summary node s3-get-files.cjs ran 1.14 ± 0.07 times faster than node s3-get-files.mjs
Comme vous pouvez le constater, s3-get-files.cjs et, par conséquent, CommonJS fonctionnent plus rapidement.
Je me suis inspiré de Buns Blogpost.
Cependant, lorsque vous souhaitez mettre en production votre bibliothèque JS, vous devez la regrouper. Sinon, vous expédierez tous les node_modules. Est utilisé esbuild car il est capable de se regrouper avec CJS et ESM. Maintenant, exécutons le même benchmark avec la version fournie.
hyperfine --warmup 10 --style color 'node s3-bundle.cjs' 'node s3-bundle.mjs' Benchmark 1: node s3-bundle.cjs Time (mean ± σ): 62.1 ms ± 2.5 ms [User: 53.8 ms, System: 6.7 ms] Range (min … max): 59.5 ms … 74.5 ms 45 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Benchmark 2: node s3-bundle.mjs Time (mean ± σ): 45.3 ms ± 2.2 ms [User: 38.1 ms, System: 5.6 ms] Range (min … max): 43.0 ms … 59.2 ms 62 runs Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options. Summary node s3-bundle.mjs ran 1.37 ± 0.09 times faster than node s3-bundle.cjs
Comme vous pouvez le constater, le s3-bundle.mjs est désormais plus rapide que le s3-bundle.cjs. Le fichier ESM est désormais encore plus rapide que le fichier CommonJS dégroupé, car il entraîne des tailles de fichier plus petites et des temps de chargement plus rapides grâce à un tremblement d'arborescence efficace, un processus qui supprime le code inutilisé.
L'avenir des modules JavaScript penche sans aucun doute vers l'ESM. Cela commence lors de la création d'un nouveau projet NodeJS ou même d'un projet React. Chaque tutoriel et article utilise l'instruction import—, qui est donc ESM. Malgré de nombreux packages CommonJS existants, la tendance évolue à mesure que de plus en plus de développeurs et de responsables adoptent ESM pour ses avantages en termes de performances et sa syntaxe moderne. Une autre question est également de savoir combien de ces projets uniquement CJS sont encore maintenus.
ESM est un standard qui fonctionne dans n'importe quel environnement d'exécution, tel que NodeJS, Bun ou Deno, et dans le navigateur sans s'exécuter sur un serveur. Il n'est pas nécessaire de convertir via Babel vers CommonJS car le navigateur comprend ESM. Vous pouvez toujours utiliser Babel pour convertir vers une autre version d'ECMAScript, mais vous ne devriez pas convertir en CJS.
Vous devez développer uniquement dans ESM, car tous les environnements d'exécution actuels et les navigateurs plus récents que 2017 comprennent ESM.
Si votre code tombe en panne, vous pourriez avoir des problèmes hérités. Pensez à utiliser différents outils ou packages. Par exemple, vous pouvez migrer de Jest vers vitest ou d'ExpressJS vers h3. La syntaxe reste la même ; la seule différence est la déclaration d'importation.
Points clés à retenir:
Pour commencer, vous pouvez suivre cet Gist ou obtenir un apprentissage inspirant ici.
Pour un meilleur avenir JavaScript, adoptez ESM !
La présentation
https://www.freecodecamp.org/news/javascript-es-modules-and-module-bundlers/#why-use-modules ↩
https://deno.com/blog/commonjs-is-hurting-javascript ↩
https://tc39.es/ecma262/#sec-overview ↩
https://twitter.com/wooorm/status/1759918205928194443 ↩
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!