Modules/Metadata/Purpose

From CommonJS Spec Wiki
Jump to: navigation, search

Goals

Performance

The Modules/Metadata proposal was developed with client-side performance in mind.

Extensibility

It is easy to extend the metadata format to add new features, such as ways of handling css, images, or other forms of external dependencies, furthermore the metadata can also be used by developers for all sorts of other purposes.

Problems Solved

Synchronicity

The require statement of Modules/1.0 is too tied to blocking IO and the server side. One of the principles of this proposal is that IO should be asynchronous and non-blocking on the server-side as well as the client-side.

// Block the UI and all processing until we load the add module
// Also if the add module happens to be online at the time, then everything might hang.
var add = require('math').add;

Solution: This proposal solves this problem by using a source filter to build a function wrapper that is friendly to asynchronous loaders, or by wrapping a module in one of the Module/Transport schemes.

Dependency Resolution

Modules/1.1.1 specifies that you should handle your dependencies by placing require statements around your module, perhaps this works on the server-side, however, on the client-side you need to get the dependencies pre-runtime, so in order to get the dependencies it is recommended that you use regular expressions such as this one:

// from: http://github.com/jbrantly/yabble/blob/master/yabbler.js
var requireRegex = /(?:^|[^\w\$_.])require\s*\(\s*("[^"\\]*(?:\\.[^"\\]*)*"|'[^'\\]*(?:\\.[^'\\]*)*')\s*\)/g;

The dependencies are not that accessible if you have to use regular expressions to get them, and some specifications state that you have to use string literals in your require statements to aid such static analysis tools, this is confusing to JavaScript users who expect functions to behave as functions.

// Error: only use a string literal in your require statements:
require( moduleName );
require( isPositive ? "Utils.inc" : "Utils.dec" );
(require ? require : function() {})("Utils.inc");
 
eval( "require('Utils.inc')" );
 
var alternativeName = require;
alternativeName("Utils.inc");

Solution: This proposal solves this problem by storing all metadata as JSON a format which is widely accepted and its parser is built right into JavaScript, that way if you want you can get the metadata without any regular expressions or string handling functions.

Keyword Dependency

Some users may be discouraged by the Modules/1.1.1 dependency on introduced keywords such as exports, require, and module. This proposal gives you all the features of the Modules specification without depending on any keywords.

META({
 
    "returns": "exports",
 
    "use": {
        // Specify that you want to use an old version of require()
        // that is to use the 1.0 version.
        "require": "js-require-1.0-commonjs"
    }
 
});

Solution: this proposal solves this by assuming that you don't want any keywords unless you specify that you want them in your META header, however, if you completely omit your META header from your file then some implementations may assume that you are using a commonjs module.