devstory

L'histoire des modules en JavaScript

Suivez-nous sur notre fanpage pour recevoir des notifications chaque fois qu'il y a de nouveaux articles. Facebook

1- Module?

Cet article vous présente l'historique des modules en JavaScript. De nombreuses spécifications et implémentations de modules ont été créées jusqu'à ce que JavaScript ES6 (2105) publie une nouvelle spécification de module prise en charge au niveau du langage. Par conséquent, les anciennes spécifications deviennent lentement obsolètes. Bien que certains d'entre eux soient encore utilisés quelque part, comme NodeJS, ils seront certainement supprimés dans un proche avenir.
Le but de cet article est de proposer une vue générale et de prévenir toute confusion pour les débutants qui se lancent dans le JavaScript Module, ainsi que d'éviter de perdre du temps sur des bibliothèques obsolètes.
Les programmes JavaScript ont commencé pratiquement petit - au début, son utilisation consistait en grande partie à effectuer des tâches de script isolées, offrant un peu d'interactivité à vos pages Web si nécessaire, de sorte que les scripts volumineux n'étaient généralement pas nécessaires. On zappe quelques années et on dispose maintenant des applications complètes exécutées dans différents navigateurs avec beaucoup de JavaScript, ainsi que JavaScript utilisé dans de nombreux contextes différents, tels que NodeJs.
Lorsque JavaScript a commencé à être utilisé dans les applications, il est devenu plus difficile de gérer et de maintenir le code. De plus, l'utilisation de plusieurs fichiers JavaScript dans le même programme provoquera des conflits de noms de variables ou de fonctions et créera de grands risques. Observer l'exemple ci-dessous:
file_1a.js

var friendName = "Tom";
function sayHello() {
    console.log(`Hello ${friendName}!`);
}
file_2a.js

sayHello(); // Hello Tom!
friendName = 'Jerry';
sayHello(); // Hello Jerry!
test_a.html

<html>
  <head>
     <script src="file_1a.js"></script>
     <script src="file_2a.js"></script>
     <script>
        var friendName = 'Donald';
        sayHello(); // Hello Donald!
     </script>
  </head>
  <body>
      View the result in the Browser Console Window.
  </body>
</html>
Output:

Hello Tom!
Hello Jerry!
Hello Donald!
Donc, le concept de module a émergé pour résoudre deux problèmes importants :
  • Le module doit être un espace clos, tout ce qui est partagé avec l'extérieur doit être issu d'une intention claire.
  • Les modules doivent être un moyen de diviser une grande application en plusieurs petites parties séparées, ce qui facilite le développement et le travail de maintenance de l'application des programmeurs.

2- IIFE

IIFE (Immediately Invoked Function Expression) (Expression de fonction immédiatement convoquée): Il s'agit de la technique la plus élémentaire de la modularisation du code. Aujourd'hui, le concept de classes n'existe pas en JavaScript. L'utilisation d'IIFE nous donne la liberté de créer des variables ou des fonctions dans un espace clos à usage interne, et sans crainte de conflit ailleurs dans l'application.
L'expression IIFE ressemble à ceci :

(function () {
  // Statements
})();
Cela ressemble à une épreuve intellectuelle, car de nombreux crochets sont impliqués dans l'expression, mais la forme équivalente ci-dessous s'avère beaucoup plus facile à comprendre :

var myFunc = function()  {
   // Statements
}  
myFunc();
IIFE aide à cacher le code en cours de traitement à l'intérieur et expose uniquement ce qu'on veut. Exemple:

var text = (function () {
    var privateText = "My private TEXT";
    var publicText = "My public TEXT";
    return publicText;
})();

console.log(text); // My public TEXT
Et on peut toujours accéder aux variables globales depuis l'IIFE normalement :

var myGlobalVariable = 'Hello, I am a global variable :)';

var text = (function () {
    var privateText = "My private TEXT";
    var publicText = "My public TEXT";
    console.log(myGlobalVariable);
    return publicText;
})();

console.log(text); // My public TEXT
En continuant avec l'idée ci-dessus, un exemple IIFE renvoie un objet structuré comme une interface :
file_1b.js

var mySimpleModule = (function() {
   var greeting = 'Hello'; // Private variable!
   var friendName = "Tom";
   var sayHello = function()  {
       console.log(`${greeting} ${friendName}!`);
   }
   var mm = {
       friendName: friendName,
       sayHello: sayHello
   };
   return mm;
})();
file_2b.js

// Call sayHello function of 'mySimpleModule':
mySimpleModule.sayHello(); // Hello Tom!

var friendName = 'Donald';
mySimpleModule.friendName = 'Jerry';
mySimpleModule.sayHello(); // Hello Jerry!

3- CommonJS

CommonJS est une spécification lancée en janvier 2009 par l'ingénieur de Mozilla, Kevin Dangoor. Son objectif majeur consiste à établir des conventions d'écosystème de modules pour les environnements JavaScript autres que ceux fournis par le navigateur. Maintenant, on est au milieu, comme l'illustration ci-dessous, n'est-ce pas ?
En fait, le projet s'appelait à l'origine ServerJS, visant l'écosystème JavaScript sur le serveur. En août 2009, il a été renommé CommonJS pour exprimer son large éventail d'utilisations, y compris les navigateurs.
Depuis sa création, la spécification du module CommonJS a été utilisée pour NodeJS. Et jusqu'à la publication de cet article (2021), CommonJS était toujours utilisé dans NodeJS. Cependant, il est certain qu'il sera remplacé par le module ES6 dans un futur proche. Les caractéristiques d'identification de CommonJS sont les fonctions require() et module.exports().
Les avantages de CommonJS:
  • Simple et facile à utiliser sans revoir la documentation..
  • Gestionnaire de dépendances intégré. Les modules sont chargés dans un ordre approprié.
  • La fonction require() peut être utilisée n'importe où pour exiger un autre module.
  • La prise en charge de la dépendance circulaire.
Les inconvénients de CommonJS:
  • Le chargement de modules de manière synchrone entraîne une vitesse de chargement lente et n'est pas adapté à certaines utilisations, telles que les applications côté navigateur.
  • Un fichier par module.
  • Les navigateurs ne comprennent pas les modules selon la norme CommonJS. Il a besoin d'une bibliothèque Module Loader supplémentaire ou au moins il doit être transpilé par un transpiler.
  • Ne prend pas en charge les fonctions de constructeur (Comme spécification). Cependant, NodeJS prend en charge cela.
  • Difficile à analyser pour les analyseurs de code statique.
Les bibliothèques JavaScript qui implémentent la spécification CommonJS :
  • NodeJS (Server side)
  • webpack (Client side)
  • Browserify (Client side)
Exemple : Comment déclarer un module dans CommonJS :
cjs_file_1.js

function _add(a, b) {
    return a + b;
}
function _subtract(a, b) {
    return a - b;
}
module.exports = {
    add: _add,
    subtract: _subtract,
};
La manière d'utilisation:
cjs_file_2.js

// Using require() function to load file "csj_file_1.js", no need .js extension.
var calculator = require("./csj_file_1");
console.log(calculator.add(2, 2)); // 4
console.log(calculator.subtract(2, 2)); // 0
Voir les articles détaillés de CommonJS :

4- AMD

AMD (Asynchronous Module Definition) est né d'un groupe de développeurs mécontents de la direction prise par CommonJS. En fait, AMD a été séparé de CommonJS en tout de son développement. La principale différence entre AMD et CommonJS réside dans sa prise en charge du chargement de module asynchrone. Comme CommonJS, AMD n'est qu'une spécification.
Avec le chargement asynchrone, les bibliothèques qui ne dépendent pas les unes des autres pour le chargement peuvent être chargées en même temps. Ceci est particulièrement important pour les navigateurs, où le temps de démarrage est essentiel pour une bonne expérience utilisateur.
Les avantages d'AMD:
  • Le chargement asynchrone (Asynchronos loading) permet d'optimiser temps de démarrage.
  • La prise en charge est compatible avec les fonctions require() et module.exports(), à l'instar de CommonJS.
  • Gestionnaire de dépendances intégré.
  • Un module peut inclure plusieurs fichiers.
  • Prendre en charge de la fonction constructeur.
  • Prendre en charge de la fonction constructeur.
  • Prendre en charge des plugins (étapes de chargement personnalisées).
Les inconvénients  AMD:
  • Syntaxiquement, c'est un peu plus compliqué que CommonJS.
  • Difficile à analyser pour les analyseurs de code statique.
  • Les navigateurs ne comprennent pas les modules selon les normes AMD. Il a besoin d'une bibliothèque Module Loader supplémentaire ou au moins il doit être transpilé par un transpiler.
Par exemple: Créer un module AMD:
amd_file_1.js

define("myAmdModule", {
    add: function (a, b) {
        return a + b;
    },
    subtract: function (a, b) {
        return a - b;
    },
});
amd_file_2.js

require(["myAmdModule"], function (myAmdModule) {
    console.log(myAmdModule.add(2, 2)); // 4
    console.log(myAmdModule.subtract(2, 2)); // 0
});
Voir plus d'article sur AMD:

5- UMD

UMD (Universal Module Definition) est un ensemble de techniques utilisées pour créer des modules qui peuvent être importés en tant que modules IIFE, CommonJS ou AMD. Par conséquent, un programme peut désormais importer des modules tiers, quelle que soit la spécification de module qu'il utilise.
Par exemple :
UMD_file_1.js

(function (myUmdModule) {
    if (typeof define === 'function' && define.amd) {
        // Export with AMD
        define("myUmdModule", myUmdModule);
    } else if (typeof module === 'object' && module.exports) {
        // Export with CommonJS
        module.exports = myUmdModule;
    } else {
        // Export with browser global
        window.myUmdModule = myUmdModule;
    }
}({
    add: function (a, b) {
        return a + b;
    },
    subtract: function (a, b) {
        return a - b;
    },
}));
UMD_file_2.js

// Load with AMD
require(["myUmdModule"], function (myUmdModule) {
    console.log(myUmdModule.add(2, 2));
    console.log(myUmdModule.subtract(2, 2));
});
// Load with CommonJS
var myUmdModule = require("./myUmdModule");
console.log(myUmdModule.add(2, 2));
console.log(myUmdModule.subtract(2, 2));

6- ES Modules

Les modules ES Modules alias modules ECMAScript Modules ou modules ES6 ou modules ES2015. ES Modules est la solution pour un meilleur avenir de l'écosystème de modules en normalisant la syntaxe de déclaration de module, en travaillant à la fois sur le backend et le frontend, et pris en charge par JavaScript au niveau du langage. Cependant, tous les utilisateurs n'ont pas migré vers des navigateurs modernes prenant en charge ES6, il faut donc plus de temps.