GithubHelp home page GithubHelp logo

mods's Introduction

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 ([email protected])

mods's People

Contributors

inikulin avatar bitdeli-chef avatar

Stargazers

Rômulo Mendes Soares Junior avatar Hector Romo avatar Chris Hart avatar Stanley Shyiko avatar foo9 avatar Boris Kirov avatar Ryun Shofner avatar Joohun, Maeng avatar Corban Cloud avatar Jiří Prokop avatar Luis Albarenga avatar Nikolay Kolev avatar Peter Willert avatar Vlad avatar Yuya Saito avatar Jonathan Barnett avatar odedbd avatar XΛVI avatar Sindre Gulseth avatar Weston Watson avatar Sascha avatar trkw avatar  avatar Ivan Shvedunov avatar Joe Minichino avatar Jyrki Laurila avatar Gonçalo Morais avatar Ross Cousens avatar Cody Lindley avatar Dowon Kang avatar Brandon Smith avatar  avatar Gary Taylor avatar

Watchers

 avatar James Cloos avatar  avatar

Forkers

kokujin amit08255

mods's Issues

Encapsulating vendor libs

Hi there!

Mods is nice, I like the small codebase. I have an issue though, looking at this example

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

Where does the "jQuery.noConflict();" come from from? If it was loaded normally using a script tag, that would mean that JQuery is already in the global scope and Mods would not need to wrap it. Or did you mean placing the comple jQuery code in the "define" ? Thanks

Gruntfile task question for example app

The "concat" taks for the example states this:

    concat: {
            dist: {
                src: [
                    '../mods.min.js',
                    'src/intro.js',
                    'src/**/*.js'
                ],
                dest: 'app/app.js'
            }
        },

Would 'src/intro.js' not be added twice to the result of the concat(app.js) ?

Why not just use AMD define

  define('main', function(require, exports) {
  });

is entirely supported by AMD, and concatenates for builds.

If you really wanted to push this technique, could you not push it with the existing toolset?

What isn't supported by RequireJS or Almond with the above that necessitates writing a new tool?

Wrapping existing AMD modules

Hi there @inikulin ! Thanks for the reply. I had to work on a few other things. I am still not clear how mods wraps existing AMD modules.
For example, using require.js:

requirejs(['jquery', 'AMD_mod1', 'AMD_mod2'], function   ($, mod1, mod2) {
      ...
    };
});

The AMD modues AMD_mod1 and AMD_mod2 modules have signatures like the following:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {       
        define(['AMD_mod1'], factory);
    } else {     
        root.amdWeb = factory(root.AMD_mod1);
    }
}(this, function (mod1) {  
    return {};
}));

Do I have to modify the source of these modules and wrap all of them before requesting them using mods? I hope not because I intend to use several modules in the bower registry that have these signatures. Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.