Relação entre CommonJS, AMD e RequireJS?

840

Ainda estou muito confuso sobre CommonJS, AMD e RequireJS , mesmo depois de ler muito.

Eu sei que o CommonJS (anteriormente ServerJS ) é um grupo para definir algumas especificações de JavaScript (ou seja, módulos) quando o idioma é usado fora do navegador. A especificação dos módulos CommonJS tem alguma implementação como Node.js ou RingoJS , certo?

Qual é a relação entre CommonJS , AMD ( Asynchronous Module Definition ) e RequireJS ?

O RequireJS é uma implementação da definição do módulo CommonJS ? Se sim, o que é AMD então?

gremo
fonte
31
A leitura de requirejs.org/docs/whyamd.html esclareceria muito, pois menciona todos eles. (publicá-lo como um comentário, pois não considero isso uma resposta completa).
mmutilva
5
Posso pedir ou adicionar mais; Como ou onde as instruções de importação do ES2015 se encaixam em todas elas; por exemplo, importar brasa de 'brasa';
testndtv 28/02
Há também um systemjs que carrega qualquer um dos formatos de módulo JS suportados, como (CommonJS, UMD, AMD, ES6).
21417 Andy

Respostas:

770

O RequireJS implementa a API da AMD (origem) .

CommonJS é uma maneira de definir módulos com a ajuda de um exportsobjeto, que define o conteúdo do módulo. Simplificando, uma implementação do CommonJS pode funcionar assim:

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

Basicamente, o CommonJS especifica que você precisa ter uma require()função para buscar dependências, uma exportsvariável para exportar o conteúdo do módulo e um identificador de módulo (que descreve o local do módulo em questão em relação a este módulo) que é usado para exigir as dependências ( origem ) O CommonJS possui várias implementações, incluindo o Node.js , que você mencionou.

O CommonJS não foi especialmente projetado com os navegadores em mente, por isso não se encaixa muito bem no ambiente do navegador ( eu realmente não tenho uma fonte para isso - apenas diz isso em todos os lugares, incluindo o site RequireJS. ) Aparentemente, isso tem algo a fazer com carregamento assíncrono, etc.

Por outro lado, o RequireJS implementa a AMD, projetada para se adequar ao ambiente do navegador ( fonte ). Aparentemente, a AMD começou como um spinoff do formato CommonJS Transport e evoluiu para sua própria API de definição de módulo. Daí as semelhanças entre os dois. O novo recurso da AMD é a define()função que permite ao módulo declarar suas dependências antes de ser carregado. Por exemplo, a definição pode ser:

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

Portanto, CommonJS e AMD são APIs de definição de módulo JavaScript que possuem implementações diferentes, mas ambas vêm da mesma origem.

  • A AMD é mais adequada para o navegador, pois suporta o carregamento assíncrono das dependências do módulo.
  • O RequireJS é uma implementação da AMD , ao mesmo tempo em que tenta manter o espírito do CommonJS (principalmente nos identificadores do módulo).

Para confundir ainda mais, o RequireJS, embora seja uma implementação da AMD, oferece um wrapper CommonJS para que os módulos CommonJS possam ser quase diretamente importados para uso com o RequireJS.

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

Espero que isso ajude a esclarecer as coisas!

jakee
fonte
7
Confira o projeto uRequire.org que preenche as lacunas dos 2 formatos - escreva em (ou ambos), implemente em qualquer um dos dois ou simples <script> #
Angelos Pikoulas #
51
FYI Browserify agora permitirá que você use commonjs no navegador.
Eruant
9
@ Eruant Mas, ainda não tem essa natureza assíncrona como a AMD.
Inanc Gumus
8
O motivo pelo qual o CommonJS não cabe no navegador, conforme mencionado nos documentos do RequireJS - "O CommonJS require () é uma chamada síncrona; espera-se que o módulo retorne imediatamente. Isso não funciona bem no navegador" . Mais informações aqui .
msenni
4
@aaaaaa, convém ativar alguns recursos, dependendo da solicitação do usuário; então a natureza assíncrona da AMD pode ser útil.
Inanc Gumus
199

O CommonJS é mais do que isso - é um projeto para definir uma API e um ecossistema comuns para JavaScript. Uma parte do CommonJS é a especificação do módulo . Node.js e RingoJS são tempos de execução JavaScript do lado do servidor e, sim, ambos implementam módulos com base na especificação do módulo CommonJS.

AMD (Asynchronous Module Definition) é outra especificação para módulos. RequireJS é provavelmente a implementação mais popular da AMD. Uma grande diferença do CommonJS é que a AMD especifica que os módulos são carregados de forma assíncrona - isso significa que os módulos são carregados em paralelo, em vez de bloquear a execução, aguardando a conclusão da carga.

A AMD geralmente é mais usada no desenvolvimento de JavaScript no lado do cliente (no navegador) devido a isso, e os Módulos CommonJS geralmente são usados ​​no lado do servidor. No entanto, você pode usar as especificações de um módulo em qualquer ambiente - por exemplo, o RequireJS oferece instruções para execução no Node.js e o browserify é uma implementação do Módulo CommonJS que pode ser executada no navegador.

Nate
fonte
20
Por que a página inicial do CommonJS é tão horrível? Estou apenas tentando visualizar as especificações oficiais. Possui erros de sintaxe, documentação incompleta e a página wiki não está sendo resolvida.
taco
7
Não é isso que significa carregar módulos de forma assíncrona. Você pode estar falando sobre carregamento dinâmico / lento. Com o assíncrono, você sugere que um arquivo seja carregado e, algum tempo depois, ele retornará quando terminar o carregamento. Com a sincronização, você sugere um arquivo para carregar e, em seguida, todo o thread é bloqueado até que o arquivo termine de carregar; nenhum código adicional é executado até que o arquivo seja carregado. O primeiro pode produzir melhor desempenho à custa da imprevisibilidade, enquanto o segundo pode produzir os mesmos resultados sempre e, portanto, é mais previsível. Observe que essas peculiaridades podem ser mitigadas usando várias otimizações.
perry
Obrigado pela resposta. Agora que os módulos são oficiais em JS com ES2015, isso significa que eles são preferidos mais do que AMD ou JS comum?
Akhoy
Isso não significa que eles são os preferidos. Tudo depende das necessidades do desenvolvedor. Eu não acho que deixar nenhuma opção e optar pelos módulos ES6 seja uma boa idéia. No entanto, usando um bom UMD, você pode combater esse problema. Carregar bundles CommonJS sincronizados com a AMD é uma boa (melhor) ideia em geral (para melhorias de desempenho). Se você sente que deveria ter mais controle, obviamente. E você deveria.
Maciej Sitko
187

A resposta curta seria:

CommonJS e AMD são especificações (ou formatos) de como os módulos e suas dependências devem ser declarados em aplicativos javascript.

O RequireJS é uma biblioteca do carregador de scripts compatível com AMD,sendo o curljs outro exemplo.

Compatível com CommonJS:

Retirado do livro de 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;

Compatível com 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
    }
});

Em outro lugar, o módulo pode ser usado com:

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

Alguns antecedentes:

Na verdade, o CommonJS é muito mais do que uma declaração de API e apenas parte dela lida com isso. A AMD começou como uma especificação preliminar para o formato do módulo na lista CommonJS, mas não foi alcançado um consenso completo e o desenvolvimento do formato foi movido para o grupo amdjs . Os argumentos em torno de qual formato é melhor afirmam que o CommonJS tenta cobrir um conjunto mais amplo de preocupações e que é mais adequado ao desenvolvimento do lado do servidor, devido à sua natureza síncrona, e que a AMD é mais adequada ao desenvolvimento do lado do cliente (navegador), devido à sua natureza assíncrona e ao fato de ter suas raízes na implementação da declaração do módulo do Dojo.

Fontes:

mmutilva
fonte
1
Ver código em vez de descrições ajuda! :) AMD complianté realmente RequireJS, certo?
Asim KT
Estou faltando alguma coisa ou há algo errado? Você define "package / lib", mas requer "package / myModule".
RullDawg
Eu sempre gosto de ler um pouco sobre a história de por que as coisas são do jeito que são! Obrigado por fornecer esse histórico!
Andru
@RullDawg Não, “package / lib” não está definido aqui, é uma dependência de terceiros usada aqui.
Robert Siemer
28

Citação

AMD :

  • Uma abordagem baseada no navegador
  • Optando por comportamento assíncrono e compatibilidade retroativa simplificada
  • Não possui nenhum conceito de E / S de arquivo.
  • Ele suporta objetos, funções, construtores, strings, JSON e muitos outros tipos de módulos.

CommonJS :

  • Uma abordagem de primeiro servidor
  • Assumindo comportamento síncrono
  • Abranja um conjunto mais amplo de preocupações como E / S, sistema de arquivos, promessas e muito mais.
  • Suporta módulos desembrulhados, pode parecer um pouco mais próximo das especificações ES.next/Harmony , liberando você do wrapper define () que AMDimpõe.
  • Suporte apenas objetos como módulos.
zangw
fonte
17

É bastante normal organizar o programa JavaScript modular em vários arquivos e chamar child-modules partir do main js module.

O problema é que o JavaScript não fornece isso. Até hoje, nas versões mais recentes do navegador Chrome e FF.

Mas, existe alguma palavra-chave no JavaScript para chamar outro módulo JavaScript?

Esta questão pode ser um colapso total do mundo para muitos, porque a resposta é Não .


No ES5 (lançado em 2009), o JavaScript não tinha palavras-chave como importar , incluir ou exigir .

O ES6 salva o dia (lançado em 2015) propondo a palavra-chave import ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), mas nenhum navegador implementa isso.

Se você usar o Babel 6.18.0 e transpilar apenas com a opção ES2015

import myDefault from "my-module";

você receberá requirenovamente.

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

Isso ocorre porque requiresignifica que o módulo será carregado a partir do Node.js. O Node.js manipulará tudo, desde a leitura de arquivos no nível do sistema até as funções de agrupamento no módulo.

Como no JavaScript, as funções são os únicos invólucros a representar os módulos.

Estou muito confuso sobre CommonJS e AMD?

Tanto o CommonJS quanto a AMD são apenas duas técnicas diferentes de como superar o "defeito" do JavaScript para carregar módulos inteligentes.

prosti
fonte
3
Deve atualizar sua resposta, porque agora todos os navegadores modernos são compatíveis import
vsync
@vsync, sim, sinta-se à vontade para editar minha resposta, pois não acompanho esse segmento há algum tempo.
Prosti