sgoran
sgoran

Reputation: 976

Building Javascript Modules

I have small library for client side routing and template loading. It's built from several smaller module, for example Tpl, Router..

Every module check if library namespace is defined and than apply itself to it.

Here is the code: https://github.com/sgoran/micro

For example Tpl component binds itself to Micro library (the main lib)

if(typeof Micro === "function" && Micro.prototype.isMicro){
      Micro['Tpl'] = Tpl;

And than I am calling library with constructor

var micro = new Micro(properties);

Problem is if I want to make another instance...dependencies will collide internally

var micro2 = new Micro(properties);

For build, I use gulp and just concatenate modules to one file..

Can anyone propose a good way for building multiple modules to one, like sandboxing them? Or some best practices and patterns without using webpack, requireJs etc..

Upvotes: 1

Views: 171

Answers (3)

sgoran
sgoran

Reputation: 976

A a nice approach for fragmenting application without using any additional code (via CommonJS or AMD tools) would be just to check at the end of each submodule, does a main module exists..

If it does not exist, we can expose module globally and use it individually, test it or similar.

;(function (window, document){

    function Tpl(props){

    }

    Tpl.prototye = {
      // some methods
    }


    if(typeof Micro === "function" && Micro.prototype.isMicro){
      Micro['Tpl'] = Tpl;
    }
    else if ( typeof module != 'undefined' && module.exports ){
        module.exports = Tpl;
    }else if( typeof define == 'function' && define.amd ){
        define( function () { return Tpl; }); 
    }
    else{
        window.Tpl = Tpl;
    }



}(window, document));

**Declaring inside main module **

me.tpl = new Micro.Tpl(props);

Upvotes: 0

Matías Fidemraizer
Matías Fidemraizer

Reputation: 64923

Use module pattern as is.

// Module1.js
var Module1 = (function(exports) {
   exports.Micro = function() {};
   exports.Micro.prototype = {
       // Properties...
   };
})(Module1 || {});

// Module2.js
var Module2 (function(exports, Module1) {
    var micro = new Module1.Micro();
})(exports, Module1); 

// Module3.js
var Module3 (function(exports, Module1) {
    // No collission here because Module3 creates an isolated scope
    // like Module2 already does too!
    var micro = new Module1.Micro();
})(exports, Module1); 

If you don't want to pollute the global scope...

...you can implement submodules. You won't be able to fully avoid global scope pollution, but you'll limit it to declare the top-level module:

// Module1.js
var Module1 = (function(Module1) {
    exports.Micro = function() {};
    exports.Micro.prototype = {
         // Properties...
    };
})(Module1 || {});

// Module2.js
(function(Module1) {
    Module1.Module2 = Module1.Module2 || {};

    exports.Other = function() {

    };

    exports.a = 11;
})(Module1 || {});

BTW move forward and go with a solution like SystemJS to configure your modules and avoid the dependency hell (otherwise, you'll need to add your script files manually and in a specific order to let your dependent modules be usable...).

Upvotes: 2

plalx
plalx

Reputation: 43718

You only have to get rid of all shared state within the Micro constructor itself. For instance, with me.events = Micro.Pubsub; all instances will share the same Pubsub instance which is problematic, but you can solve that by instantiating a new Pubsub for every Micro instance. There is probably more shared state (e.g. document.querySelectorAll('[hub-link]')), but I haven't dug far.

Once you get rid of shared state within the Micro constructor, what would still be problematic though is to have multiple Micro instances using different sub-modules (e.g. Tpl, Routes). That is because you did not use any form of dependency inversion to resolve these sub-modules from within the Micro constructor.

That's probably not a problem though because I doubt a single application would ever use different sub-module implementations concurrently. Still, you may want to make dependencies explicit and allow to inject the sub-modules dependencies into the Micro constructor.

Upvotes: 1

Related Questions