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?


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!


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.


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:


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.

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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.