Relation between CommonJS, AMD and RequireJS?
Asked Answered
W

6

899

I'm still very confused about CommonJS, AMD and RequireJS, even after reading a lot.

I know that CommonJS (formerly ServerJS) is a group for defining some JavaScript specifications (i.e. modules) when the language is used outside the browser. CommonJS modules specification has some implementation like Node.js or RingoJS, right?

What's the relation between CommonJS, Asynchronous Module Definition (AMD) and RequireJS?

Is RequireJS an implementation of the CommonJS module definition? If yes, what's AMD then?

Wichern answered 13/5, 2013 at 11:56 Comment(2)
Reading requirejs.org/docs/whyamd.html would clarify a lot as it mentions all them. (posting it as a comment as I don't consider this a full answer).Adebayo
Can I ask or add more; How or where does the ES2015 import statements fit into all of these; e.g. import Ember from 'ember';Broadax
A
813

RequireJS implements the AMD API (source).

CommonJS is a way of defining modules with the help of an exports object, that defines the module contents. Simply put, a CommonJS implementation might work like this:

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

Basically, CommonJS specifies that you need to have a require() function to fetch dependencies, an exports variable to export module contents and a module identifier (which describes the location of the module in question in relation to this module) that is used to require the dependencies (source). CommonJS has various implementations, including Node.js, which you mentioned.

CommonJS was not particularly designed with browsers in mind, so it doesn't fit in the browser environment very well (*I really have no source for this--it just says so everywhere, including the RequireJS site.*) Apparently, this has something to do with asynchronous loading, etc.

On the other hand, RequireJS implements AMD, which is designed to suit the browser environment (source). Apparently, AMD started as a spinoff of the CommonJS Transport format and evolved into its own module definition API. Hence the similarities between the two. The new feature in AMD is the define() function that allows the module to declare its dependencies before being loaded. For example, the definition could be:

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

So, CommonJS and AMD are JavaScript module definition APIs that have different implementations, but both come from the same origins.

  • AMD is more suited for the browser, because it supports asynchronous loading of module dependencies.
  • RequireJS is an implementation of AMD, while at the same time trying to keep the spirit of CommonJS (mainly in the module identifiers).

To confuse you even more, RequireJS, while being an AMD implementation, offers a CommonJS wrapper so CommonJS modules can almost directly be imported for use with RequireJS.

define(function(require, exports, module) {
  var someModule = require('someModule'); // in the vein of node    
  exports.doSomethingElse = function() { return someModule.doSomething() + "bar"; };
});
Abscond answered 13/5, 2013 at 13:14 Comment(10)
Check out uRequire.org project that bridges the gaps of the 2 formats - write in either (or both), deploy to any of the two or simple <script>Daladier
So…, if requirejs can load commonjs modules, than it shouldn't be a problem to load node modules (since they're using commonjs's approach) right? If my first statement is true - is it possible to load requirejs modules to node module then?Gmur
@Gmur The CommmonJS files will lack the define(...) wrapper in the last example in this answer. A server-side JS preprocessor could add this wrapper (it would just be textual JS before and after the existing CommonJS definition.)Excretory
FYI Browserify will now let you use CommonJS in the browser.Protuberant
@Protuberant But, it is still has not that asynchronously nature as AMD.Cultivable
Writing modular js, Write up by addyosmani which also has a sub section discussing on whether CommonJS is suitable for browser or not.Sevigny
The reason why CommonJS doesn't fit in the browser as mentioned in RequireJS docs - "The CommonJS require() is a synchronous call, it is expected to return the module immediately. This does not work well in the browser". More info here.Shechem
@deeperx - Isn't that irrelevant since it's concatenating the files so the server only has to serve a single one?Tillage
@Tillage you might want to enable some features depending on the user request; so AMD's async nature may come handy.Cultivable
Can I ask or add more; How or where does the ES2015 import statements fit into all of these; e.g. import Ember from 'ember';Broadax
E
212

CommonJS is more than that - it's a project to define a common API and ecosystem for JavaScript. One part of CommonJS is the Module specification. Node.js and RingoJS are server-side JavaScript runtimes, and yes, both of them implement modules based on the CommonJS Module spec.

AMD (Asynchronous Module Definition) is another specification for modules. RequireJS is probably the most popular implementation of AMD. One major difference from CommonJS is that AMD specifies that modules are loaded asynchronously - that means modules are loaded in parallel, as opposed to blocking the execution by waiting for a load to finish.

AMD is generally more used in client-side (in-browser) JavaScript development due to this, and CommonJS Modules are generally used server-side. However, you can use either module spec in either environment - for example, RequireJS offers directions for running in Node.js and browserify is a CommonJS Module implementation that can run in the browser.

Essieessinger answered 13/5, 2013 at 13:6 Comment(5)
Why is the CommonJS homepage so horrible... I'm just trying to view the offical spec. It has syntax errors, incomplete documentation and the wiki page isn't resolving.Creole
That's not what it means to load modules asynchronously. You might be talking about dynamic/lazy loading. With async, you suggest a file to load and then some time later it will call back when it has finished loading. With sync, you suggest a file to load and then the whole thread blocks until that file has finished loading; no further code executes until the file loads. The former can yield better performance at the cost of unpredictability, while the latter can yield the same results every time and is thus more predictable. Do note these quirks can be mitigated using various optimizations.Headwards
Thanks for the answer. Now that modules are official in JS with ES2015, does this mean that they are preffered more than AMD or common JS?Wadesworth
It does not mean that they are preferred. It's all up to developer needs. I don't think that leaving no option and going for ES6 modules is especially good idea. Using good UMD however, you can combat that issue. Loading CommonJS bundles synced with AMD is a good (best) idea in general (for performance sake improvements). If you feel like you should have more control, obviously. And you should.Floss
This should be the accepted answer. Your wording is more precise and concise.Garbage
A
201

The short answer would be:

CommonJS and AMD are specifications (or formats) on how modules and their dependencies should be declared in javascript applications.

RequireJS is a script loader library that is AMD compliant, curljs being another example.

CommonJS compliant:

Taken from Addy Osmani's book.

// 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 compliant:

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

Somewhere else the module can be used with:

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

Some background:

Actually, CommonJS is much more than an API declaration and only a part of it deals with that. AMD started as a draft specification for the module format on the CommonJS list, but full consensus wasn't reached and further development of the format moved to the amdjs group. Arguments around which format is better state that CommonJS attempts to cover a broader set of concerns and that it's better suited for server side development given its synchronous nature, and that AMD is better suited for client side (browser) development given its asynchronous nature and the fact that it has its roots in Dojo's module declaration implementation.

Sources:

Adebayo answered 29/12, 2013 at 23:5 Comment(4)
Seeing code rather than descriptions helps! :) AMD compliant is actually RequireJS, right?Dysthymia
Am I missing something, or is there something mistyped? You define "package/lib" but then require "package/myModule".Elah
I always like to read a bit about the history of why something's the way it is! Thanks for providing that background!Paedogenesis
@Elah No, “package/lib” is not defined here, it is a 3rd party dependency used here.Jemima
W
30

Quoting

AMD:

  • One browser-first approach
  • Opting for asynchronous behavior and simplified backwards compatibility
  • It doesn't have any concept of File I/O.
  • It supports objects, functions, constructors, strings, JSON and many other types of modules.

CommonJS:

  • One server-first approach
  • Assuming synchronous behavior
  • Cover a broader set of concerns such as I/O, File system, Promises and more.
  • Supports unwrapped modules, it can feel a little more close to the ES.next/Harmony specifications, freeing you of the define() wrapper that AMD enforces.
  • Only support objects as modules.
Wellestablished answered 29/7, 2015 at 10:36 Comment(0)
C
19

It is quite normal to organize JavaScript program modular into several files and to call child-modules from the main js module.

The thing is JavaScript doesn't provide this. Not even today in latest browser versions of Chrome and FF.

But, is there any keyword in JavaScript to call another JavaScript module?

This question may be a total collapse of the world for many because the answer is No.


In ES5 ( released in 2009 ) JavaScript had no keywords like import, include, or require.

ES6 saves the day ( released in 2015 ) proposing the import keyword ( https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/import ), and now all modern browsers support this.

If you use Babel 6.18.0 and transpile with ES2015 option only

import myDefault from "my-module";

you will get require again.

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

This is because require means the module will be loaded from Node.js. Node.js will handle everything from system level file read to wrapping functions into the module.

Because in JavaScript functions are the only wrappers to represent the modules.

I'm a lot confused about CommonJS and AMD?

Both CommonJS and AMD are just two different techniques how to overcome the JavaScript "defect" to load modules smart.

Cleasta answered 30/10, 2016 at 23:50 Comment(0)
K
2

AMD

  • introduced in JavaScript to scale JavaScript project into multiple files
  • mostly used in browser based application and libraries
  • popular implementation is RequireJS, Dojo Toolkit

CommonJS:

  • it is specification to handle large number of functions, files and modules of big project
  • initial name ServerJS introduced in January, 2009 by Mozilla
  • renamed in August, 2009 to CommonJS to show the broader applicability of the APIs
  • initially implementation were server, nodejs, desktop based libraries

Example

upper.js file

exports.uppercase = str => str.toUpperCase()

main.js file

const uppercaseModule = require('uppercase.js')
uppercaseModule.uppercase('test')

Summary

  • AMD – one of the most ancient module systems, initially implemented by the library require.js.
  • CommonJS – the module system created for Node.js server.
  • UMD – one more module system, suggested as a universal one, compatible with AMD and CommonJS.

Resources:

Kedron answered 14/7, 2020 at 13:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.