Relazione tra CommonJS, AMD e RequireJS?


840

Sono ancora molto confuso su CommonJS, AMD e RequireJS , anche dopo aver letto molto.

So che CommonJS (precedentemente ServerJS ) è un gruppo per la definizione di alcune specifiche JavaScript (ovvero moduli) quando la lingua viene utilizzata al di fuori del browser. Le specifiche dei moduli CommonJS hanno un'implementazione come Node.js o RingoJS , giusto?

Qual è la relazione tra CommonJS , Asynchronous Module Definition (AMD) e RequireJS ?

RequireJS è un'implementazione della definizione del modulo CommonJS ? Se sì, cos'è AMD allora?


31
La lettura di requestjs.org/docs/whyamd.html chiarirebbe molto in quanto menziona tutti. (pubblicandolo come commento poiché non considero questa una risposta completa).
mmutilva,

5
Posso chiedere o aggiungere altro; Come o dove le dichiarazioni di importazione ES2015 si adattano a tutte queste; es. importare Ember da 'ember';
testndtv,

Esiste anche un systemjs che carica uno qualsiasi dei formati di modulo JS supportati come (CommonJS, UMD, AMD, ES6).
Andy,

Risposte:


770

RequireJS implementa l' API AMD (sorgente) .

CommonJS è un modo per definire i moduli con l'aiuto di un exportsoggetto, che definisce i contenuti del modulo. In poche parole, un'implementazione di CommonJS potrebbe funzionare in questo modo:

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

Fondamentalmente, CommonJS specifica che è necessario disporre di una require()funzione per recuperare le dipendenze, una exportsvariabile per esportare il contenuto del modulo e un identificatore del modulo (che descrive la posizione del modulo in questione in relazione a questo modulo) che viene utilizzato per richiedere le dipendenze ( sorgente ). CommonJS ha varie implementazioni, tra cui Node.js , che hai citato.

CommonJS non è stato progettato appositamente per i browser, quindi non si adatta molto bene all'ambiente del browser (non ho davvero alcuna fonte per questo - lo dice semplicemente ovunque, incluso il sito RequireJS. ) Apparentemente, questo ha qualcosa da fare con caricamento asincrono, ecc.

D'altra parte, RequireJS implementa AMD, progettato per adattarsi all'ambiente del browser ( sorgente ). Apparentemente, AMD è iniziato come uno spin-off del formato di trasporto CommonJS e si è evoluto nella propria API di definizione del modulo. Da qui le somiglianze tra i due. La nuova funzionalità di AMD è la define()funzione che consente al modulo di dichiarare le proprie dipendenze prima di essere caricato. Ad esempio, la definizione potrebbe essere:

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

Quindi, CommonJS e AMD sono JavaScript API di definizione del modulo che hanno implementazioni diverse, ma entrambe provengono dalle stesse origini.

  • AMD è più adatto per il browser, perché supporta il caricamento asincrono delle dipendenze del modulo.
  • RequireJS è un'implementazione di AMD , mentre allo stesso tempo cerca di mantenere lo spirito di CommonJS (principalmente negli identificatori del modulo).

Per confondervi ancora di più, RequireJS, pur essendo un'implementazione AMD, offre un wrapper CommonJS in modo che i moduli CommonJS possano essere importati quasi direttamente per l'uso con RequireJS.

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

Spero che questo aiuti a chiarire le cose!


7
Scopri uRequire.org progetto che colma le lacune dei 2 formati - scrittura a uno (o entrambi), l'implementazione su qualsiasi dei due o semplice <script>
Angelos Pikoulas

51
FYI Browserify ora ti permetterà di usare CommonJS nel browser.
Eruant

9
@Eruant Ma non ha ancora quella natura asincrona come AMD.
Inanc Gumus,

8
Il motivo per cui CommonJS non rientra nel browser come indicato nei documenti RequireJS - "CommonJS Require () è una chiamata sincrona, si prevede che restituisca immediatamente il modulo. Questo non funziona bene nel browser" . Maggiori informazioni qui .
msenni

4
@aaaaaa potresti voler abilitare alcune funzionalità a seconda della richiesta dell'utente; quindi la natura asincrona di AMD può tornare utile.
Inanc Gumus,

199

CommonJS è molto più di questo: è un progetto per definire un'API e un ecosistema comuni per JavaScript. Una parte di CommonJS è la specifica del modulo . Node.js e RingoJS sono runtime JavaScript sul lato server e, sì, entrambi implementano moduli basati sulle specifiche del modulo CommonJS.

AMD (Asynchronous Module Definition) è un'altra specifica per i moduli. RequireJS è probabilmente l'implementazione più popolare di AMD. Una delle principali differenze rispetto a CommonJS è che AMD specifica che i moduli vengono caricati in modo asincrono , il che significa che i moduli vengono caricati in parallelo, anziché bloccare l'esecuzione in attesa che un carico finisca.

AMD è generalmente più utilizzato nello sviluppo JavaScript lato client (nel browser) a causa di ciò, mentre i moduli CommonJS sono generalmente utilizzati lato server. Tuttavia, è possibile utilizzare le specifiche dei moduli in entrambi gli ambienti, ad esempio RequireJS offre istruzioni per l'esecuzione in Node.js e browserify è un'implementazione del modulo CommonJS che può essere eseguita nel browser.


20
Perché la homepage di CommonJS è così orribile ... Sto solo cercando di visualizzare le specifiche ufficiali. Ha errori di sintassi, documentazione incompleta e la pagina wiki non si risolve.
Taco,

7
Non è questo che significa caricare i moduli in modo asincrono. Potresti parlare di caricamento dinamico / lento. Con asincrono, suggerisci di caricare un file e dopo qualche tempo richiamerà quando avrà terminato il caricamento. Con la sincronizzazione, si suggerisce di caricare un file e quindi l'intero thread si blocca fino a quando il file non ha terminato il caricamento; nessun ulteriore codice viene eseguito fino al caricamento del file. Il primo può produrre prestazioni migliori a costo di imprevedibilità, mentre il secondo può produrre gli stessi risultati ogni volta ed è quindi più prevedibile. Nota che queste stranezze possono essere mitigate usando varie ottimizzazioni.
perry,

Grazie per la risposta. Ora che i moduli sono ufficiali in JS con ES2015, ciò significa che sono preferiti più di AMD o JS comuni?
Akhoy,

Non significa che siano preferiti. Dipende tutto dalle esigenze degli sviluppatori. Non penso che lasciare nessuna opzione e optare per i moduli ES6 sia una buona idea. Usando un buon UMD, tuttavia, puoi combattere quel problema. Il caricamento di bundle CommonJS sincronizzati con AMD è una buona (migliore) idea in generale (per migliorare le prestazioni). Se hai voglia di avere più controllo, ovviamente. E dovresti.
Maciej Sitko,

187

La risposta breve sarebbe:

CommonJS e AMD sono specifiche (o formati) su come i moduli e le loro dipendenze dovrebbero essere dichiarati nelle applicazioni javascript.

RequireJS è una libreria del caricatore di script che è conforme AMD, curljs è un altro esempio.

Conforme a CommonJS:

Tratto dal libro di 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;

Conformità 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
    }
});

Da qualche altra parte il modulo può essere utilizzato con:

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

Alcuni retroscena:

In realtà, CommonJS è molto più di una dichiarazione API e solo una parte di essa si occupa di questo. AMD ha iniziato come bozza di specifica per il formato del modulo nell'elenco CommonJS, ma non è stato raggiunto il pieno consenso e l'ulteriore sviluppo del formato è stato spostato nel gruppo amdjs . Gli argomenti su quale formato sia migliore affermano che CommonJS tenta di coprire una serie più ampia di preoccupazioni e che è più adatto allo sviluppo lato server data la sua natura sincrona e che AMD è più adatto allo sviluppo lato client (browser) data la sua natura asincrona e il fatto che ha le sue radici nell'implementazione della dichiarazione del modulo di Dojo.

fonti:


1
Vedere il codice anziché le descrizioni aiuta! :) in AMD compliantrealtà è RequireJS, giusto?
Asim KT,

Mi sto perdendo qualcosa o c'è qualcosa di sbagliato? Definisci "pacchetto / lib" ma poi richiedi "pacchetto / myModule".
RullDawg,

Mi piace sempre leggere un po 'della storia del perché qualcosa è come è! Grazie per averci fornito questo background!
Andru,

@RullDawg No, "pacchetto / lib" non è definito qui, è una dipendenza di terze parti utilizzata qui.
Robert Siemer,

28

citando

AMD :

  • Un approccio basato sul browser
  • Optare per un comportamento asincrono e una compatibilità retroattiva semplificata
  • Non ha alcun concetto di File I / O.
  • Supporta oggetti, funzioni, costruttori, stringhe, JSON e molti altri tipi di moduli.

CommonJS :

  • Un primo approccio al server
  • Supponendo un comportamento sincrono
  • Copre una serie più ampia di preoccupazioni come I / O, File system, Promesse e altro ancora.
  • Supporta moduli non confezionati , può sembrare un po 'più vicino alle specifiche ES.next/Harmony , liberandoti del wrapper define () che AMDapplica.
  • Supporta solo oggetti come moduli.

17

È abbastanza normale organizzare il programma JavaScript modulare in più file e chiamare child-modulesdalmain js module .

Il fatto è che JavaScript non lo fornisce. Nemmeno oggi nelle ultime versioni del browser di Chrome e FF.

Ma esiste una parola chiave in JavaScript per chiamare un altro modulo JavaScript?

Questa domanda può essere un crollo totale del mondo per molti, perché la risposta è No .


In ES5 (rilasciato nel 2009) JavaScript non conteneva parole chiave come importazione , inclusione o richiesta .

ES6 salva il giorno (rilasciato nel 2015) proponendo la parola chiave import ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), ma nessun browser lo implementa.

Se si utilizza Babel 6.18.0 e si traspila solo con l'opzione ES2015

import myDefault from "my-module";

otterrai di requirenuovo.

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

Questo perché requiresignifica che il modulo verrà caricato da Node.js. Node.js gestirà tutto, dalla lettura dei file a livello di sistema alle funzioni di wrapping nel modulo.

Perché nelle funzioni JavaScript sono gli unici wrapper a rappresentare i moduli.

Sono molto confuso su CommonJS e AMD?

Sia CommonJS che AMD sono solo due diverse tecniche su come superare il "difetto" JavaScript per caricare i moduli in modo intelligente.


3
Dovresti aggiornare la tua risposta perché ora supporta tutti i browser moderniimport
vsync,

@vsync, sì, sentiti libero di modificare la mia risposta, poiché non seguo questo segmento da un po 'di tempo.
prosti,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.