Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

52 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

modsmods

Nice modular Javascript library in just 470 bytes of minified code.

or

  • Install with bower: $ bower install mods

What?

Nowadays building any non-trivial JavaScript application requires a significant amount of code. Historically JavaScript doesn't have any modular system, which allows you to split your code in modules, separate files and control their dependencies. Moreover a big application doesn't need to initialize all its subsystems on start. Here a lazy loading of submodules comes to help. There are a lot of great libraries that provide such functionality (RequireJS is the most notable). However, I feel a constant frustration with their complexity and strange design decisions. I feel that things are not DRY and my code is not narrative when I'm writing things like this in RequireJS:

requirejs(['jquery', 'canvas', 'app/sub'], function   ($, canvas, sub) {
    //jQuery, canvas and the app/sub module are loaded and can be used here now.
    
    return {
        helloWorld: function() {
          console.log('Hi there!');
        }
    };
});

This design is dictated by the fact, that RequireJS should load dependencies from server before module initialization. But in most cases I have the only one good-old concatinated script file.

So, this is how I want it to be done in my code:

MyApp.define('Main', function(require, exports) {
    var $ = require('jquery'),
        canvas = require('canvas'),
        sub = require('sub');
        
    exports.helloWorld = function(){
      console.log('Hi there');
    };
});

Another issue of RequireJs/CommonJs is that a module structure mimics a filesystem structure. So rebasing a single file may become a significant pain in the ass. The most common process of building your scripts (e.g. with grunt) is:

  • Concat all JS files in the given directory into a single file, which is used at run time
  • Minify this file

With such approach, usage of the RequireJS may become really painful.

So, if you want

  • nice, modular and narrative code
  • filesystem/URL-agnostic AMD library with nice error handling
  • concat all your scripts (without taking care of their order/filesystem path) into a single file

then mods is your choice.

Usage

1. Init your app/module container

var MyApp = new Mods();

2. Encapsulate used libs

MyApp.define('jQuery', function() {
    this.exports = jQuery.noConflict();
});

MyApp.define('async', function() {
    this.exports = async.noConflict();
});

3. Define your modules

//Use objects as exports...
//---------------------------------------------------------
MyApp.define('Greetings.Settings', function() {
    this.exports = {
      text: 'Hello world',
      color: 'red'
    };
});


//...or use functions as exports...
//----------------------------------------------------------
MyApp.define('Greetings.Printer.DOM', function(require) {
    var $ = require('jQuery');
    
    this.exports = function(text, color) {
        $('<div>')
            .text(text)
            .css({color: color})
            .appendTo('body');
    };
});


MyApp.define('Greetings.Printer.Console', function(require) {
    this.exports = function(text) {
        console.log(text);
    };
});


//...or just extend exports object (like in node.js)
//----------------------------------------------------------
MyApp.define('Main', function(require, exports) {
    var Settings = require('Greetings.Settings'),
        printToDOM = require('Greetings.Printer.DOM'),
        printToConsole = require('Greetings.Printer.Console');

    exports.helloToDOM = function(){
        printToDOM(Settings.text, Settings.color);
    };

    exports.helloToConsole = function(){
        printToConsole(Settings.text);
    };
});

4. Use your app/module container

var Main = MyApp.get('Main');

Main.helloToDOM();
Main.helloToConsole();

Hm, but I want backward compatibility with RequireJS/CommonJS!

Ok. In your startup code do this

var MyApp = new Mods();

window.define = function(name, mod) {
    MyApp.define(name, mod);
};

so you can turn this

MyApp.define('i.am.rock', function(require, exports) {
   var app = require('app');
   
   exports.awesomeness = 'My ' + app.name;
});

into this

define('i.am.rock', function(require, exports) {
   var app = require('app');
   
   exports.awesomeness = 'My ' + app.name;
});

I need an example project

We have one. As you can see it mimics superb app from Usage section.

By the way, it can handle issues in your code

###If you have a circular dependency in your code:

var MyApp = new Mods();

MyApp.define('Module1', function(require){
  var Module2 = require('Module2');
});

MyApp.define('Module2', function(){
  var Module1 = require('Module1');
});

var Module1 = MyApp.get('Module1');

You will get an error from mods in your console: Mods: circular dependency: "Module1" -> "Module2" -> "Module1"

###If you load a module that is not defined:

var MyApp = new Mods();

MyApp.define('Main', function(require){
   var dummy = require('MyUndefinedModule');
});

//or

var dummy = MyApp.get('MyUndefinedModule'); 

You will get an error from mods in your console: Mods: required "MyUndefinedModule" is undefined

###If you redefine already defined module:

var MyApp = new Mods();

MyApp.define('Main', function(){
});

MyApp.define('Main', function(){
});

You will get an error from mods in your console: Mods: "Main" is already defined

Questions or suggestions?

If you have any questions, please feel free to create an issue here on github.

Author

Ivan Nikulin (ifaaan@gmail.com)

About

Modular JavaScript library in just 470 bytes of minified code

Resources

Stars

33 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages