Beziehung zwischen CommonJS, AMD und RequireJS?

840

Ich bin immer noch sehr verwirrt über CommonJS, AMD und RequireJS , selbst nachdem ich viel gelesen habe.

Ich weiß, dass CommonJS (früher ServerJS ) eine Gruppe zum Definieren einiger JavaScript- Spezifikationen (dh Module) ist, wenn die Sprache außerhalb des Browsers verwendet wird. Die CommonJS- Modulspezifikation hat einige Implementierungen wie Node.js oder RingoJS , richtig?

Welche Beziehung besteht zwischen CommonJS , Asynchronous Module Definition (AMD) und RequireJS ?

Ist RequireJS eine Implementierung der CommonJS- Moduldefinition? Wenn ja, was ist dann AMD ?

Gremo
quelle
31
Das Lesen von requirejs.org/docs/whyamd.html würde viel klarstellen, da es alle erwähnt. (Posten als Kommentar, da ich dies nicht als vollständige Antwort betrachte).
mmutilva
5
Kann ich mehr fragen oder hinzufügen? Wie oder wo passen die ES2015-Importanweisungen in all diese? zB Ember aus 'Ember' importieren;
Testndtv
Es gibt auch ein System, das alle unterstützten JS-Modulformate wie CommonJS, UMD, AMD, ES6 lädt.
Andy

Antworten:

770

RequireJS implementiert die AMD- API (Quelle) .

CommonJS ist eine Möglichkeit, Module mithilfe eines exportsObjekts zu definieren, das den Modulinhalt definiert. Einfach ausgedrückt könnte eine CommonJS-Implementierung folgendermaßen funktionieren:

// 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"; };

Grundsätzlich gibt CommonJS an, dass Sie eine require()Funktion zum Abrufen von Abhängigkeiten, eine exportsVariable zum Exportieren von Modulinhalten und eine Modulkennung (die den Speicherort des betreffenden Moduls in Bezug auf dieses Modul beschreibt) benötigen, mit der die Abhängigkeiten ( Quelle) benötigt werden ). CommonJS verfügt über verschiedene Implementierungen, einschließlich Node.js , die Sie erwähnt haben.

CommonJS wurde nicht speziell für Browser entwickelt, daher passt es nicht sehr gut in die Browserumgebung ( ich habe wirklich keine Quelle dafür - es sagt es einfach überall, einschließlich der RequireJS-Site. ) Anscheinend hat dies etwas zu tun tun mit asynchronem Laden usw.

Andererseits implementiert RequireJS AMD, das für die Browserumgebung ( Quelle ) ausgelegt ist. Anscheinend begann AMD als Spin-off des CommonJS-Transportformats und entwickelte sich zu einer eigenen Moduldefinitions-API. Daher die Ähnlichkeiten zwischen den beiden. Die neue Funktion in AMD ist die define()Funktion, mit der das Modul seine Abhängigkeiten deklarieren kann, bevor es geladen wird. Zum Beispiel könnte die Definition sein:

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

CommonJS und AMD sind also JavaScript- Moduldefinitions-APIs mit unterschiedlichen Implementierungen, die jedoch beide denselben Ursprung haben.

  • AMD ist besser für den Browser geeignet, da es das asynchrone Laden von Modulabhängigkeiten unterstützt.
  • RequireJS ist eine Implementierung von AMD , während gleichzeitig versucht wird, den Geist von CommonJS beizubehalten (hauptsächlich in den Modulkennungen).

Um Sie noch mehr zu verwirren, bietet RequireJS als AMD-Implementierung einen CommonJS-Wrapper, sodass CommonJS-Module fast direkt zur Verwendung mit RequireJS importiert werden können.

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

Ich hoffe das hilft die Dinge zu klären!

jakee
quelle
7
Schauen Sie sich das uRequire.org- Projekt an, das die Lücken der beiden Formate schließt - schreiben Sie in eines (oder beide), stellen Sie es in einem der beiden oder einfachen <script>
bereit
51
Mit FYI Browserify können Sie jetzt CommonJS im Browser verwenden.
Eruant
9
@Eruant Aber es ist immer noch nicht so asynchron wie AMD.
Inanc Gumus
8
Der Grund , warum Commonjs nicht im Browser passen , wie in RequireJS docs erwähnt - „Die Commonjs require () ist ein synchroner Aufruf, wird erwartet , sofort das Modul zurückzukehren Dies funktioniert nicht gut in dem Browser.“ . Mehr Infos hier .
Msenni
4
@aaaaaa Je nach Benutzeranforderung möchten Sie möglicherweise einige Funktionen aktivieren. Daher kann die asynchrone Natur von AMD nützlich sein.
Inanc Gumus
199

CommonJS ist mehr als das - es ist ein Projekt zur Definition einer gemeinsamen API und eines gemeinsamen Ökosystems für JavaScript. Ein Teil von CommonJS ist die Modulspezifikation . Node.js und RingoJS sind serverseitige JavaScript-Laufzeiten, und ja, beide implementieren Module basierend auf der CommonJS-Modulspezifikation.

AMD (Asynchronous Module Definition) ist eine weitere Spezifikation für Module. RequireJS ist wahrscheinlich die beliebteste Implementierung von AMD. Ein wesentlicher Unterschied zu CommonJS besteht darin, dass AMD angibt, dass Module asynchron geladen werden. Dies bedeutet, dass Module parallel geladen werden, anstatt die Ausführung zu blockieren, indem auf das Beenden eines Ladevorgangs gewartet wird.

Aus diesem Grund wird AMD in der clientseitigen JavaScript-Entwicklung (im Browser) häufiger verwendet, und CommonJS-Module werden im Allgemeinen serverseitig verwendet. Sie können jedoch beide Modulspezifikationen in beiden Umgebungen verwenden. Beispielsweise bietet RequireJS Anweisungen zum Ausführen in Node.js und browserify ist eine CommonJS- Modulimplementierung , die im Browser ausgeführt werden kann.

Nate
quelle
20
Warum ist die CommonJS-Homepage so schrecklich ... Ich versuche nur, die offizielle Spezifikation anzuzeigen. Es hat Syntaxfehler, unvollständige Dokumentation und die Wiki-Seite wird nicht aufgelöst.
Taco
7
Das bedeutet nicht, Module asynchron zu laden. Möglicherweise handelt es sich um dynamisches / verzögertes Laden. Mit async schlagen Sie vor, eine Datei zu laden, und einige Zeit später wird sie zurückgerufen, wenn der Ladevorgang abgeschlossen ist. Bei der Synchronisierung schlagen Sie eine zu ladende Datei vor und dann blockiert der gesamte Thread, bis diese Datei vollständig geladen ist. Es wird kein weiterer Code ausgeführt, bis die Datei geladen wird. Ersteres kann eine bessere Leistung auf Kosten der Unvorhersehbarkeit erzielen, während letzteres jedes Mal die gleichen Ergebnisse liefern kann und somit vorhersehbarer ist. Beachten Sie, dass diese Macken durch verschiedene Optimierungen verringert werden können.
Perry
Danke für die Antwort. Bedeutet dies, dass Module, die in JS mit ES2015 offiziell sind, mehr bevorzugt werden als AMD oder gewöhnliches JS?
Akhoy
Dies bedeutet nicht, dass sie bevorzugt werden. Es hängt alles von den Anforderungen der Entwickler ab. Ich denke nicht, dass es besonders gut ist, keine Option zu lassen und sich für ES6-Module zu entscheiden. Mit einer guten UMD können Sie dieses Problem jedoch bekämpfen. Das Laden von mit AMD synchronisierten CommonJS-Bundles ist im Allgemeinen eine gute (beste) Idee (aus Gründen der Leistungsverbesserung). Wenn Sie das Gefühl haben, sollten Sie natürlich mehr Kontrolle haben. Und du solltest.
Maciej Sitko
187

Die kurze Antwort wäre:

CommonJS und AMD sind Spezifikationen (oder Formate), wie Module und ihre Abhängigkeiten in Javascript-Anwendungen deklariert werden sollen.

RequireJS ist eine Skriptladeprogrammbibliothek , dieAMD-kompatibel ist. Curljs ist ein weiteres Beispiel.

CommonJS-konform:

Entnommen aus Addy Osmanis Buch .

// 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;

AMD-konform:

// 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
    }
});

An anderer Stelle kann das Modul verwendet werden mit:

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

Einige Hintergrundinformationen:

Tatsächlich ist CommonJS viel mehr als eine API-Deklaration, und nur ein Teil davon befasst sich damit. AMD begann als Entwurf einer Spezifikation für das Modulformat in der CommonJS-Liste, aber es wurde kein vollständiger Konsens erzielt, und die Weiterentwicklung des Formats wurde in die amdjs-Gruppe verschoben . Argumente, um welches Format es sich besser handelt, besagen, dass CommonJS versucht, ein breiteres Spektrum von Bedenken abzudecken, und dass es aufgrund seiner Synchronität besser für die serverseitige Entwicklung geeignet ist und dass AMD aufgrund seiner asynchronen Natur und der Entwicklung besser für die clientseitige (Browser-) Entwicklung geeignet ist Tatsache, dass es seine Wurzeln in der Implementierung der Moduldeklaration von Dojo hat.

Quellen:

mmutilva
quelle
1
Es hilft, Code statt Beschreibungen zu sehen! :) AMD compliantist eigentlich RequireJS, oder?
Asim KT
Vermisse ich etwas oder ist etwas falsch geschrieben? Sie definieren "package / lib", benötigen dann aber "package / myModule".
RullDawg
Ich lese immer gerne ein bisschen über die Geschichte, warum etwas so ist, wie es ist! Vielen Dank für diesen Hintergrund!
Andru
@RullDawg Nein, "package / lib" ist hier nicht definiert, es handelt sich um eine Abhängigkeit von Drittanbietern, die hier verwendet wird.
Robert Siemer
28

Zitieren

AMD :

  • Ein Browser-First-Ansatz
  • Entscheiden Sie sich für asynchrones Verhalten und vereinfachte Abwärtskompatibilität
  • Es gibt kein Konzept für Datei-E / A.
  • Es unterstützt Objekte, Funktionen, Konstruktoren, Zeichenfolgen, JSON und viele andere Modultypen.

CommonJS :

  • Ein Server-First-Ansatz
  • Synchrones Verhalten annehmen
  • Decken Sie ein breiteres Spektrum von Anliegen ab, z. B. E / A, Dateisystem, Versprechen und mehr.
  • Unterstützt nicht verpackte Module, kann sich den ES.next/Harmony-Spezifikationen etwas näher fühlen und befreit Sie vom definierten define () - Wrapper AMD.
  • Unterstützt nur Objekte als Module.
zangw
quelle
17

Es ist ganz normal, JavaScript-Programme modular in mehrere Dateien zu organisieren und child-modulesvon der aus aufzurufen main js module.

Die Sache ist, dass JavaScript dies nicht bietet. Nicht einmal heute in den neuesten Browserversionen von Chrome und FF.

Aber gibt es in JavaScript ein Schlüsselwort, um ein anderes JavaScript-Modul aufzurufen?

Diese Frage kann für viele ein völliger Zusammenbruch der Welt sein, denn die Antwort lautet Nein .


In ES5 (veröffentlicht im Jahre 2009) hatte JavaScript keine Schlüsselwörter wie Import , enthalten oder benötigen .

ES6 spart den Tag (veröffentlicht im Jahr 2015) und schlägt das Importschlüsselwort vor ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), aber kein Browser implementiert dies.

Wenn Sie Babel 6.18.0 verwenden und nur mit der Option ES2015 transpilen

import myDefault from "my-module";

du wirst requirewieder bekommen .

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

Dies liegt daran, requiredass das Modul von Node.js geladen wird. Node.js erledigt alles vom Lesen von Dateien auf Systemebene bis zum Umschließen von Funktionen in das Modul.

Denn in JavaScript sind Funktionen die einzigen Wrapper, die die Module darstellen.

Ich bin sehr verwirrt über CommonJS und AMD?

Sowohl CommonJS als auch AMD sind nur zwei verschiedene Techniken, um den JavaScript- "Defekt" zu überwinden und Module intelligent zu laden.

Prosti
quelle
3
Sollte Ihre Antwort aktualisieren, da jetzt alle modernen Browser unterstützen import
vsync
@vsync, ja, Sie können meine Antwort jederzeit bearbeiten, da ich diesem Segment seit einiger Zeit nicht mehr gefolgt bin.
Prosti