1

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..

2
  • If your business logic is modular, and you have a lot of dependencies between modules I would suggest you to use CommonJs architecture. It is the architecture which NodeJs uses. Are you familiar with NodeJs? Commented Oct 25, 2016 at 13:40
  • Yea I am familiar with NodeJs and CommonJS approach. It uses export and require.. but I would need to use RequireJS or similar.. I would prefer some custom solution Commented Oct 25, 2016 at 14:42

3 Answers 3

2

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...).

Sign up to request clarification or add additional context in comments.

12 Comments

The namespace can also be a function itself like in the OP's design, it doesn't matter. This doesn't answer the question.
@plalx Probably the OP shouldn't be using functions like namespaces. The proposal is that OP should leverage module pattern. This is my answer to OP's question/concern. I'm not that sure that my answer doesn't addresses the question. It would be too limited if I would be answering questions just how the OP expects the solution... Then, why asking questions in StackOverflow? :D
I don't want to use SystemJS, Browsify or any other tool currently even if I know it can be done easily in that way. Current goal is to learn something too and include my brain instead to rely immediately on ton of tools. And I love to use grunt for automation. I should probably create new dependency objects with each Micro creation and things should work..
@sgora si I've already provided you a vanilla solution.. System JS is just a suggestion
I said that this doesn't answer OP's question because you did not explain why he couldn't have multiple Micro instances and that was the main concern. The approach you proposed is identical or very close to what the OP was already doing and it doesn't solve that problem. It all depends on how the Micro constructor is implemented internally.
|
1

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.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.