Związek między CommonJS, AMD i RequireJS?

840

Nadal jestem bardzo zdezorientowany co do CommonJS, AMD i RequireJS , nawet po dużym przeczytaniu.

Wiem, że CommonJS (wcześniej ServerJS ) to grupa do definiowania niektórych specyfikacji JavaScript (tj. Modułów), gdy język jest używany poza przeglądarką. Specyfikacja modułów CommonJS ma pewne implementacje, takie jak Node.js lub RingoJS , prawda?

Jaki jest związek między CommonJS , definicją modułu asynchronicznego (AMD) i RequireJS ?

Czy RequireJS jest implementacją definicji modułu CommonJS ? Jeśli tak, to czym jest AMD ?

gremo
źródło
31
Czytanie wymaga.js.org/docs/whyamd.html wiele wyjaśnia, ponieważ wspomina o nich wszystkich. (opublikowanie go jako komentarza, ponieważ nie uważam tego za pełną odpowiedź).
mmutilva
5
Czy mogę zapytać lub dodać więcej; W jaki sposób i gdzie pasuje do wszystkich tych instrukcji importowych ES2015; np. import Ember z „ember”;
testndtv
Istnieje również systemjs, który ładuje dowolny z obsługiwanych formatów modułów JS, takich jak (CommonJS, UMD, AMD, ES6).
Andy,

Odpowiedzi:

770

RequireJS implementuje API AMD (źródło) .

CommonJS to sposób definiowania modułów za pomocą exportsobiektu, który definiuje zawartość modułu. Krótko mówiąc, implementacja CommonJS może działać w następujący sposób:

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

Zasadniczo CommonJS określa, że ​​potrzebujesz require()funkcji do pobierania zależności, exportszmiennej do eksportowania zawartości modułu i identyfikatora modułu (który opisuje lokalizację danego modułu w stosunku do tego modułu), który jest używany do żądania zależności ( źródło ). CommonJS ma różne implementacje, w tym Node.js , o których wspomniałeś.

CommonJS nie został specjalnie zaprojektowany z myślą o przeglądarkach, więc nie pasuje zbyt dobrze do środowiska przeglądarki ( naprawdę nie mam na to źródła - tak po prostu jest wszędzie, w tym strona RequireJS ) . Najwyraźniej ma to coś do zrobić z ładowaniem asynchronicznym itp.

Z drugiej strony RequireJS implementuje AMD, które jest zaprojektowane tak, aby pasowało do środowiska przeglądarki ( źródła ). Najwyraźniej AMD zaczęło jako wydzielenie formatu CommonJS Transport i przekształciło się we własny interfejs API definicji modułów. Stąd podobieństwa między nimi. Nowa funkcja AMD to define()funkcja, która pozwala modułowi zadeklarować swoje zależności przed załadowaniem. Na przykład definicja może wyglądać następująco:

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

Tak więc CommonJS i AMD to interfejsy API definicji modułów JavaScript , które mają różne implementacje, ale oba pochodzą z tego samego źródła.

  • AMD jest bardziej odpowiedni dla przeglądarki, ponieważ obsługuje asynchroniczne ładowanie zależności modułów.
  • RequireJS jest implementacją AMD , a jednocześnie stara się zachować ducha CommonJS (głównie w identyfikatorach modułów).

Aby jeszcze bardziej Cię zdezorientować, RequireJS, będąc implementacją AMD, oferuje opakowanie CommonJS, dzięki czemu moduły CommonJS można niemal zaimportować bezpośrednio do użycia z RequireJS.

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

Mam nadzieję, że to pomoże w wyjaśnieniu!

jakee
źródło
7
Sprawdź projekt uRequire.org, który wypełnia luki między dwoma formatami - pisz w jednym (lub w obu), wdróż w dowolnym z dwóch lub prostych <script>
Angelos Pikoulas
51
FYI Browserify pozwoli teraz korzystać z CommonJS w przeglądarce.
Eruant
9
@Eruant Ale wciąż nie ma tak asynchronicznej natury jak AMD.
Inanc Gumus
8
Powód, dla którego CommonJS nie pasuje do przeglądarki, jak wspomniano w dokumentach RequireJS - „CommonJS wymaga () to wywołanie synchroniczne, oczekuje się, że natychmiast zwróci moduł. To nie działa dobrze w przeglądarce” . Więcej informacji tutaj .
msenni
4
@ aaaaaa możesz chcieć włączyć niektóre funkcje w zależności od żądania użytkownika; więc asynchroniczna natura AMD może się przydać.
Inanc Gumus
199

CommonJS to coś więcej - to projekt definiujący wspólny interfejs API i ekosystem dla JavaScript. Jedną częścią CommonJS jest specyfikacja modułu . Node.js i RingoJS to środowiska wykonawcze JavaScript po stronie serwera i tak, oba implementują moduły w oparciu o specyfikację modułu CommonJS.

AMD (Definicja modułu asynchronicznego) to kolejna specyfikacja modułów. RequireJS jest prawdopodobnie najpopularniejszą implementacją AMD. Jedną z głównych różnic w stosunku do CommonJS jest to, że AMD określa, że ​​moduły ładowane są asynchronicznie - to znaczy moduły ładowane są równolegle, w przeciwieństwie do blokowania wykonywania przez oczekiwanie na zakończenie ładowania.

Z tego powodu AMD jest częściej używane w programowaniu JavaScript po stronie klienta (w przeglądarce), a moduły CommonJS są zwykle używane po stronie serwera. Można jednak użyć dowolnej specyfikacji modułu w dowolnym środowisku - na przykład RequireJS oferuje wskazówki dotyczące uruchamiania w Node.js, a browserrify to implementacja modułu CommonJS, którą można uruchomić w przeglądarce.

Nate
źródło
20
Dlaczego strona główna CommonJS jest taka okropna ... Próbuję tylko zobaczyć oficjalną specyfikację. Ma błędy składniowe, niekompletną dokumentację, a strona wiki nie rozwiązuje się.
taco
7
Nie to oznacza ładowanie modułów asynchronicznie. Być może mówisz o ładowaniu dynamicznym / leniwym. W przypadku asynchronizacji sugerujesz załadowanie pliku, a następnie jakiś czas później oddzwoni, gdy zakończy ładowanie. W przypadku synchronizacji sugerujesz załadowanie pliku, a następnie zablokowanie całego wątku, aż plik się zakończy; żaden kod nie jest wykonywany, dopóki plik nie zostanie załadowany. Ten pierwszy może przynieść lepszą wydajność kosztem nieprzewidywalności, podczas gdy drugi może dawać te same wyniki za każdym razem, a zatem jest bardziej przewidywalny. Pamiętaj, że te dziwactwa można złagodzić za pomocą różnych optymalizacji.
perry,
Dziękuję za odpowiedź. Teraz, gdy moduły są oficjalne w JS z ES2015, czy to oznacza, że ​​są one preferowane bardziej niż AMD czy wspólny JS?
Akhoy
Nie oznacza to, że są preferowane. Wszystko zależy od potrzeb programistów. Nie sądzę, aby pozostawienie opcji i wybranie modułów ES6 było szczególnie dobrym pomysłem. Korzystając z dobrej UMD, możesz jednak zwalczyć ten problem. Ładowanie pakietów CommonJS zsynchronizowanych z AMD jest ogólnie dobrym (najlepszym) pomysłem (dla poprawy wydajności). Jeśli czujesz, że powinieneś mieć większą kontrolę, oczywiście. I powinieneś.
Maciej Sitko
187

Krótka odpowiedź brzmiałaby:

CommonJS i AMD to specyfikacje (lub formaty) dotyczące sposobu deklarowania modułów i ich zależności w aplikacjach javascript.

RequireJS to biblioteka programu ładującego skrypty, która jest zgodna z AMD, a curljs jest kolejnym przykładem.

Zgodny z CommonJS:

Zaczerpnięte z książki 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;

Zgodny z 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
    }
});

Gdzie indziej moduł może być używany z:

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

Niektóre tło:

W rzeczywistości CommonJS to znacznie więcej niż deklaracja API i zajmuje się tym tylko jego część. AMD zaczęło jako projekt specyfikacji formatu modułu na liście CommonJS, ale pełny konsensus nie został osiągnięty, a dalszy rozwój formatu został przeniesiony do grupy amdjs . Argumenty, wokół których formatu jest lepszy, wskazują, że CommonJS próbuje uwzględnić szerszy zestaw problemów i że lepiej nadaje się do rozwoju po stronie serwera, biorąc pod uwagę jego synchroniczny charakter, oraz że AMD lepiej nadaje się do programowania po stronie klienta (przeglądarki), biorąc pod uwagę jego asynchroniczny charakter i fakt, że ma swoje korzenie w implementacji deklaracji modułu Dojo.

Źródła:

mmutilva
źródło
1
Widok kodu zamiast opisów pomaga! :) AMD compliantjest faktycznie RequireJS, prawda?
Asim KT
Czy coś mi brakuje, czy jest coś źle wpisanego? Definiujesz „pakiet / lib”, ale następnie potrzebujesz „pakiet / mój moduł”.
RullDawg
Zawsze lubię czytać trochę o historii, dlaczego tak jest! Dziękujemy za udostępnienie tego tła!
Andru
@RullDawg Nie „pakiet / lib” nie jest zdefiniowane tutaj, to jest zależność 3rd party stosowane tutaj.
Robert Siemer
28

Cytowanie

AMD :

  • Jedno podejście do przeglądarki
  • Wybór zachowania asynchronicznego i uproszczonej kompatybilności wstecznej
  • Nie ma żadnej koncepcji File I / O.
  • Obsługuje obiekty, funkcje, konstruktory, łańcuchy, JSON i wiele innych typów modułów.

CommonJS :

  • Jedno podejście do serwera
  • Zakładając zachowanie synchroniczne
  • Obejmują szerszy zestaw problemów, takich jak I / O, system plików, obietnice i wiele innych.
  • Obsługuje nieopakowane moduły, może czuć się trochę bliżej specyfikacji ES.next/Harmony , uwalniając cię od opakowującego definiowania (), które AMDwymusza.
  • Obsługuj tylko obiekty jako moduły.
zangw
źródło
17

Całkiem normalne jest organizowanie programu JavaScript w kilka plików i wywoływanie go child-modulesz main js module.

Chodzi o to, że JavaScript tego nie zapewnia. Nawet dzisiaj w najnowszych wersjach przeglądarek Chrome i FF.

Ale czy w JavaScript jest jakieś słowo kluczowe, które wywołuje inny moduł JavaScript?

To pytanie może być dla wielu totalnym upadkiem świata, ponieważ odpowiedź brzmi „ nie” .


W ES5 (wydany w 2009) JavaScript nie miał słów kluczowych, takich jak import , to albo wymagają .

ES6 oszczędza dzień (wydany w 2015 r.) Proponując słowo kluczowe importu ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), ale żadna przeglądarka tego nie implementuje.

Jeśli używasz Babel 6.18.0 i transpiluj tylko z opcją ES2015

import myDefault from "my-module";

dostaniesz requireponownie.

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

Wynika to z faktu require, że moduł zostanie załadowany z Node.js. Node.js obsłuży wszystko - od odczytu pliku na poziomie systemu po zawijanie funkcji do modułu.

Ponieważ w JavaScript funkcje są jedynymi opakowaniami reprezentującymi moduły.

Jestem bardzo zdezorientowany co do CommonJS i AMD?

Zarówno CommonJS, jak i AMD to tylko dwie różne techniki przezwyciężenia „defektu” JavaScript w celu inteligentnego załadowania modułów.

prosti
źródło
3
Powinieneś zaktualizować swoją odpowiedź, ponieważ teraz obsługuje wszystkie nowoczesne przeglądarkiimport
vsync
@vsync, tak, nie wahaj się edytować mojej odpowiedzi, ponieważ od jakiegoś czasu nie śledzę tego segmentu.
prosti