Relation entre CommonJS, AMD et RequireJS?

840

Je suis toujours très confus à propos de CommonJS, AMD et RequireJS , même après avoir beaucoup lu.

Je sais que CommonJS (anciennement ServerJS ) est un groupe pour définir certaines spécifications JavaScript (c'est-à-dire des modules) lorsque la langue est utilisée en dehors du navigateur. La spécification des modules CommonJS a une implémentation comme Node.js ou RingoJS , non?

Quelle est la relation entre CommonJS , la définition de module asynchrone (AMD) et RequireJS ?

RequireJS est- il une implémentation de la définition du module CommonJS ? Si oui, quel est AMD alors?

gremo
la source
31
La lecture de requirejs.org/docs/whyamd.html clarifierait beaucoup car elle les mentionne tous. (le poster comme un commentaire car je ne considère pas cela comme une réponse complète).
mmutilva
5
Puis-je demander ou ajouter plus; Comment ou où les déclarations d'importation ES2015 s'intègrent-elles dans tous ces éléments? par exemple, importer de la braise de 'braise';
testndtv
Il y a aussi un systemjs qui charge tous les formats de module JS pris en charge comme (CommonJS, UMD, AMD, ES6).
Andy

Réponses:

770

RequireJS implémente l' API AMD (source) .

CommonJS est un moyen de définir des modules à l'aide d'un exportsobjet, qui définit le contenu du module. Autrement dit, une implémentation CommonJS pourrait fonctionner comme ceci:

// someModule.js
exports.doSomething = function() { return "foo"; };

//otherModule.js
var someModule = require('someModule'); // in the vein of node    
exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };

Fondamentalement, CommonJS spécifie que vous devez avoir une require()fonction pour récupérer les dépendances, une exportsvariable pour exporter le contenu du module et un identifiant de module (qui décrit l'emplacement du module en question par rapport à ce module) qui est utilisé pour exiger les dépendances ( source ). CommonJS a diverses implémentations, dont Node.js , que vous avez mentionné.

CommonJS n'a pas été spécialement conçu pour les navigateurs, il ne s'intègre donc pas très bien dans l'environnement du navigateur ( je n'ai vraiment aucune source pour cela - il le dit partout, y compris le site RequireJS. ) Apparemment, cela a quelque chose à faire avec le chargement asynchrone, etc.

D'autre part, RequireJS implémente AMD, qui est conçu pour convenir à l'environnement du navigateur ( source ). Apparemment, AMD a commencé comme un spin-off du format CommonJS Transport et est devenu sa propre API de définition de module. D'où les similitudes entre les deux. La nouvelle fonctionnalité d'AMD est la define()fonction qui permet au module de déclarer ses dépendances avant d'être chargé. Par exemple, la définition pourrait être:

define('module/id/string', ['module', 'dependency', 'array'], 
function(module, factory function) {
  return ModuleContents;  
});

Ainsi, CommonJS et AMD sont des API de définition de module JavaScript qui ont des implémentations différentes, mais les deux proviennent des mêmes origines.

  • AMD est plus adapté au navigateur, car il prend en charge le chargement asynchrone des dépendances de module.
  • RequireJS est une implémentation d' AMD , tout en essayant de garder l'esprit de CommonJS (principalement dans les identifiants des modules).

Pour vous embrouiller encore plus, RequireJS, tout en étant une implémentation AMD, propose un wrapper CommonJS afin que les modules CommonJS puissent presque directement être importés pour être utilisés avec RequireJS.

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});

J'espère que cela aide à clarifier les choses!

jakee
la source
7
Découvrez le projet uRequire.org qui comble les lacunes des 2 formats - écrivez l'un des deux (ou les deux), déployez-le dans l'un des deux ou simple <script>
Angelos Pikoulas
51
FYI Browserify vous permet désormais d'utiliser CommonJS dans le navigateur.
Eruant
9
@Eruant Mais, il n'a toujours pas cette nature asynchrone comme AMD.
Inanc Gumus
8
La raison pour laquelle CommonJS ne rentre pas dans le navigateur, comme mentionné dans les documents RequireJS - "Le CommonJS require () est un appel synchrone, il devrait renvoyer le module immédiatement. Cela ne fonctionne pas bien dans le navigateur" . Plus d'infos ici .
msenni
4
@aaaaaa vous voudrez peut-être activer certaines fonctionnalités en fonction de la demande de l'utilisateur; la nature asynchrone d'AMD peut donc être utile.
Inanc Gumus
199

CommonJS est plus que cela - c'est un projet pour définir une API et un écosystème communs pour JavaScript. Une partie de CommonJS est la spécification du module . Node.js et RingoJS sont des exécutions JavaScript côté serveur, et oui, les deux implémentent des modules basés sur la spécification CommonJS Module.

AMD (Asynchronous Module Definition) est une autre spécification pour les modules. RequireJS est probablement l'implémentation la plus populaire d'AMD. Une différence majeure par rapport à CommonJS est qu'AMD spécifie que les modules sont chargés de manière asynchrone - ce qui signifie que les modules sont chargés en parallèle, au lieu de bloquer l'exécution en attendant la fin d'un chargement.

AMD est généralement plus utilisé dans le développement JavaScript côté client (dans le navigateur) pour cette raison, et les modules CommonJS sont généralement utilisés côté serveur. Cependant, vous pouvez utiliser l'une des spécifications de module dans l'un ou l'autre environnement - par exemple, RequireJS propose des instructions pour l'exécution dans Node.js et browserify est une implémentation de module CommonJS qui peut s'exécuter dans le navigateur.

Nate
la source
20
Pourquoi la page d'accueil de CommonJS est-elle si horrible ... J'essaie juste de voir les spécifications officielles. Il contient des erreurs de syntaxe, une documentation incomplète et la page wiki ne se résout pas.
taco
7
Ce n'est pas ce que signifie charger des modules de manière asynchrone. Vous pourriez parler de chargement dynamique / paresseux. Avec async, vous proposez un fichier à charger, puis un peu plus tard, il vous rappellera une fois le chargement terminé. Avec la synchronisation, vous suggérez un fichier à charger, puis l'ensemble des blocs de threads jusqu'à ce que le fichier ait fini de se charger; aucun autre code ne s'exécute avant le chargement du fichier. Les premiers peuvent donner de meilleures performances au prix de l'imprévisibilité, tandis que les seconds peuvent donner les mêmes résultats à chaque fois et sont donc plus prévisibles. Notez que ces bizarreries peuvent être atténuées à l'aide de diverses optimisations.
perry
Merci d'avoir répondu. Maintenant que les modules sont officiels dans JS avec ES2015, cela signifie-t-il qu'ils sont plus préférés qu'AMD ou JS commun?
Akhoy
Cela ne signifie pas qu'ils sont préférés. Tout dépend des besoins des développeurs. Je ne pense pas que laisser aucune option et opter pour les modules ES6 soit une bonne idée. Cependant, en utilisant un bon UMD, vous pouvez lutter contre ce problème. Le chargement de bundles CommonJS synchronisés avec AMD est une bonne (meilleure) idée en général (pour améliorer les performances). Si vous pensez que vous devriez avoir plus de contrôle, évidemment. Et tu devrais.
Maciej Sitko
187

La réponse courte serait:

CommonJS et AMD sont des spécifications (ou formats) sur la façon dont les modules et leurs dépendances doivent être déclarés dans les applications javascript.

RequireJS est une bibliothèque de chargeur de script compatible AMD, curljs étant un autre exemple.

Conforme à CommonJS:

Tiré du livre d' Addy Osmani .

// package/lib is a dependency we require
var lib = require( "package/lib" );

// behavior for our module
function foo(){
    lib.log( "hello world!" );
}

// export (expose) foo to other modules as foobar
exports.foobar = foo;

Conforme AMD:

// package/lib is a dependency we require
define(["package/lib"], function (lib) {

    // behavior for our module
    function foo() {
        lib.log( "hello world!" );
    }

    // export (expose) foo to other modules as foobar
    return {
        foobar: foo
    }
});

Quelque part ailleurs, le module peut être utilisé avec:

require(["package/myModule"], function(myModule) {
    myModule.foobar();
});

Quelques antécédents:

En fait, CommonJS est bien plus qu'une déclaration d'API et seule une partie de celle-ci traite de cela. AMD a commencé comme un projet de spécification pour le format de module sur la liste CommonJS, mais le consensus n'a pas été atteint et le développement du format a été transféré au groupe amdjs . Les arguments selon lesquels le format est le meilleur indiquent que CommonJS tente de couvrir un ensemble plus large de préoccupations et qu'il est mieux adapté au développement côté serveur étant donné sa nature synchrone, et qu'AMD est mieux adapté au développement côté client (navigateur) étant donné sa nature asynchrone et la fait qu'il a ses racines dans l'implémentation de la déclaration de module de Dojo.

Sources:

mmutilva
la source
1
Voir du code plutôt que des descriptions aide! :) AMD compliantest en fait RequireJS, non?
Asim KT
Suis-je en train de manquer quelque chose ou y a-t-il quelque chose de mal écrit? Vous définissez "package / lib" mais vous avez ensuite besoin de "package / myModule".
RullDawg
J'aime toujours lire un peu l'histoire de pourquoi quelque chose est comme ça! Merci d'avoir fourni ce fond!
Andru
@RullDawg Non, "package / lib" n'est pas défini ici, c'est une dépendance tierce utilisée ici.
Robert Siemer
28

Citant

AMD :

  • Une approche par navigateur
  • Opter pour un comportement asynchrone et une compatibilité descendante simplifiée
  • Il n'a aucun concept d'E / S de fichiers.
  • Il prend en charge les objets, fonctions, constructeurs, chaînes, JSON et de nombreux autres types de modules.

CommonJS :

  • Une approche axée sur le serveur
  • En supposant un comportement synchrone
  • Couvrir un ensemble plus large de préoccupations telles que les E / S, le système de fichiers, les promesses et plus encore.
  • Prend en charge les modules non encapsulés, il peut se sentir un peu plus proche des spécifications ES.next/Harmony , vous libérant du wrapper define () qui AMDs'applique.
  • Ne prend en charge que les objets en tant que modules.
zangw
la source
17

Il est tout à fait normal d'organiser le programme JavaScript en plusieurs fichiers et d'appeler child-modulesdepuis main js module.

Le fait est que JavaScript ne fournit pas cela. Pas même aujourd'hui dans les dernières versions de navigateur de Chrome et FF.

Mais, y a-t-il un mot clé en JavaScript pour appeler un autre module JavaScript?

Cette question peut être un effondrement total du monde pour beaucoup parce que la réponse est non .


Dans ES5 (sorti en 2009), JavaScript n'avait pas de mots clés comme importer , inclure ou exiger .

ES6 sauve le jour (publié en 2015) en proposant le mot-clé d' importation ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), mais aucun navigateur ne l'implémente.

Si vous utilisez Babel 6.18.0 et transpile avec l'option ES2015 uniquement

import myDefault from "my-module";

vous obtiendrez à requirenouveau.

"use strict";
var _myModule = require("my-module");
var _myModule2 = _interopRequireDefault(_myModule);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

En effet, cela requiresignifie que le module sera chargé à partir de Node.js. Node.js gérera tout, de la lecture de fichiers au niveau système aux fonctions d'encapsulation dans le module.

Parce qu'en JavaScript, les fonctions sont les seuls wrappers à représenter les modules.

Je suis très confus à propos de CommonJS et AMD?

CommonJS et AMD ne sont que deux techniques différentes pour surmonter le "défaut" JavaScript de chargement intelligent des modules.

prosti
la source
3
Devrait mettre à jour votre réponse, car maintenant tous les navigateurs modernes prennent en charge import
vsync
@vsync, oui, n'hésitez pas à modifier ma réponse, car je n'ai pas suivi ce segment depuis un certain temps.
prosti